Passed
Push — master ( 62403d...0c3e2f )
by Joas
14:50 queued 14s
created
lib/private/Template/CSSResourceLocator.php 1 patch
Indentation   +113 added lines, -113 removed lines patch added patch discarded remove patch
@@ -35,117 +35,117 @@
 block discarded – undo
35 35
 
36 36
 class CSSResourceLocator extends ResourceLocator {
37 37
 
38
-	/** @var SCSSCacher */
39
-	protected $scssCacher;
40
-
41
-	/**
42
-	 * @param ILogger $logger
43
-	 * @param string $theme
44
-	 * @param array $core_map
45
-	 * @param array $party_map
46
-	 * @param SCSSCacher $scssCacher
47
-	 */
48
-	public function __construct(ILogger $logger, $theme, $core_map, $party_map, $scssCacher) {
49
-		$this->scssCacher = $scssCacher;
50
-
51
-		parent::__construct($logger, $theme, $core_map, $party_map);
52
-	}
53
-
54
-	/**
55
-	 * @param string $style
56
-	 */
57
-	public function doFind($style) {
58
-		$app = substr($style, 0, strpos($style, '/'));
59
-		if (strpos($style, '3rdparty') === 0
60
-			&& $this->appendIfExist($this->thirdpartyroot, $style.'.css')
61
-			|| $this->cacheAndAppendScssIfExist($this->serverroot, $style.'.scss', $app)
62
-			|| $this->cacheAndAppendScssIfExist($this->serverroot, 'core/'.$style.'.scss')
63
-			|| $this->appendIfExist($this->serverroot, $style.'.css')
64
-			|| $this->appendIfExist($this->serverroot, 'core/'.$style.'.css')
65
-		) {
66
-			return;
67
-		}
68
-		$style = substr($style, strpos($style, '/')+1);
69
-		$app_path = \OC_App::getAppPath($app);
70
-		$app_url = \OC_App::getAppWebPath($app);
71
-
72
-		if ($app_path === false && $app_url === false) {
73
-			$this->logger->error('Could not find resource {resource} to load', [
74
-				'resource' => $app . '/' . $style . '.css',
75
-				'app' => 'cssresourceloader',
76
-			]);
77
-			return;
78
-		}
79
-
80
-		// Account for the possibility of having symlinks in app path. Doing
81
-		// this here instead of above as an empty argument to realpath gets
82
-		// turned into cwd.
83
-		$app_path = realpath($app_path);
84
-
85
-		if(!$this->cacheAndAppendScssIfExist($app_path, $style.'.scss', $app)) {
86
-			$this->append($app_path, $style.'.css', $app_url);
87
-		}
88
-	}
89
-
90
-	/**
91
-	 * @param string $style
92
-	 */
93
-	public function doFindTheme($style) {
94
-		$theme_dir = 'themes/'.$this->theme.'/';
95
-		$this->appendIfExist($this->serverroot, $theme_dir.'apps/'.$style.'.css')
96
-			|| $this->appendIfExist($this->serverroot, $theme_dir.$style.'.css')
97
-			|| $this->appendIfExist($this->serverroot, $theme_dir.'core/'.$style.'.css');
98
-	}
99
-
100
-	/**
101
-	 * cache and append the scss $file if exist at $root
102
-	 *
103
-	 * @param string $root path to check
104
-	 * @param string $file the filename
105
-	 * @return bool True if the resource was found and cached, false otherwise
106
-	 */
107
-	protected function cacheAndAppendScssIfExist($root, $file, $app = 'core') {
108
-		if (is_file($root.'/'.$file)) {
109
-			if($this->scssCacher !== null) {
110
-				if($this->scssCacher->process($root, $file, $app)) {
111
-
112
-					$this->append($root, $this->scssCacher->getCachedSCSS($app, $file), \OC::$WEBROOT, true, true);
113
-					return true;
114
-				} else {
115
-					$this->logger->warning('Failed to compile and/or save '.$root.'/'.$file, ['app' => 'core']);
116
-					return false;
117
-				}
118
-			} else {
119
-				return true;
120
-			}
121
-		}
122
-		return false;
123
-	}
124
-
125
-	public function append($root, $file, $webRoot = null, $throw = true, $scss = false) {
126
-		if (!$scss) {
127
-			parent::append($root, $file, $webRoot, $throw);
128
-		} else {
129
-			if (!$webRoot) {
130
-				$webRoot = $this->findWebRoot($root);
131
-
132
-				if ($webRoot === null) {
133
-					$webRoot = '';
134
-					$this->logger->error('ResourceLocator can not find a web root (root: {root}, file: {file}, webRoot: {webRoot}, throw: {throw})', [
135
-						'app' => 'lib',
136
-						'root' => $root,
137
-						'file' => $file,
138
-						'webRoot' => $webRoot,
139
-						'throw' => $throw ? 'true' : 'false'
140
-					]);
141
-
142
-					if ($throw && $root === '/') {
143
-						throw new ResourceNotFoundException($file, $webRoot);
144
-					}
145
-				}
146
-			}
147
-
148
-			$this->resources[] = [$webRoot? : \OC::$WEBROOT, $webRoot, $file];
149
-		}
150
-	}
38
+    /** @var SCSSCacher */
39
+    protected $scssCacher;
40
+
41
+    /**
42
+     * @param ILogger $logger
43
+     * @param string $theme
44
+     * @param array $core_map
45
+     * @param array $party_map
46
+     * @param SCSSCacher $scssCacher
47
+     */
48
+    public function __construct(ILogger $logger, $theme, $core_map, $party_map, $scssCacher) {
49
+        $this->scssCacher = $scssCacher;
50
+
51
+        parent::__construct($logger, $theme, $core_map, $party_map);
52
+    }
53
+
54
+    /**
55
+     * @param string $style
56
+     */
57
+    public function doFind($style) {
58
+        $app = substr($style, 0, strpos($style, '/'));
59
+        if (strpos($style, '3rdparty') === 0
60
+            && $this->appendIfExist($this->thirdpartyroot, $style.'.css')
61
+            || $this->cacheAndAppendScssIfExist($this->serverroot, $style.'.scss', $app)
62
+            || $this->cacheAndAppendScssIfExist($this->serverroot, 'core/'.$style.'.scss')
63
+            || $this->appendIfExist($this->serverroot, $style.'.css')
64
+            || $this->appendIfExist($this->serverroot, 'core/'.$style.'.css')
65
+        ) {
66
+            return;
67
+        }
68
+        $style = substr($style, strpos($style, '/')+1);
69
+        $app_path = \OC_App::getAppPath($app);
70
+        $app_url = \OC_App::getAppWebPath($app);
71
+
72
+        if ($app_path === false && $app_url === false) {
73
+            $this->logger->error('Could not find resource {resource} to load', [
74
+                'resource' => $app . '/' . $style . '.css',
75
+                'app' => 'cssresourceloader',
76
+            ]);
77
+            return;
78
+        }
79
+
80
+        // Account for the possibility of having symlinks in app path. Doing
81
+        // this here instead of above as an empty argument to realpath gets
82
+        // turned into cwd.
83
+        $app_path = realpath($app_path);
84
+
85
+        if(!$this->cacheAndAppendScssIfExist($app_path, $style.'.scss', $app)) {
86
+            $this->append($app_path, $style.'.css', $app_url);
87
+        }
88
+    }
89
+
90
+    /**
91
+     * @param string $style
92
+     */
93
+    public function doFindTheme($style) {
94
+        $theme_dir = 'themes/'.$this->theme.'/';
95
+        $this->appendIfExist($this->serverroot, $theme_dir.'apps/'.$style.'.css')
96
+            || $this->appendIfExist($this->serverroot, $theme_dir.$style.'.css')
97
+            || $this->appendIfExist($this->serverroot, $theme_dir.'core/'.$style.'.css');
98
+    }
99
+
100
+    /**
101
+     * cache and append the scss $file if exist at $root
102
+     *
103
+     * @param string $root path to check
104
+     * @param string $file the filename
105
+     * @return bool True if the resource was found and cached, false otherwise
106
+     */
107
+    protected function cacheAndAppendScssIfExist($root, $file, $app = 'core') {
108
+        if (is_file($root.'/'.$file)) {
109
+            if($this->scssCacher !== null) {
110
+                if($this->scssCacher->process($root, $file, $app)) {
111
+
112
+                    $this->append($root, $this->scssCacher->getCachedSCSS($app, $file), \OC::$WEBROOT, true, true);
113
+                    return true;
114
+                } else {
115
+                    $this->logger->warning('Failed to compile and/or save '.$root.'/'.$file, ['app' => 'core']);
116
+                    return false;
117
+                }
118
+            } else {
119
+                return true;
120
+            }
121
+        }
122
+        return false;
123
+    }
124
+
125
+    public function append($root, $file, $webRoot = null, $throw = true, $scss = false) {
126
+        if (!$scss) {
127
+            parent::append($root, $file, $webRoot, $throw);
128
+        } else {
129
+            if (!$webRoot) {
130
+                $webRoot = $this->findWebRoot($root);
131
+
132
+                if ($webRoot === null) {
133
+                    $webRoot = '';
134
+                    $this->logger->error('ResourceLocator can not find a web root (root: {root}, file: {file}, webRoot: {webRoot}, throw: {throw})', [
135
+                        'app' => 'lib',
136
+                        'root' => $root,
137
+                        'file' => $file,
138
+                        'webRoot' => $webRoot,
139
+                        'throw' => $throw ? 'true' : 'false'
140
+                    ]);
141
+
142
+                    if ($throw && $root === '/') {
143
+                        throw new ResourceNotFoundException($file, $webRoot);
144
+                    }
145
+                }
146
+            }
147
+
148
+            $this->resources[] = [$webRoot? : \OC::$WEBROOT, $webRoot, $file];
149
+        }
150
+    }
151 151
 }
Please login to merge, or discard this patch.
lib/private/Template/JSCombiner.php 1 patch
Indentation   +220 added lines, -220 removed lines patch added patch discarded remove patch
@@ -38,224 +38,224 @@
 block discarded – undo
38 38
 
39 39
 class JSCombiner {
40 40
 
41
-	/** @var IAppData */
42
-	protected $appData;
43
-
44
-	/** @var IURLGenerator */
45
-	protected $urlGenerator;
46
-
47
-	/** @var ICache */
48
-	protected $depsCache;
49
-
50
-	/** @var SystemConfig */
51
-	protected $config;
52
-
53
-	/** @var ILogger */
54
-	protected $logger;
55
-
56
-	/** @var ICacheFactory */
57
-	private $cacheFactory;
58
-
59
-	/**
60
-	 * @param IAppData $appData
61
-	 * @param IURLGenerator $urlGenerator
62
-	 * @param ICacheFactory $cacheFactory
63
-	 * @param SystemConfig $config
64
-	 * @param ILogger $logger
65
-	 */
66
-	public function __construct(IAppData $appData,
67
-								IURLGenerator $urlGenerator,
68
-								ICacheFactory $cacheFactory,
69
-								SystemConfig $config,
70
-								ILogger $logger) {
71
-		$this->appData = $appData;
72
-		$this->urlGenerator = $urlGenerator;
73
-		$this->cacheFactory = $cacheFactory;
74
-		$this->depsCache = $this->cacheFactory->createDistributed('JS-' . md5($this->urlGenerator->getBaseUrl()));
75
-		$this->config = $config;
76
-		$this->logger = $logger;
77
-	}
78
-
79
-	/**
80
-	 * @param string $root
81
-	 * @param string $file
82
-	 * @param string $app
83
-	 * @return bool
84
-	 */
85
-	public function process($root, $file, $app) {
86
-		if ($this->config->getValue('debug') || !$this->config->getValue('installed')) {
87
-			return false;
88
-		}
89
-
90
-		$path = explode('/', $root . '/' . $file);
91
-
92
-		$fileName = array_pop($path);
93
-		$path = implode('/', $path);
94
-
95
-		try {
96
-			$folder = $this->appData->getFolder($app);
97
-		} catch(NotFoundException $e) {
98
-			// creating css appdata folder
99
-			$folder = $this->appData->newFolder($app);
100
-		}
101
-
102
-		if($this->isCached($fileName, $folder)) {
103
-			return true;
104
-		}
105
-		return $this->cache($path, $fileName, $folder);
106
-	}
107
-
108
-	/**
109
-	 * @param string $fileName
110
-	 * @param ISimpleFolder $folder
111
-	 * @return bool
112
-	 */
113
-	protected function isCached($fileName, ISimpleFolder $folder) {
114
-		$fileName = str_replace('.json', '.js', $fileName);
115
-
116
-		if (!$folder->fileExists($fileName)) {
117
-			return false;
118
-		}
119
-
120
-		$fileName = $fileName . '.deps';
121
-		try {
122
-			$deps = $this->depsCache->get($folder->getName() . '-' . $fileName);
123
-			if ($deps === null || $deps === '') {
124
-				$depFile = $folder->getFile($fileName);
125
-				$deps = $depFile->getContent();
126
-			}
127
-
128
-			// check again
129
-			if ($deps === null || $deps === '') {
130
-				$this->logger->info('JSCombiner: deps file empty: ' . $fileName);
131
-				return false;
132
-			}
133
-
134
-			$deps = json_decode($deps, true);
135
-
136
-			if ($deps === null) {
137
-				return false;
138
-			}
139
-
140
-			foreach ($deps as $file=>$mtime) {
141
-				if (!file_exists($file) || filemtime($file) > $mtime) {
142
-					return false;
143
-				}
144
-			}
145
-
146
-			return true;
147
-		} catch(NotFoundException $e) {
148
-			return false;
149
-		}
150
-	}
151
-
152
-	/**
153
-	 * @param string $path
154
-	 * @param string $fileName
155
-	 * @param ISimpleFolder $folder
156
-	 * @return bool
157
-	 */
158
-	protected function cache($path, $fileName, ISimpleFolder $folder) {
159
-		$deps = [];
160
-		$fullPath = $path . '/' . $fileName;
161
-		$data = json_decode(file_get_contents($fullPath));
162
-		$deps[$fullPath] = filemtime($fullPath);
163
-
164
-		$res = '';
165
-		foreach ($data as $file) {
166
-			$filePath = $path . '/' . $file;
167
-
168
-			if (is_file($filePath)) {
169
-				$res .= file_get_contents($filePath);
170
-				$res .= PHP_EOL . PHP_EOL;
171
-				$deps[$filePath] = filemtime($filePath);
172
-			}
173
-		}
174
-
175
-		$fileName = str_replace('.json', '.js', $fileName);
176
-		try {
177
-			$cachedfile = $folder->getFile($fileName);
178
-		} catch(NotFoundException $e) {
179
-			$cachedfile = $folder->newFile($fileName);
180
-		}
181
-
182
-		$depFileName = $fileName . '.deps';
183
-		try {
184
-			$depFile = $folder->getFile($depFileName);
185
-		} catch (NotFoundException $e) {
186
-			$depFile = $folder->newFile($depFileName);
187
-		}
188
-
189
-		try {
190
-			$gzipFile = $folder->getFile($fileName . '.gzip'); # Safari doesn't like .gz
191
-		} catch (NotFoundException $e) {
192
-			$gzipFile = $folder->newFile($fileName . '.gzip'); # Safari doesn't like .gz
193
-		}
194
-
195
-		try {
196
-			$cachedfile->putContent($res);
197
-			$deps = json_encode($deps);
198
-			$depFile->putContent($deps);
199
-			$this->depsCache->set($folder->getName() . '-' . $depFileName, $deps);
200
-			$gzipFile->putContent(gzencode($res, 9));
201
-			$this->logger->debug('JSCombiner: successfully cached: ' . $fileName);
202
-			return true;
203
-		} catch (NotPermittedException $e) {
204
-			$this->logger->error('JSCombiner: unable to cache: ' . $fileName);
205
-			return false;
206
-		}
207
-	}
208
-
209
-	/**
210
-	 * @param string $appName
211
-	 * @param string $fileName
212
-	 * @return string
213
-	 */
214
-	public function getCachedJS($appName, $fileName) {
215
-		$tmpfileLoc = explode('/', $fileName);
216
-		$fileName = array_pop($tmpfileLoc);
217
-		$fileName = str_replace('.json', '.js', $fileName);
218
-
219
-		return substr($this->urlGenerator->linkToRoute('core.Js.getJs', ['fileName' => $fileName, 'appName' => $appName]), strlen(\OC::$WEBROOT) + 1);
220
-	}
221
-
222
-	/**
223
-	 * @param string $root
224
-	 * @param string $file
225
-	 * @return string[]
226
-	 */
227
-	public function getContent($root, $file) {
228
-		/** @var array $data */
229
-		$data = json_decode(file_get_contents($root . '/' . $file));
230
-		if(!is_array($data)) {
231
-			return [];
232
-		}
233
-
234
-		$path = explode('/', $file);
235
-		array_pop($path);
236
-		$path = implode('/', $path);
237
-
238
-		$result = [];
239
-		foreach ($data as $f) {
240
-			$result[] = $path . '/' . $f;
241
-		}
242
-
243
-		return $result;
244
-	}
245
-
246
-
247
-	/**
248
-	 * Clear cache with combined javascript files
249
-	 *
250
-	 * @throws NotFoundException
251
-	 */
252
-	public function resetCache() {
253
-		$this->cacheFactory->createDistributed('JS-')->clear();
254
-		$appDirectory = $this->appData->getDirectoryListing();
255
-		foreach ($appDirectory as $folder) {
256
-			foreach ($folder->getDirectoryListing() as $file) {
257
-				$file->delete();
258
-			}
259
-		}
260
-	}
41
+    /** @var IAppData */
42
+    protected $appData;
43
+
44
+    /** @var IURLGenerator */
45
+    protected $urlGenerator;
46
+
47
+    /** @var ICache */
48
+    protected $depsCache;
49
+
50
+    /** @var SystemConfig */
51
+    protected $config;
52
+
53
+    /** @var ILogger */
54
+    protected $logger;
55
+
56
+    /** @var ICacheFactory */
57
+    private $cacheFactory;
58
+
59
+    /**
60
+     * @param IAppData $appData
61
+     * @param IURLGenerator $urlGenerator
62
+     * @param ICacheFactory $cacheFactory
63
+     * @param SystemConfig $config
64
+     * @param ILogger $logger
65
+     */
66
+    public function __construct(IAppData $appData,
67
+                                IURLGenerator $urlGenerator,
68
+                                ICacheFactory $cacheFactory,
69
+                                SystemConfig $config,
70
+                                ILogger $logger) {
71
+        $this->appData = $appData;
72
+        $this->urlGenerator = $urlGenerator;
73
+        $this->cacheFactory = $cacheFactory;
74
+        $this->depsCache = $this->cacheFactory->createDistributed('JS-' . md5($this->urlGenerator->getBaseUrl()));
75
+        $this->config = $config;
76
+        $this->logger = $logger;
77
+    }
78
+
79
+    /**
80
+     * @param string $root
81
+     * @param string $file
82
+     * @param string $app
83
+     * @return bool
84
+     */
85
+    public function process($root, $file, $app) {
86
+        if ($this->config->getValue('debug') || !$this->config->getValue('installed')) {
87
+            return false;
88
+        }
89
+
90
+        $path = explode('/', $root . '/' . $file);
91
+
92
+        $fileName = array_pop($path);
93
+        $path = implode('/', $path);
94
+
95
+        try {
96
+            $folder = $this->appData->getFolder($app);
97
+        } catch(NotFoundException $e) {
98
+            // creating css appdata folder
99
+            $folder = $this->appData->newFolder($app);
100
+        }
101
+
102
+        if($this->isCached($fileName, $folder)) {
103
+            return true;
104
+        }
105
+        return $this->cache($path, $fileName, $folder);
106
+    }
107
+
108
+    /**
109
+     * @param string $fileName
110
+     * @param ISimpleFolder $folder
111
+     * @return bool
112
+     */
113
+    protected function isCached($fileName, ISimpleFolder $folder) {
114
+        $fileName = str_replace('.json', '.js', $fileName);
115
+
116
+        if (!$folder->fileExists($fileName)) {
117
+            return false;
118
+        }
119
+
120
+        $fileName = $fileName . '.deps';
121
+        try {
122
+            $deps = $this->depsCache->get($folder->getName() . '-' . $fileName);
123
+            if ($deps === null || $deps === '') {
124
+                $depFile = $folder->getFile($fileName);
125
+                $deps = $depFile->getContent();
126
+            }
127
+
128
+            // check again
129
+            if ($deps === null || $deps === '') {
130
+                $this->logger->info('JSCombiner: deps file empty: ' . $fileName);
131
+                return false;
132
+            }
133
+
134
+            $deps = json_decode($deps, true);
135
+
136
+            if ($deps === null) {
137
+                return false;
138
+            }
139
+
140
+            foreach ($deps as $file=>$mtime) {
141
+                if (!file_exists($file) || filemtime($file) > $mtime) {
142
+                    return false;
143
+                }
144
+            }
145
+
146
+            return true;
147
+        } catch(NotFoundException $e) {
148
+            return false;
149
+        }
150
+    }
151
+
152
+    /**
153
+     * @param string $path
154
+     * @param string $fileName
155
+     * @param ISimpleFolder $folder
156
+     * @return bool
157
+     */
158
+    protected function cache($path, $fileName, ISimpleFolder $folder) {
159
+        $deps = [];
160
+        $fullPath = $path . '/' . $fileName;
161
+        $data = json_decode(file_get_contents($fullPath));
162
+        $deps[$fullPath] = filemtime($fullPath);
163
+
164
+        $res = '';
165
+        foreach ($data as $file) {
166
+            $filePath = $path . '/' . $file;
167
+
168
+            if (is_file($filePath)) {
169
+                $res .= file_get_contents($filePath);
170
+                $res .= PHP_EOL . PHP_EOL;
171
+                $deps[$filePath] = filemtime($filePath);
172
+            }
173
+        }
174
+
175
+        $fileName = str_replace('.json', '.js', $fileName);
176
+        try {
177
+            $cachedfile = $folder->getFile($fileName);
178
+        } catch(NotFoundException $e) {
179
+            $cachedfile = $folder->newFile($fileName);
180
+        }
181
+
182
+        $depFileName = $fileName . '.deps';
183
+        try {
184
+            $depFile = $folder->getFile($depFileName);
185
+        } catch (NotFoundException $e) {
186
+            $depFile = $folder->newFile($depFileName);
187
+        }
188
+
189
+        try {
190
+            $gzipFile = $folder->getFile($fileName . '.gzip'); # Safari doesn't like .gz
191
+        } catch (NotFoundException $e) {
192
+            $gzipFile = $folder->newFile($fileName . '.gzip'); # Safari doesn't like .gz
193
+        }
194
+
195
+        try {
196
+            $cachedfile->putContent($res);
197
+            $deps = json_encode($deps);
198
+            $depFile->putContent($deps);
199
+            $this->depsCache->set($folder->getName() . '-' . $depFileName, $deps);
200
+            $gzipFile->putContent(gzencode($res, 9));
201
+            $this->logger->debug('JSCombiner: successfully cached: ' . $fileName);
202
+            return true;
203
+        } catch (NotPermittedException $e) {
204
+            $this->logger->error('JSCombiner: unable to cache: ' . $fileName);
205
+            return false;
206
+        }
207
+    }
208
+
209
+    /**
210
+     * @param string $appName
211
+     * @param string $fileName
212
+     * @return string
213
+     */
214
+    public function getCachedJS($appName, $fileName) {
215
+        $tmpfileLoc = explode('/', $fileName);
216
+        $fileName = array_pop($tmpfileLoc);
217
+        $fileName = str_replace('.json', '.js', $fileName);
218
+
219
+        return substr($this->urlGenerator->linkToRoute('core.Js.getJs', ['fileName' => $fileName, 'appName' => $appName]), strlen(\OC::$WEBROOT) + 1);
220
+    }
221
+
222
+    /**
223
+     * @param string $root
224
+     * @param string $file
225
+     * @return string[]
226
+     */
227
+    public function getContent($root, $file) {
228
+        /** @var array $data */
229
+        $data = json_decode(file_get_contents($root . '/' . $file));
230
+        if(!is_array($data)) {
231
+            return [];
232
+        }
233
+
234
+        $path = explode('/', $file);
235
+        array_pop($path);
236
+        $path = implode('/', $path);
237
+
238
+        $result = [];
239
+        foreach ($data as $f) {
240
+            $result[] = $path . '/' . $f;
241
+        }
242
+
243
+        return $result;
244
+    }
245
+
246
+
247
+    /**
248
+     * Clear cache with combined javascript files
249
+     *
250
+     * @throws NotFoundException
251
+     */
252
+    public function resetCache() {
253
+        $this->cacheFactory->createDistributed('JS-')->clear();
254
+        $appDirectory = $this->appData->getDirectoryListing();
255
+        foreach ($appDirectory as $folder) {
256
+            foreach ($folder->getDirectoryListing() as $file) {
257
+                $file->delete();
258
+            }
259
+        }
260
+    }
261 261
 }
Please login to merge, or discard this patch.
lib/private/Cache/File.php 1 patch
Indentation   +157 added lines, -157 removed lines patch added patch discarded remove patch
@@ -37,170 +37,170 @@
 block discarded – undo
37 37
 
38 38
 class File implements ICache {
39 39
 
40
-	/** @var View */
41
-	protected $storage;
40
+    /** @var View */
41
+    protected $storage;
42 42
 
43
-	/**
44
-	 * Returns the cache storage for the logged in user
45
-	 *
46
-	 * @return \OC\Files\View cache storage
47
-	 * @throws \OC\ForbiddenException
48
-	 * @throws \OC\User\NoUserException
49
-	 */
50
-	protected function getStorage() {
51
-		if (isset($this->storage)) {
52
-			return $this->storage;
53
-		}
54
-		if (\OC::$server->getUserSession()->isLoggedIn()) {
55
-			$rootView = new View();
56
-			$user = \OC::$server->getUserSession()->getUser();
57
-			Filesystem::initMountPoints($user->getUID());
58
-			if (!$rootView->file_exists('/' . $user->getUID() . '/cache')) {
59
-				$rootView->mkdir('/' . $user->getUID() . '/cache');
60
-			}
61
-			$this->storage = new View('/' . $user->getUID() . '/cache');
62
-			return $this->storage;
63
-		} else {
64
-			\OCP\Util::writeLog('core', 'Can\'t get cache storage, user not logged in', ILogger::ERROR);
65
-			throw new \OC\ForbiddenException('Can\t get cache storage, user not logged in');
66
-		}
67
-	}
43
+    /**
44
+     * Returns the cache storage for the logged in user
45
+     *
46
+     * @return \OC\Files\View cache storage
47
+     * @throws \OC\ForbiddenException
48
+     * @throws \OC\User\NoUserException
49
+     */
50
+    protected function getStorage() {
51
+        if (isset($this->storage)) {
52
+            return $this->storage;
53
+        }
54
+        if (\OC::$server->getUserSession()->isLoggedIn()) {
55
+            $rootView = new View();
56
+            $user = \OC::$server->getUserSession()->getUser();
57
+            Filesystem::initMountPoints($user->getUID());
58
+            if (!$rootView->file_exists('/' . $user->getUID() . '/cache')) {
59
+                $rootView->mkdir('/' . $user->getUID() . '/cache');
60
+            }
61
+            $this->storage = new View('/' . $user->getUID() . '/cache');
62
+            return $this->storage;
63
+        } else {
64
+            \OCP\Util::writeLog('core', 'Can\'t get cache storage, user not logged in', ILogger::ERROR);
65
+            throw new \OC\ForbiddenException('Can\t get cache storage, user not logged in');
66
+        }
67
+    }
68 68
 
69
-	/**
70
-	 * @param string $key
71
-	 * @return mixed|null
72
-	 * @throws \OC\ForbiddenException
73
-	 */
74
-	public function get($key) {
75
-		$result = null;
76
-		if ($this->hasKey($key)) {
77
-			$storage = $this->getStorage();
78
-			$result = $storage->file_get_contents($key);
79
-		}
80
-		return $result;
81
-	}
69
+    /**
70
+     * @param string $key
71
+     * @return mixed|null
72
+     * @throws \OC\ForbiddenException
73
+     */
74
+    public function get($key) {
75
+        $result = null;
76
+        if ($this->hasKey($key)) {
77
+            $storage = $this->getStorage();
78
+            $result = $storage->file_get_contents($key);
79
+        }
80
+        return $result;
81
+    }
82 82
 
83
-	/**
84
-	 * Returns the size of the stored/cached data
85
-	 *
86
-	 * @param string $key
87
-	 * @return int
88
-	 */
89
-	public function size($key) {
90
-		$result = 0;
91
-		if ($this->hasKey($key)) {
92
-			$storage = $this->getStorage();
93
-			$result = $storage->filesize($key);
94
-		}
95
-		return $result;
96
-	}
83
+    /**
84
+     * Returns the size of the stored/cached data
85
+     *
86
+     * @param string $key
87
+     * @return int
88
+     */
89
+    public function size($key) {
90
+        $result = 0;
91
+        if ($this->hasKey($key)) {
92
+            $storage = $this->getStorage();
93
+            $result = $storage->filesize($key);
94
+        }
95
+        return $result;
96
+    }
97 97
 
98
-	/**
99
-	 * @param string $key
100
-	 * @param mixed $value
101
-	 * @param int $ttl
102
-	 * @return bool|mixed
103
-	 * @throws \OC\ForbiddenException
104
-	 */
105
-	public function set($key, $value, $ttl = 0) {
106
-		$storage = $this->getStorage();
107
-		$result = false;
108
-		// unique id to avoid chunk collision, just in case
109
-		$uniqueId = \OC::$server->getSecureRandom()->generate(
110
-			16,
111
-			ISecureRandom::CHAR_DIGITS . ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_UPPER
112
-		);
98
+    /**
99
+     * @param string $key
100
+     * @param mixed $value
101
+     * @param int $ttl
102
+     * @return bool|mixed
103
+     * @throws \OC\ForbiddenException
104
+     */
105
+    public function set($key, $value, $ttl = 0) {
106
+        $storage = $this->getStorage();
107
+        $result = false;
108
+        // unique id to avoid chunk collision, just in case
109
+        $uniqueId = \OC::$server->getSecureRandom()->generate(
110
+            16,
111
+            ISecureRandom::CHAR_DIGITS . ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_UPPER
112
+        );
113 113
 
114
-		// use part file to prevent hasKey() to find the key
115
-		// while it is being written
116
-		$keyPart = $key . '.' . $uniqueId . '.part';
117
-		if ($storage and $storage->file_put_contents($keyPart, $value)) {
118
-			if ($ttl === 0) {
119
-				$ttl = 86400; // 60*60*24
120
-			}
121
-			$result = $storage->touch($keyPart, time() + $ttl);
122
-			$result &= $storage->rename($keyPart, $key);
123
-		}
124
-		return $result;
125
-	}
114
+        // use part file to prevent hasKey() to find the key
115
+        // while it is being written
116
+        $keyPart = $key . '.' . $uniqueId . '.part';
117
+        if ($storage and $storage->file_put_contents($keyPart, $value)) {
118
+            if ($ttl === 0) {
119
+                $ttl = 86400; // 60*60*24
120
+            }
121
+            $result = $storage->touch($keyPart, time() + $ttl);
122
+            $result &= $storage->rename($keyPart, $key);
123
+        }
124
+        return $result;
125
+    }
126 126
 
127
-	/**
128
-	 * @param string $key
129
-	 * @return bool
130
-	 * @throws \OC\ForbiddenException
131
-	 */
132
-	public function hasKey($key) {
133
-		$storage = $this->getStorage();
134
-		if ($storage && $storage->is_file($key) && $storage->isReadable($key)) {
135
-			return true;
136
-		}
137
-		return false;
138
-	}
127
+    /**
128
+     * @param string $key
129
+     * @return bool
130
+     * @throws \OC\ForbiddenException
131
+     */
132
+    public function hasKey($key) {
133
+        $storage = $this->getStorage();
134
+        if ($storage && $storage->is_file($key) && $storage->isReadable($key)) {
135
+            return true;
136
+        }
137
+        return false;
138
+    }
139 139
 
140
-	/**
141
-	 * @param string $key
142
-	 * @return bool|mixed
143
-	 * @throws \OC\ForbiddenException
144
-	 */
145
-	public function remove($key) {
146
-		$storage = $this->getStorage();
147
-		if (!$storage) {
148
-			return false;
149
-		}
150
-		return $storage->unlink($key);
151
-	}
140
+    /**
141
+     * @param string $key
142
+     * @return bool|mixed
143
+     * @throws \OC\ForbiddenException
144
+     */
145
+    public function remove($key) {
146
+        $storage = $this->getStorage();
147
+        if (!$storage) {
148
+            return false;
149
+        }
150
+        return $storage->unlink($key);
151
+    }
152 152
 
153
-	/**
154
-	 * @param string $prefix
155
-	 * @return bool
156
-	 * @throws \OC\ForbiddenException
157
-	 */
158
-	public function clear($prefix = '') {
159
-		$storage = $this->getStorage();
160
-		if ($storage and $storage->is_dir('/')) {
161
-			$dh = $storage->opendir('/');
162
-			if (is_resource($dh)) {
163
-				while (($file = readdir($dh)) !== false) {
164
-					if ($file != '.' and $file != '..' and ($prefix === '' || strpos($file, $prefix) === 0)) {
165
-						$storage->unlink('/' . $file);
166
-					}
167
-				}
168
-			}
169
-		}
170
-		return true;
171
-	}
153
+    /**
154
+     * @param string $prefix
155
+     * @return bool
156
+     * @throws \OC\ForbiddenException
157
+     */
158
+    public function clear($prefix = '') {
159
+        $storage = $this->getStorage();
160
+        if ($storage and $storage->is_dir('/')) {
161
+            $dh = $storage->opendir('/');
162
+            if (is_resource($dh)) {
163
+                while (($file = readdir($dh)) !== false) {
164
+                    if ($file != '.' and $file != '..' and ($prefix === '' || strpos($file, $prefix) === 0)) {
165
+                        $storage->unlink('/' . $file);
166
+                    }
167
+                }
168
+            }
169
+        }
170
+        return true;
171
+    }
172 172
 
173
-	/**
174
-	 * Runs GC
175
-	 * @throws \OC\ForbiddenException
176
-	 */
177
-	public function gc() {
178
-		$storage = $this->getStorage();
179
-		if ($storage) {
180
-			// extra hour safety, in case of stray part chunks that take longer to write,
181
-			// because touch() is only called after the chunk was finished
182
-			$now = time() - 3600;
183
-			$dh = $storage->opendir('/');
184
-			if (!is_resource($dh)) {
185
-				return null;
186
-			}
187
-			while (($file = readdir($dh)) !== false) {
188
-				if ($file != '.' and $file != '..') {
189
-					try {
190
-						$mtime = $storage->filemtime('/' . $file);
191
-						if ($mtime < $now) {
192
-							$storage->unlink('/' . $file);
193
-						}
194
-					} catch (\OCP\Lock\LockedException $e) {
195
-						// ignore locked chunks
196
-						\OC::$server->getLogger()->debug('Could not cleanup locked chunk "' . $file . '"', ['app' => 'core']);
197
-					} catch (\OCP\Files\ForbiddenException $e) {
198
-						\OC::$server->getLogger()->debug('Could not cleanup forbidden chunk "' . $file . '"', ['app' => 'core']);
199
-					} catch (\OCP\Files\LockNotAcquiredException $e) {
200
-						\OC::$server->getLogger()->debug('Could not cleanup locked chunk "' . $file . '"', ['app' => 'core']);
201
-					}
202
-				}
203
-			}
204
-		}
205
-	}
173
+    /**
174
+     * Runs GC
175
+     * @throws \OC\ForbiddenException
176
+     */
177
+    public function gc() {
178
+        $storage = $this->getStorage();
179
+        if ($storage) {
180
+            // extra hour safety, in case of stray part chunks that take longer to write,
181
+            // because touch() is only called after the chunk was finished
182
+            $now = time() - 3600;
183
+            $dh = $storage->opendir('/');
184
+            if (!is_resource($dh)) {
185
+                return null;
186
+            }
187
+            while (($file = readdir($dh)) !== false) {
188
+                if ($file != '.' and $file != '..') {
189
+                    try {
190
+                        $mtime = $storage->filemtime('/' . $file);
191
+                        if ($mtime < $now) {
192
+                            $storage->unlink('/' . $file);
193
+                        }
194
+                    } catch (\OCP\Lock\LockedException $e) {
195
+                        // ignore locked chunks
196
+                        \OC::$server->getLogger()->debug('Could not cleanup locked chunk "' . $file . '"', ['app' => 'core']);
197
+                    } catch (\OCP\Files\ForbiddenException $e) {
198
+                        \OC::$server->getLogger()->debug('Could not cleanup forbidden chunk "' . $file . '"', ['app' => 'core']);
199
+                    } catch (\OCP\Files\LockNotAcquiredException $e) {
200
+                        \OC::$server->getLogger()->debug('Could not cleanup locked chunk "' . $file . '"', ['app' => 'core']);
201
+                    }
202
+                }
203
+            }
204
+        }
205
+    }
206 206
 }
Please login to merge, or discard this patch.
lib/private/User/Backend.php 1 patch
Indentation   +120 added lines, -120 removed lines patch added patch discarded remove patch
@@ -30,136 +30,136 @@
 block discarded – undo
30 30
  * capabilities.
31 31
  */
32 32
 abstract class Backend implements UserInterface {
33
-	/**
34
-	 * error code for functions not provided by the user backend
35
-	 */
36
-	const NOT_IMPLEMENTED = -501;
33
+    /**
34
+     * error code for functions not provided by the user backend
35
+     */
36
+    const NOT_IMPLEMENTED = -501;
37 37
 
38
-	/**
39
-	 * actions that user backends can define
40
-	 */
41
-	const CREATE_USER		= 1;			// 1 << 0
42
-	const SET_PASSWORD		= 16;			// 1 << 4
43
-	const CHECK_PASSWORD	= 256;			// 1 << 8
44
-	const GET_HOME			= 4096;			// 1 << 12
45
-	const GET_DISPLAYNAME	= 65536;		// 1 << 16
46
-	const SET_DISPLAYNAME	= 1048576;		// 1 << 20
47
-	const PROVIDE_AVATAR	= 16777216;		// 1 << 24
48
-	const COUNT_USERS		= 268435456;	// 1 << 28
38
+    /**
39
+     * actions that user backends can define
40
+     */
41
+    const CREATE_USER		= 1;			// 1 << 0
42
+    const SET_PASSWORD		= 16;			// 1 << 4
43
+    const CHECK_PASSWORD	= 256;			// 1 << 8
44
+    const GET_HOME			= 4096;			// 1 << 12
45
+    const GET_DISPLAYNAME	= 65536;		// 1 << 16
46
+    const SET_DISPLAYNAME	= 1048576;		// 1 << 20
47
+    const PROVIDE_AVATAR	= 16777216;		// 1 << 24
48
+    const COUNT_USERS		= 268435456;	// 1 << 28
49 49
 
50
-	protected $possibleActions = [
51
-		self::CREATE_USER => 'createUser',
52
-		self::SET_PASSWORD => 'setPassword',
53
-		self::CHECK_PASSWORD => 'checkPassword',
54
-		self::GET_HOME => 'getHome',
55
-		self::GET_DISPLAYNAME => 'getDisplayName',
56
-		self::SET_DISPLAYNAME => 'setDisplayName',
57
-		self::PROVIDE_AVATAR => 'canChangeAvatar',
58
-		self::COUNT_USERS => 'countUsers',
59
-	];
50
+    protected $possibleActions = [
51
+        self::CREATE_USER => 'createUser',
52
+        self::SET_PASSWORD => 'setPassword',
53
+        self::CHECK_PASSWORD => 'checkPassword',
54
+        self::GET_HOME => 'getHome',
55
+        self::GET_DISPLAYNAME => 'getDisplayName',
56
+        self::SET_DISPLAYNAME => 'setDisplayName',
57
+        self::PROVIDE_AVATAR => 'canChangeAvatar',
58
+        self::COUNT_USERS => 'countUsers',
59
+    ];
60 60
 
61
-	/**
62
-	* Get all supported actions
63
-	* @return int bitwise-or'ed actions
64
-	*
65
-	* Returns the supported actions as int to be
66
-	* compared with self::CREATE_USER etc.
67
-	*/
68
-	public function getSupportedActions() {
69
-		$actions = 0;
70
-		foreach($this->possibleActions AS $action => $methodName) {
71
-			if(method_exists($this, $methodName)) {
72
-				$actions |= $action;
73
-			}
74
-		}
61
+    /**
62
+     * Get all supported actions
63
+     * @return int bitwise-or'ed actions
64
+     *
65
+     * Returns the supported actions as int to be
66
+     * compared with self::CREATE_USER etc.
67
+     */
68
+    public function getSupportedActions() {
69
+        $actions = 0;
70
+        foreach($this->possibleActions AS $action => $methodName) {
71
+            if(method_exists($this, $methodName)) {
72
+                $actions |= $action;
73
+            }
74
+        }
75 75
 
76
-		return $actions;
77
-	}
76
+        return $actions;
77
+    }
78 78
 
79
-	/**
80
-	* Check if backend implements actions
81
-	* @param int $actions bitwise-or'ed actions
82
-	* @return boolean
83
-	*
84
-	* Returns the supported actions as int to be
85
-	* compared with self::CREATE_USER etc.
86
-	*/
87
-	public function implementsActions($actions) {
88
-		return (bool)($this->getSupportedActions() & $actions);
89
-	}
79
+    /**
80
+     * Check if backend implements actions
81
+     * @param int $actions bitwise-or'ed actions
82
+     * @return boolean
83
+     *
84
+     * Returns the supported actions as int to be
85
+     * compared with self::CREATE_USER etc.
86
+     */
87
+    public function implementsActions($actions) {
88
+        return (bool)($this->getSupportedActions() & $actions);
89
+    }
90 90
 
91
-	/**
92
-	 * delete a user
93
-	 * @param string $uid The username of the user to delete
94
-	 * @return bool
95
-	 *
96
-	 * Deletes a user
97
-	 */
98
-	public function deleteUser( $uid ) {
99
-		return false;
100
-	}
91
+    /**
92
+     * delete a user
93
+     * @param string $uid The username of the user to delete
94
+     * @return bool
95
+     *
96
+     * Deletes a user
97
+     */
98
+    public function deleteUser( $uid ) {
99
+        return false;
100
+    }
101 101
 
102
-	/**
103
-	 * Get a list of all users
104
-	 *
105
-	 * @param string $search
106
-	 * @param null|int $limit
107
-	 * @param null|int $offset
108
-	 * @return string[] an array of all uids
109
-	 */
110
-	public function getUsers($search = '', $limit = null, $offset = null) {
111
-		return [];
112
-	}
102
+    /**
103
+     * Get a list of all users
104
+     *
105
+     * @param string $search
106
+     * @param null|int $limit
107
+     * @param null|int $offset
108
+     * @return string[] an array of all uids
109
+     */
110
+    public function getUsers($search = '', $limit = null, $offset = null) {
111
+        return [];
112
+    }
113 113
 
114
-	/**
115
-	* check if a user exists
116
-	* @param string $uid the username
117
-	* @return boolean
118
-	*/
119
-	public function userExists($uid) {
120
-		return false;
121
-	}
114
+    /**
115
+     * check if a user exists
116
+     * @param string $uid the username
117
+     * @return boolean
118
+     */
119
+    public function userExists($uid) {
120
+        return false;
121
+    }
122 122
 
123
-	/**
124
-	* get the user's home directory
125
-	* @param string $uid the username
126
-	* @return boolean
127
-	*/
128
-	public function getHome($uid) {
129
-		return false;
130
-	}
123
+    /**
124
+     * get the user's home directory
125
+     * @param string $uid the username
126
+     * @return boolean
127
+     */
128
+    public function getHome($uid) {
129
+        return false;
130
+    }
131 131
 
132
-	/**
133
-	 * get display name of the user
134
-	 * @param string $uid user ID of the user
135
-	 * @return string display name
136
-	 */
137
-	public function getDisplayName($uid) {
138
-		return $uid;
139
-	}
132
+    /**
133
+     * get display name of the user
134
+     * @param string $uid user ID of the user
135
+     * @return string display name
136
+     */
137
+    public function getDisplayName($uid) {
138
+        return $uid;
139
+    }
140 140
 
141
-	/**
142
-	 * Get a list of all display names and user ids.
143
-	 *
144
-	 * @param string $search
145
-	 * @param string|null $limit
146
-	 * @param string|null $offset
147
-	 * @return array an array of all displayNames (value) and the corresponding uids (key)
148
-	 */
149
-	public function getDisplayNames($search = '', $limit = null, $offset = null) {
150
-		$displayNames = [];
151
-		$users = $this->getUsers($search, $limit, $offset);
152
-		foreach ( $users as $user) {
153
-			$displayNames[$user] = $user;
154
-		}
155
-		return $displayNames;
156
-	}
141
+    /**
142
+     * Get a list of all display names and user ids.
143
+     *
144
+     * @param string $search
145
+     * @param string|null $limit
146
+     * @param string|null $offset
147
+     * @return array an array of all displayNames (value) and the corresponding uids (key)
148
+     */
149
+    public function getDisplayNames($search = '', $limit = null, $offset = null) {
150
+        $displayNames = [];
151
+        $users = $this->getUsers($search, $limit, $offset);
152
+        foreach ( $users as $user) {
153
+            $displayNames[$user] = $user;
154
+        }
155
+        return $displayNames;
156
+    }
157 157
 
158
-	/**
159
-	 * Check if a user list is available or not
160
-	 * @return boolean if users can be listed or not
161
-	 */
162
-	public function hasUserListings() {
163
-		return false;
164
-	}
158
+    /**
159
+     * Check if a user list is available or not
160
+     * @return boolean if users can be listed or not
161
+     */
162
+    public function hasUserListings() {
163
+        return false;
164
+    }
165 165
 }
Please login to merge, or discard this patch.
lib/private/User/Session.php 1 patch
Indentation   +917 added lines, -917 removed lines patch added patch discarded remove patch
@@ -90,923 +90,923 @@
 block discarded – undo
90 90
  */
91 91
 class Session implements IUserSession, Emitter {
92 92
 
93
-	/** @var Manager|PublicEmitter $manager */
94
-	private $manager;
95
-
96
-	/** @var ISession $session */
97
-	private $session;
98
-
99
-	/** @var ITimeFactory */
100
-	private $timeFactory;
101
-
102
-	/** @var IProvider */
103
-	private $tokenProvider;
104
-
105
-	/** @var IConfig */
106
-	private $config;
107
-
108
-	/** @var User $activeUser */
109
-	protected $activeUser;
110
-
111
-	/** @var ISecureRandom */
112
-	private $random;
113
-
114
-	/** @var ILockdownManager  */
115
-	private $lockdownManager;
116
-
117
-	/** @var ILogger */
118
-	private $logger;
119
-	/** @var IEventDispatcher */
120
-	private $dispatcher;
121
-
122
-	/**
123
-	 * @param Manager $manager
124
-	 * @param ISession $session
125
-	 * @param ITimeFactory $timeFactory
126
-	 * @param IProvider $tokenProvider
127
-	 * @param IConfig $config
128
-	 * @param ISecureRandom $random
129
-	 * @param ILockdownManager $lockdownManager
130
-	 * @param ILogger $logger
131
-	 */
132
-	public function __construct(Manager $manager,
133
-								ISession $session,
134
-								ITimeFactory $timeFactory,
135
-								$tokenProvider,
136
-								IConfig $config,
137
-								ISecureRandom $random,
138
-								ILockdownManager $lockdownManager,
139
-								ILogger $logger,
140
-								IEventDispatcher $dispatcher) {
141
-		$this->manager = $manager;
142
-		$this->session = $session;
143
-		$this->timeFactory = $timeFactory;
144
-		$this->tokenProvider = $tokenProvider;
145
-		$this->config = $config;
146
-		$this->random = $random;
147
-		$this->lockdownManager = $lockdownManager;
148
-		$this->logger = $logger;
149
-		$this->dispatcher = $dispatcher;
150
-	}
151
-
152
-	/**
153
-	 * @param IProvider $provider
154
-	 */
155
-	public function setTokenProvider(IProvider $provider) {
156
-		$this->tokenProvider = $provider;
157
-	}
158
-
159
-	/**
160
-	 * @param string $scope
161
-	 * @param string $method
162
-	 * @param callable $callback
163
-	 */
164
-	public function listen($scope, $method, callable $callback) {
165
-		$this->manager->listen($scope, $method, $callback);
166
-	}
167
-
168
-	/**
169
-	 * @param string $scope optional
170
-	 * @param string $method optional
171
-	 * @param callable $callback optional
172
-	 */
173
-	public function removeListener($scope = null, $method = null, callable $callback = null) {
174
-		$this->manager->removeListener($scope, $method, $callback);
175
-	}
176
-
177
-	/**
178
-	 * get the manager object
179
-	 *
180
-	 * @return Manager|PublicEmitter
181
-	 */
182
-	public function getManager() {
183
-		return $this->manager;
184
-	}
185
-
186
-	/**
187
-	 * get the session object
188
-	 *
189
-	 * @return ISession
190
-	 */
191
-	public function getSession() {
192
-		return $this->session;
193
-	}
194
-
195
-	/**
196
-	 * set the session object
197
-	 *
198
-	 * @param ISession $session
199
-	 */
200
-	public function setSession(ISession $session) {
201
-		if ($this->session instanceof ISession) {
202
-			$this->session->close();
203
-		}
204
-		$this->session = $session;
205
-		$this->activeUser = null;
206
-	}
207
-
208
-	/**
209
-	 * set the currently active user
210
-	 *
211
-	 * @param IUser|null $user
212
-	 */
213
-	public function setUser($user) {
214
-		if (is_null($user)) {
215
-			$this->session->remove('user_id');
216
-		} else {
217
-			$this->session->set('user_id', $user->getUID());
218
-		}
219
-		$this->activeUser = $user;
220
-	}
221
-
222
-	/**
223
-	 * get the current active user
224
-	 *
225
-	 * @return IUser|null Current user, otherwise null
226
-	 */
227
-	public function getUser() {
228
-		// FIXME: This is a quick'n dirty work-around for the incognito mode as
229
-		// described at https://github.com/owncloud/core/pull/12912#issuecomment-67391155
230
-		if (OC_User::isIncognitoMode()) {
231
-			return null;
232
-		}
233
-		if (is_null($this->activeUser)) {
234
-			$uid = $this->session->get('user_id');
235
-			if (is_null($uid)) {
236
-				return null;
237
-			}
238
-			$this->activeUser = $this->manager->get($uid);
239
-			if (is_null($this->activeUser)) {
240
-				return null;
241
-			}
242
-			$this->validateSession();
243
-		}
244
-		return $this->activeUser;
245
-	}
246
-
247
-	/**
248
-	 * Validate whether the current session is valid
249
-	 *
250
-	 * - For token-authenticated clients, the token validity is checked
251
-	 * - For browsers, the session token validity is checked
252
-	 */
253
-	protected function validateSession() {
254
-		$token = null;
255
-		$appPassword = $this->session->get('app_password');
256
-
257
-		if (is_null($appPassword)) {
258
-			try {
259
-				$token = $this->session->getId();
260
-			} catch (SessionNotAvailableException $ex) {
261
-				return;
262
-			}
263
-		} else {
264
-			$token = $appPassword;
265
-		}
266
-
267
-		if (!$this->validateToken($token)) {
268
-			// Session was invalidated
269
-			$this->logout();
270
-		}
271
-	}
272
-
273
-	/**
274
-	 * Checks whether the user is logged in
275
-	 *
276
-	 * @return bool if logged in
277
-	 */
278
-	public function isLoggedIn() {
279
-		$user = $this->getUser();
280
-		if (is_null($user)) {
281
-			return false;
282
-		}
283
-
284
-		return $user->isEnabled();
285
-	}
286
-
287
-	/**
288
-	 * set the login name
289
-	 *
290
-	 * @param string|null $loginName for the logged in user
291
-	 */
292
-	public function setLoginName($loginName) {
293
-		if (is_null($loginName)) {
294
-			$this->session->remove('loginname');
295
-		} else {
296
-			$this->session->set('loginname', $loginName);
297
-		}
298
-	}
299
-
300
-	/**
301
-	 * get the login name of the current user
302
-	 *
303
-	 * @return string
304
-	 */
305
-	public function getLoginName() {
306
-		if ($this->activeUser) {
307
-			return $this->session->get('loginname');
308
-		}
309
-
310
-		$uid = $this->session->get('user_id');
311
-		if ($uid) {
312
-			$this->activeUser = $this->manager->get($uid);
313
-			return $this->session->get('loginname');
314
-		}
315
-
316
-		return null;
317
-	}
318
-
319
-	/**
320
-	 * @return null|string
321
-	 */
322
-	public function getImpersonatingUserID(): ?string {
323
-
324
-		return $this->session->get('oldUserId');
325
-
326
-	}
327
-
328
-	public function setImpersonatingUserID(bool $useCurrentUser = true): void {
329
-		if ($useCurrentUser === false) {
330
-			$this->session->remove('oldUserId');
331
-			return;
332
-		}
333
-
334
-		$currentUser = $this->getUser();
335
-
336
-		if ($currentUser === null) {
337
-			throw new \OC\User\NoUserException();
338
-		}
339
-		$this->session->set('oldUserId', $currentUser->getUID());
340
-
341
-	}
342
-	/**
343
-	 * set the token id
344
-	 *
345
-	 * @param int|null $token that was used to log in
346
-	 */
347
-	protected function setToken($token) {
348
-		if ($token === null) {
349
-			$this->session->remove('token-id');
350
-		} else {
351
-			$this->session->set('token-id', $token);
352
-		}
353
-	}
354
-
355
-	/**
356
-	 * try to log in with the provided credentials
357
-	 *
358
-	 * @param string $uid
359
-	 * @param string $password
360
-	 * @return boolean|null
361
-	 * @throws LoginException
362
-	 */
363
-	public function login($uid, $password) {
364
-		$this->session->regenerateId();
365
-		if ($this->validateToken($password, $uid)) {
366
-			return $this->loginWithToken($password);
367
-		}
368
-		return $this->loginWithPassword($uid, $password);
369
-	}
370
-
371
-	/**
372
-	 * @param IUser $user
373
-	 * @param array $loginDetails
374
-	 * @param bool $regenerateSessionId
375
-	 * @return true returns true if login successful or an exception otherwise
376
-	 * @throws LoginException
377
-	 */
378
-	public function completeLogin(IUser $user, array $loginDetails, $regenerateSessionId = true) {
379
-		if (!$user->isEnabled()) {
380
-			// disabled users can not log in
381
-			// injecting l10n does not work - there is a circular dependency between session and \OCP\L10N\IFactory
382
-			$message = \OC::$server->getL10N('lib')->t('User disabled');
383
-			throw new LoginException($message);
384
-		}
385
-
386
-		if($regenerateSessionId) {
387
-			$this->session->regenerateId();
388
-		}
389
-
390
-		$this->setUser($user);
391
-		$this->setLoginName($loginDetails['loginName']);
392
-
393
-		$isToken = isset($loginDetails['token']) && $loginDetails['token'] instanceof IToken;
394
-		if ($isToken) {
395
-			$this->setToken($loginDetails['token']->getId());
396
-			$this->lockdownManager->setToken($loginDetails['token']);
397
-			$firstTimeLogin = false;
398
-		} else {
399
-			$this->setToken(null);
400
-			$firstTimeLogin = $user->updateLastLoginTimestamp();
401
-		}
402
-
403
-		$this->dispatcher->dispatchTyped(new PostLoginEvent(
404
-			$user,
405
-			$loginDetails['password'],
406
-			$isToken
407
-		));
408
-		$this->manager->emit('\OC\User', 'postLogin', [
409
-			$user,
410
-			$loginDetails['password'],
411
-			$isToken,
412
-		]);
413
-		if($this->isLoggedIn()) {
414
-			$this->prepareUserLogin($firstTimeLogin, $regenerateSessionId);
415
-			return true;
416
-		}
417
-
418
-		$message = \OC::$server->getL10N('lib')->t('Login canceled by app');
419
-		throw new LoginException($message);
420
-	}
421
-
422
-	/**
423
-	 * Tries to log in a client
424
-	 *
425
-	 * Checks token auth enforced
426
-	 * Checks 2FA enabled
427
-	 *
428
-	 * @param string $user
429
-	 * @param string $password
430
-	 * @param IRequest $request
431
-	 * @param OC\Security\Bruteforce\Throttler $throttler
432
-	 * @throws LoginException
433
-	 * @throws PasswordLoginForbiddenException
434
-	 * @return boolean
435
-	 */
436
-	public function logClientIn($user,
437
-								$password,
438
-								IRequest $request,
439
-								OC\Security\Bruteforce\Throttler $throttler) {
440
-		$currentDelay = $throttler->sleepDelay($request->getRemoteAddress(), 'login');
441
-
442
-		if ($this->manager instanceof PublicEmitter) {
443
-			$this->manager->emit('\OC\User', 'preLogin', [$user, $password]);
444
-		}
445
-
446
-		try {
447
-			$isTokenPassword = $this->isTokenPassword($password);
448
-		} catch (ExpiredTokenException $e) {
449
-			// Just return on an expired token no need to check further or record a failed login
450
-			return false;
451
-		}
452
-
453
-		if (!$isTokenPassword && $this->isTokenAuthEnforced()) {
454
-			throw new PasswordLoginForbiddenException();
455
-		}
456
-		if (!$isTokenPassword && $this->isTwoFactorEnforced($user)) {
457
-			throw new PasswordLoginForbiddenException();
458
-		}
459
-
460
-		// Try to login with this username and password
461
-		if (!$this->login($user, $password) ) {
462
-
463
-			// Failed, maybe the user used their email address
464
-			$users = $this->manager->getByEmail($user);
465
-			if (!(\count($users) === 1 && $this->login($users[0]->getUID(), $password))) {
466
-
467
-				$this->logger->warning('Login failed: \'' . $user . '\' (Remote IP: \'' . \OC::$server->getRequest()->getRemoteAddress() . '\')', ['app' => 'core']);
468
-
469
-				$throttler->registerAttempt('login', $request->getRemoteAddress(), ['user' => $user]);
470
-				if ($currentDelay === 0) {
471
-					$throttler->sleepDelay($request->getRemoteAddress(), 'login');
472
-				}
473
-				return false;
474
-			}
475
-		}
476
-
477
-		if ($isTokenPassword) {
478
-			$this->session->set('app_password', $password);
479
-		} else if($this->supportsCookies($request)) {
480
-			// Password login, but cookies supported -> create (browser) session token
481
-			$this->createSessionToken($request, $this->getUser()->getUID(), $user, $password);
482
-		}
483
-
484
-		return true;
485
-	}
486
-
487
-	protected function supportsCookies(IRequest $request) {
488
-		if (!is_null($request->getCookie('cookie_test'))) {
489
-			return true;
490
-		}
491
-		setcookie('cookie_test', 'test', $this->timeFactory->getTime() + 3600);
492
-		return false;
493
-	}
494
-
495
-	private function isTokenAuthEnforced() {
496
-		return $this->config->getSystemValue('token_auth_enforced', false);
497
-	}
498
-
499
-	protected function isTwoFactorEnforced($username) {
500
-		Util::emitHook(
501
-			'\OCA\Files_Sharing\API\Server2Server',
502
-			'preLoginNameUsedAsUserName',
503
-			['uid' => &$username]
504
-		);
505
-		$user = $this->manager->get($username);
506
-		if (is_null($user)) {
507
-			$users = $this->manager->getByEmail($username);
508
-			if (empty($users)) {
509
-				return false;
510
-			}
511
-			if (count($users) !== 1) {
512
-				return true;
513
-			}
514
-			$user = $users[0];
515
-		}
516
-		// DI not possible due to cyclic dependencies :'-/
517
-		return OC::$server->getTwoFactorAuthManager()->isTwoFactorAuthenticated($user);
518
-	}
519
-
520
-	/**
521
-	 * Check if the given 'password' is actually a device token
522
-	 *
523
-	 * @param string $password
524
-	 * @return boolean
525
-	 * @throws ExpiredTokenException
526
-	 */
527
-	public function isTokenPassword($password) {
528
-		try {
529
-			$this->tokenProvider->getToken($password);
530
-			return true;
531
-		} catch (ExpiredTokenException $e) {
532
-			throw $e;
533
-		} catch (InvalidTokenException $ex) {
534
-			return false;
535
-		}
536
-	}
537
-
538
-	protected function prepareUserLogin($firstTimeLogin, $refreshCsrfToken = true) {
539
-		if ($refreshCsrfToken) {
540
-			// TODO: mock/inject/use non-static
541
-			// Refresh the token
542
-			\OC::$server->getCsrfTokenManager()->refreshToken();
543
-		}
544
-
545
-		//we need to pass the user name, which may differ from login name
546
-		$user = $this->getUser()->getUID();
547
-		OC_Util::setupFS($user);
548
-
549
-		if ($firstTimeLogin) {
550
-			// TODO: lock necessary?
551
-			//trigger creation of user home and /files folder
552
-			$userFolder = \OC::$server->getUserFolder($user);
553
-
554
-			try {
555
-				// copy skeleton
556
-				\OC_Util::copySkeleton($user, $userFolder);
557
-			} catch (NotPermittedException $ex) {
558
-				// read only uses
559
-			}
560
-
561
-			// trigger any other initialization
562
-			\OC::$server->getEventDispatcher()->dispatch(IUser::class . '::firstLogin', new GenericEvent($this->getUser()));
563
-		}
564
-	}
565
-
566
-	/**
567
-	 * Tries to login the user with HTTP Basic Authentication
568
-	 *
569
-	 * @todo do not allow basic auth if the user is 2FA enforced
570
-	 * @param IRequest $request
571
-	 * @param OC\Security\Bruteforce\Throttler $throttler
572
-	 * @return boolean if the login was successful
573
-	 */
574
-	public function tryBasicAuthLogin(IRequest $request,
575
-									  OC\Security\Bruteforce\Throttler $throttler) {
576
-		if (!empty($request->server['PHP_AUTH_USER']) && !empty($request->server['PHP_AUTH_PW'])) {
577
-			try {
578
-				if ($this->logClientIn($request->server['PHP_AUTH_USER'], $request->server['PHP_AUTH_PW'], $request, $throttler)) {
579
-					/**
580
-					 * Add DAV authenticated. This should in an ideal world not be
581
-					 * necessary but the iOS App reads cookies from anywhere instead
582
-					 * only the DAV endpoint.
583
-					 * This makes sure that the cookies will be valid for the whole scope
584
-					 * @see https://github.com/owncloud/core/issues/22893
585
-					 */
586
-					$this->session->set(
587
-						Auth::DAV_AUTHENTICATED, $this->getUser()->getUID()
588
-					);
589
-
590
-					// Set the last-password-confirm session to make the sudo mode work
591
-					 $this->session->set('last-password-confirm', $this->timeFactory->getTime());
592
-
593
-					return true;
594
-				}
595
-			} catch (PasswordLoginForbiddenException $ex) {
596
-				// Nothing to do
597
-			}
598
-		}
599
-		return false;
600
-	}
601
-
602
-	/**
603
-	 * Log an user in via login name and password
604
-	 *
605
-	 * @param string $uid
606
-	 * @param string $password
607
-	 * @return boolean
608
-	 * @throws LoginException if an app canceld the login process or the user is not enabled
609
-	 */
610
-	private function loginWithPassword($uid, $password) {
611
-		$user = $this->manager->checkPasswordNoLogging($uid, $password);
612
-		if ($user === false) {
613
-			// Password check failed
614
-			return false;
615
-		}
616
-
617
-		return $this->completeLogin($user, ['loginName' => $uid, 'password' => $password], false);
618
-	}
619
-
620
-	/**
621
-	 * Log an user in with a given token (id)
622
-	 *
623
-	 * @param string $token
624
-	 * @return boolean
625
-	 * @throws LoginException if an app canceled the login process or the user is not enabled
626
-	 */
627
-	private function loginWithToken($token) {
628
-		try {
629
-			$dbToken = $this->tokenProvider->getToken($token);
630
-		} catch (InvalidTokenException $ex) {
631
-			return false;
632
-		}
633
-		$uid = $dbToken->getUID();
634
-
635
-		// When logging in with token, the password must be decrypted first before passing to login hook
636
-		$password = '';
637
-		try {
638
-			$password = $this->tokenProvider->getPassword($dbToken, $token);
639
-		} catch (PasswordlessTokenException $ex) {
640
-			// Ignore and use empty string instead
641
-		}
642
-
643
-		$this->manager->emit('\OC\User', 'preLogin', [$uid, $password]);
644
-
645
-		$user = $this->manager->get($uid);
646
-		if (is_null($user)) {
647
-			// user does not exist
648
-			return false;
649
-		}
650
-
651
-		return $this->completeLogin(
652
-			$user,
653
-			[
654
-				'loginName' => $dbToken->getLoginName(),
655
-				'password' => $password,
656
-				'token' => $dbToken
657
-			],
658
-			false);
659
-	}
660
-
661
-	/**
662
-	 * Create a new session token for the given user credentials
663
-	 *
664
-	 * @param IRequest $request
665
-	 * @param string $uid user UID
666
-	 * @param string $loginName login name
667
-	 * @param string $password
668
-	 * @param int $remember
669
-	 * @return boolean
670
-	 */
671
-	public function createSessionToken(IRequest $request, $uid, $loginName, $password = null, $remember = IToken::DO_NOT_REMEMBER) {
672
-		if (is_null($this->manager->get($uid))) {
673
-			// User does not exist
674
-			return false;
675
-		}
676
-		$name = isset($request->server['HTTP_USER_AGENT']) ? $request->server['HTTP_USER_AGENT'] : 'unknown browser';
677
-		try {
678
-			$sessionId = $this->session->getId();
679
-			$pwd = $this->getPassword($password);
680
-			// Make sure the current sessionId has no leftover tokens
681
-			$this->tokenProvider->invalidateToken($sessionId);
682
-			$this->tokenProvider->generateToken($sessionId, $uid, $loginName, $pwd, $name, IToken::TEMPORARY_TOKEN, $remember);
683
-			return true;
684
-		} catch (SessionNotAvailableException $ex) {
685
-			// This can happen with OCC, where a memory session is used
686
-			// if a memory session is used, we shouldn't create a session token anyway
687
-			return false;
688
-		}
689
-	}
690
-
691
-	/**
692
-	 * Checks if the given password is a token.
693
-	 * If yes, the password is extracted from the token.
694
-	 * If no, the same password is returned.
695
-	 *
696
-	 * @param string $password either the login password or a device token
697
-	 * @return string|null the password or null if none was set in the token
698
-	 */
699
-	private function getPassword($password) {
700
-		if (is_null($password)) {
701
-			// This is surely no token ;-)
702
-			return null;
703
-		}
704
-		try {
705
-			$token = $this->tokenProvider->getToken($password);
706
-			try {
707
-				return $this->tokenProvider->getPassword($token, $password);
708
-			} catch (PasswordlessTokenException $ex) {
709
-				return null;
710
-			}
711
-		} catch (InvalidTokenException $ex) {
712
-			return $password;
713
-		}
714
-	}
715
-
716
-	/**
717
-	 * @param IToken $dbToken
718
-	 * @param string $token
719
-	 * @return boolean
720
-	 */
721
-	private function checkTokenCredentials(IToken $dbToken, $token) {
722
-		// Check whether login credentials are still valid and the user was not disabled
723
-		// This check is performed each 5 minutes
724
-		$lastCheck = $dbToken->getLastCheck() ? : 0;
725
-		$now = $this->timeFactory->getTime();
726
-		if ($lastCheck > ($now - 60 * 5)) {
727
-			// Checked performed recently, nothing to do now
728
-			return true;
729
-		}
730
-
731
-		try {
732
-			$pwd = $this->tokenProvider->getPassword($dbToken, $token);
733
-		} catch (InvalidTokenException $ex) {
734
-			// An invalid token password was used -> log user out
735
-			return false;
736
-		} catch (PasswordlessTokenException $ex) {
737
-			// Token has no password
738
-
739
-			if (!is_null($this->activeUser) && !$this->activeUser->isEnabled()) {
740
-				$this->tokenProvider->invalidateToken($token);
741
-				return false;
742
-			}
743
-
744
-			$dbToken->setLastCheck($now);
745
-			return true;
746
-		}
747
-
748
-		// Invalidate token if the user is no longer active
749
-		if (!is_null($this->activeUser) && !$this->activeUser->isEnabled()) {
750
-			$this->tokenProvider->invalidateToken($token);
751
-			return false;
752
-		}
753
-
754
-		// If the token password is no longer valid mark it as such
755
-		if ($this->manager->checkPassword($dbToken->getLoginName(), $pwd) === false) {
756
-			$this->tokenProvider->markPasswordInvalid($dbToken, $token);
757
-			// User is logged out
758
-			return false;
759
-		}
760
-
761
-		$dbToken->setLastCheck($now);
762
-		return true;
763
-	}
764
-
765
-	/**
766
-	 * Check if the given token exists and performs password/user-enabled checks
767
-	 *
768
-	 * Invalidates the token if checks fail
769
-	 *
770
-	 * @param string $token
771
-	 * @param string $user login name
772
-	 * @return boolean
773
-	 */
774
-	private function validateToken($token, $user = null) {
775
-		try {
776
-			$dbToken = $this->tokenProvider->getToken($token);
777
-		} catch (InvalidTokenException $ex) {
778
-			return false;
779
-		}
780
-
781
-		// Check if login names match
782
-		if (!is_null($user) && $dbToken->getLoginName() !== $user) {
783
-			// TODO: this makes it imposssible to use different login names on browser and client
784
-			// e.g. login by e-mail '[email protected]' on browser for generating the token will not
785
-			//      allow to use the client token with the login name 'user'.
786
-			return false;
787
-		}
788
-
789
-		if (!$this->checkTokenCredentials($dbToken, $token)) {
790
-			return false;
791
-		}
792
-
793
-		// Update token scope
794
-		$this->lockdownManager->setToken($dbToken);
795
-
796
-		$this->tokenProvider->updateTokenActivity($dbToken);
797
-
798
-		return true;
799
-	}
800
-
801
-	/**
802
-	 * Tries to login the user with auth token header
803
-	 *
804
-	 * @param IRequest $request
805
-	 * @todo check remember me cookie
806
-	 * @return boolean
807
-	 */
808
-	public function tryTokenLogin(IRequest $request) {
809
-		$authHeader = $request->getHeader('Authorization');
810
-		if (strpos($authHeader, 'Bearer ') === false) {
811
-			// No auth header, let's try session id
812
-			try {
813
-				$token = $this->session->getId();
814
-			} catch (SessionNotAvailableException $ex) {
815
-				return false;
816
-			}
817
-		} else {
818
-			$token = substr($authHeader, 7);
819
-		}
820
-
821
-		if (!$this->loginWithToken($token)) {
822
-			return false;
823
-		}
824
-		if(!$this->validateToken($token)) {
825
-			return false;
826
-		}
827
-
828
-		// Set the session variable so we know this is an app password
829
-		$this->session->set('app_password', $token);
830
-
831
-		return true;
832
-	}
833
-
834
-	/**
835
-	 * perform login using the magic cookie (remember login)
836
-	 *
837
-	 * @param string $uid the username
838
-	 * @param string $currentToken
839
-	 * @param string $oldSessionId
840
-	 * @return bool
841
-	 */
842
-	public function loginWithCookie($uid, $currentToken, $oldSessionId) {
843
-		$this->session->regenerateId();
844
-		$this->manager->emit('\OC\User', 'preRememberedLogin', [$uid]);
845
-		$user = $this->manager->get($uid);
846
-		if (is_null($user)) {
847
-			// user does not exist
848
-			return false;
849
-		}
850
-
851
-		// get stored tokens
852
-		$tokens = $this->config->getUserKeys($uid, 'login_token');
853
-		// test cookies token against stored tokens
854
-		if (!in_array($currentToken, $tokens, true)) {
855
-			return false;
856
-		}
857
-		// replace successfully used token with a new one
858
-		$this->config->deleteUserValue($uid, 'login_token', $currentToken);
859
-		$newToken = $this->random->generate(32);
860
-		$this->config->setUserValue($uid, 'login_token', $newToken, $this->timeFactory->getTime());
861
-
862
-		try {
863
-			$sessionId = $this->session->getId();
864
-			$token = $this->tokenProvider->renewSessionToken($oldSessionId, $sessionId);
865
-		} catch (SessionNotAvailableException $ex) {
866
-			return false;
867
-		} catch (InvalidTokenException $ex) {
868
-			\OC::$server->getLogger()->warning('Renewing session token failed', ['app' => 'core']);
869
-			return false;
870
-		}
871
-
872
-		$this->setMagicInCookie($user->getUID(), $newToken);
873
-
874
-		//login
875
-		$this->setUser($user);
876
-		$this->setLoginName($token->getLoginName());
877
-		$this->setToken($token->getId());
878
-		$this->lockdownManager->setToken($token);
879
-		$user->updateLastLoginTimestamp();
880
-		$password = null;
881
-		try {
882
-			$password = $this->tokenProvider->getPassword($token, $sessionId);
883
-		} catch (PasswordlessTokenException $ex) {
884
-			// Ignore
885
-		}
886
-		$this->manager->emit('\OC\User', 'postRememberedLogin', [$user, $password]);
887
-		return true;
888
-	}
889
-
890
-	/**
891
-	 * @param IUser $user
892
-	 */
893
-	public function createRememberMeToken(IUser $user) {
894
-		$token = $this->random->generate(32);
895
-		$this->config->setUserValue($user->getUID(), 'login_token', $token, $this->timeFactory->getTime());
896
-		$this->setMagicInCookie($user->getUID(), $token);
897
-	}
898
-
899
-	/**
900
-	 * logout the user from the session
901
-	 */
902
-	public function logout() {
903
-		$user = $this->getUser();
904
-		$this->manager->emit('\OC\User', 'logout', [$user]);
905
-		if ($user !== null) {
906
-			try {
907
-				$this->tokenProvider->invalidateToken($this->session->getId());
908
-			} catch (SessionNotAvailableException $ex) {
909
-
910
-			}
911
-		}
912
-		$this->setUser(null);
913
-		$this->setLoginName(null);
914
-		$this->setToken(null);
915
-		$this->unsetMagicInCookie();
916
-		$this->session->clear();
917
-		$this->manager->emit('\OC\User', 'postLogout', [$user]);
918
-	}
919
-
920
-	/**
921
-	 * Set cookie value to use in next page load
922
-	 *
923
-	 * @param string $username username to be set
924
-	 * @param string $token
925
-	 */
926
-	public function setMagicInCookie($username, $token) {
927
-		$secureCookie = OC::$server->getRequest()->getServerProtocol() === 'https';
928
-		$webRoot = \OC::$WEBROOT;
929
-		if ($webRoot === '') {
930
-			$webRoot = '/';
931
-		}
932
-
933
-		$maxAge = $this->config->getSystemValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15);
934
-		\OC\Http\CookieHelper::setCookie(
935
-			'nc_username',
936
-			$username,
937
-			$maxAge,
938
-			$webRoot,
939
-			'',
940
-			$secureCookie,
941
-			true,
942
-			\OC\Http\CookieHelper::SAMESITE_LAX
943
-		);
944
-		\OC\Http\CookieHelper::setCookie(
945
-			'nc_token',
946
-			$token,
947
-			$maxAge,
948
-			$webRoot,
949
-			'',
950
-			$secureCookie,
951
-			true,
952
-			\OC\Http\CookieHelper::SAMESITE_LAX
953
-		);
954
-		try {
955
-			\OC\Http\CookieHelper::setCookie(
956
-				'nc_session_id',
957
-				$this->session->getId(),
958
-				$maxAge,
959
-				$webRoot,
960
-				'',
961
-				$secureCookie,
962
-				true,
963
-				\OC\Http\CookieHelper::SAMESITE_LAX
964
-			);
965
-		} catch (SessionNotAvailableException $ex) {
966
-			// ignore
967
-		}
968
-	}
969
-
970
-	/**
971
-	 * Remove cookie for "remember username"
972
-	 */
973
-	public function unsetMagicInCookie() {
974
-		//TODO: DI for cookies and IRequest
975
-		$secureCookie = OC::$server->getRequest()->getServerProtocol() === 'https';
976
-
977
-		unset($_COOKIE['nc_username']); //TODO: DI
978
-		unset($_COOKIE['nc_token']);
979
-		unset($_COOKIE['nc_session_id']);
980
-		setcookie('nc_username', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT, '', $secureCookie, true);
981
-		setcookie('nc_token', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT, '', $secureCookie, true);
982
-		setcookie('nc_session_id', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT, '', $secureCookie, true);
983
-		// old cookies might be stored under /webroot/ instead of /webroot
984
-		// and Firefox doesn't like it!
985
-		setcookie('nc_username', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
986
-		setcookie('nc_token', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
987
-		setcookie('nc_session_id', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
988
-	}
989
-
990
-	/**
991
-	 * Update password of the browser session token if there is one
992
-	 *
993
-	 * @param string $password
994
-	 */
995
-	public function updateSessionTokenPassword($password) {
996
-		try {
997
-			$sessionId = $this->session->getId();
998
-			$token = $this->tokenProvider->getToken($sessionId);
999
-			$this->tokenProvider->setPassword($token, $sessionId, $password);
1000
-		} catch (SessionNotAvailableException $ex) {
1001
-			// Nothing to do
1002
-		} catch (InvalidTokenException $ex) {
1003
-			// Nothing to do
1004
-		}
1005
-	}
1006
-
1007
-	public function updateTokens(string $uid, string $password) {
1008
-		$this->tokenProvider->updatePasswords($uid, $password);
1009
-	}
93
+    /** @var Manager|PublicEmitter $manager */
94
+    private $manager;
95
+
96
+    /** @var ISession $session */
97
+    private $session;
98
+
99
+    /** @var ITimeFactory */
100
+    private $timeFactory;
101
+
102
+    /** @var IProvider */
103
+    private $tokenProvider;
104
+
105
+    /** @var IConfig */
106
+    private $config;
107
+
108
+    /** @var User $activeUser */
109
+    protected $activeUser;
110
+
111
+    /** @var ISecureRandom */
112
+    private $random;
113
+
114
+    /** @var ILockdownManager  */
115
+    private $lockdownManager;
116
+
117
+    /** @var ILogger */
118
+    private $logger;
119
+    /** @var IEventDispatcher */
120
+    private $dispatcher;
121
+
122
+    /**
123
+     * @param Manager $manager
124
+     * @param ISession $session
125
+     * @param ITimeFactory $timeFactory
126
+     * @param IProvider $tokenProvider
127
+     * @param IConfig $config
128
+     * @param ISecureRandom $random
129
+     * @param ILockdownManager $lockdownManager
130
+     * @param ILogger $logger
131
+     */
132
+    public function __construct(Manager $manager,
133
+                                ISession $session,
134
+                                ITimeFactory $timeFactory,
135
+                                $tokenProvider,
136
+                                IConfig $config,
137
+                                ISecureRandom $random,
138
+                                ILockdownManager $lockdownManager,
139
+                                ILogger $logger,
140
+                                IEventDispatcher $dispatcher) {
141
+        $this->manager = $manager;
142
+        $this->session = $session;
143
+        $this->timeFactory = $timeFactory;
144
+        $this->tokenProvider = $tokenProvider;
145
+        $this->config = $config;
146
+        $this->random = $random;
147
+        $this->lockdownManager = $lockdownManager;
148
+        $this->logger = $logger;
149
+        $this->dispatcher = $dispatcher;
150
+    }
151
+
152
+    /**
153
+     * @param IProvider $provider
154
+     */
155
+    public function setTokenProvider(IProvider $provider) {
156
+        $this->tokenProvider = $provider;
157
+    }
158
+
159
+    /**
160
+     * @param string $scope
161
+     * @param string $method
162
+     * @param callable $callback
163
+     */
164
+    public function listen($scope, $method, callable $callback) {
165
+        $this->manager->listen($scope, $method, $callback);
166
+    }
167
+
168
+    /**
169
+     * @param string $scope optional
170
+     * @param string $method optional
171
+     * @param callable $callback optional
172
+     */
173
+    public function removeListener($scope = null, $method = null, callable $callback = null) {
174
+        $this->manager->removeListener($scope, $method, $callback);
175
+    }
176
+
177
+    /**
178
+     * get the manager object
179
+     *
180
+     * @return Manager|PublicEmitter
181
+     */
182
+    public function getManager() {
183
+        return $this->manager;
184
+    }
185
+
186
+    /**
187
+     * get the session object
188
+     *
189
+     * @return ISession
190
+     */
191
+    public function getSession() {
192
+        return $this->session;
193
+    }
194
+
195
+    /**
196
+     * set the session object
197
+     *
198
+     * @param ISession $session
199
+     */
200
+    public function setSession(ISession $session) {
201
+        if ($this->session instanceof ISession) {
202
+            $this->session->close();
203
+        }
204
+        $this->session = $session;
205
+        $this->activeUser = null;
206
+    }
207
+
208
+    /**
209
+     * set the currently active user
210
+     *
211
+     * @param IUser|null $user
212
+     */
213
+    public function setUser($user) {
214
+        if (is_null($user)) {
215
+            $this->session->remove('user_id');
216
+        } else {
217
+            $this->session->set('user_id', $user->getUID());
218
+        }
219
+        $this->activeUser = $user;
220
+    }
221
+
222
+    /**
223
+     * get the current active user
224
+     *
225
+     * @return IUser|null Current user, otherwise null
226
+     */
227
+    public function getUser() {
228
+        // FIXME: This is a quick'n dirty work-around for the incognito mode as
229
+        // described at https://github.com/owncloud/core/pull/12912#issuecomment-67391155
230
+        if (OC_User::isIncognitoMode()) {
231
+            return null;
232
+        }
233
+        if (is_null($this->activeUser)) {
234
+            $uid = $this->session->get('user_id');
235
+            if (is_null($uid)) {
236
+                return null;
237
+            }
238
+            $this->activeUser = $this->manager->get($uid);
239
+            if (is_null($this->activeUser)) {
240
+                return null;
241
+            }
242
+            $this->validateSession();
243
+        }
244
+        return $this->activeUser;
245
+    }
246
+
247
+    /**
248
+     * Validate whether the current session is valid
249
+     *
250
+     * - For token-authenticated clients, the token validity is checked
251
+     * - For browsers, the session token validity is checked
252
+     */
253
+    protected function validateSession() {
254
+        $token = null;
255
+        $appPassword = $this->session->get('app_password');
256
+
257
+        if (is_null($appPassword)) {
258
+            try {
259
+                $token = $this->session->getId();
260
+            } catch (SessionNotAvailableException $ex) {
261
+                return;
262
+            }
263
+        } else {
264
+            $token = $appPassword;
265
+        }
266
+
267
+        if (!$this->validateToken($token)) {
268
+            // Session was invalidated
269
+            $this->logout();
270
+        }
271
+    }
272
+
273
+    /**
274
+     * Checks whether the user is logged in
275
+     *
276
+     * @return bool if logged in
277
+     */
278
+    public function isLoggedIn() {
279
+        $user = $this->getUser();
280
+        if (is_null($user)) {
281
+            return false;
282
+        }
283
+
284
+        return $user->isEnabled();
285
+    }
286
+
287
+    /**
288
+     * set the login name
289
+     *
290
+     * @param string|null $loginName for the logged in user
291
+     */
292
+    public function setLoginName($loginName) {
293
+        if (is_null($loginName)) {
294
+            $this->session->remove('loginname');
295
+        } else {
296
+            $this->session->set('loginname', $loginName);
297
+        }
298
+    }
299
+
300
+    /**
301
+     * get the login name of the current user
302
+     *
303
+     * @return string
304
+     */
305
+    public function getLoginName() {
306
+        if ($this->activeUser) {
307
+            return $this->session->get('loginname');
308
+        }
309
+
310
+        $uid = $this->session->get('user_id');
311
+        if ($uid) {
312
+            $this->activeUser = $this->manager->get($uid);
313
+            return $this->session->get('loginname');
314
+        }
315
+
316
+        return null;
317
+    }
318
+
319
+    /**
320
+     * @return null|string
321
+     */
322
+    public function getImpersonatingUserID(): ?string {
323
+
324
+        return $this->session->get('oldUserId');
325
+
326
+    }
327
+
328
+    public function setImpersonatingUserID(bool $useCurrentUser = true): void {
329
+        if ($useCurrentUser === false) {
330
+            $this->session->remove('oldUserId');
331
+            return;
332
+        }
333
+
334
+        $currentUser = $this->getUser();
335
+
336
+        if ($currentUser === null) {
337
+            throw new \OC\User\NoUserException();
338
+        }
339
+        $this->session->set('oldUserId', $currentUser->getUID());
340
+
341
+    }
342
+    /**
343
+     * set the token id
344
+     *
345
+     * @param int|null $token that was used to log in
346
+     */
347
+    protected function setToken($token) {
348
+        if ($token === null) {
349
+            $this->session->remove('token-id');
350
+        } else {
351
+            $this->session->set('token-id', $token);
352
+        }
353
+    }
354
+
355
+    /**
356
+     * try to log in with the provided credentials
357
+     *
358
+     * @param string $uid
359
+     * @param string $password
360
+     * @return boolean|null
361
+     * @throws LoginException
362
+     */
363
+    public function login($uid, $password) {
364
+        $this->session->regenerateId();
365
+        if ($this->validateToken($password, $uid)) {
366
+            return $this->loginWithToken($password);
367
+        }
368
+        return $this->loginWithPassword($uid, $password);
369
+    }
370
+
371
+    /**
372
+     * @param IUser $user
373
+     * @param array $loginDetails
374
+     * @param bool $regenerateSessionId
375
+     * @return true returns true if login successful or an exception otherwise
376
+     * @throws LoginException
377
+     */
378
+    public function completeLogin(IUser $user, array $loginDetails, $regenerateSessionId = true) {
379
+        if (!$user->isEnabled()) {
380
+            // disabled users can not log in
381
+            // injecting l10n does not work - there is a circular dependency between session and \OCP\L10N\IFactory
382
+            $message = \OC::$server->getL10N('lib')->t('User disabled');
383
+            throw new LoginException($message);
384
+        }
385
+
386
+        if($regenerateSessionId) {
387
+            $this->session->regenerateId();
388
+        }
389
+
390
+        $this->setUser($user);
391
+        $this->setLoginName($loginDetails['loginName']);
392
+
393
+        $isToken = isset($loginDetails['token']) && $loginDetails['token'] instanceof IToken;
394
+        if ($isToken) {
395
+            $this->setToken($loginDetails['token']->getId());
396
+            $this->lockdownManager->setToken($loginDetails['token']);
397
+            $firstTimeLogin = false;
398
+        } else {
399
+            $this->setToken(null);
400
+            $firstTimeLogin = $user->updateLastLoginTimestamp();
401
+        }
402
+
403
+        $this->dispatcher->dispatchTyped(new PostLoginEvent(
404
+            $user,
405
+            $loginDetails['password'],
406
+            $isToken
407
+        ));
408
+        $this->manager->emit('\OC\User', 'postLogin', [
409
+            $user,
410
+            $loginDetails['password'],
411
+            $isToken,
412
+        ]);
413
+        if($this->isLoggedIn()) {
414
+            $this->prepareUserLogin($firstTimeLogin, $regenerateSessionId);
415
+            return true;
416
+        }
417
+
418
+        $message = \OC::$server->getL10N('lib')->t('Login canceled by app');
419
+        throw new LoginException($message);
420
+    }
421
+
422
+    /**
423
+     * Tries to log in a client
424
+     *
425
+     * Checks token auth enforced
426
+     * Checks 2FA enabled
427
+     *
428
+     * @param string $user
429
+     * @param string $password
430
+     * @param IRequest $request
431
+     * @param OC\Security\Bruteforce\Throttler $throttler
432
+     * @throws LoginException
433
+     * @throws PasswordLoginForbiddenException
434
+     * @return boolean
435
+     */
436
+    public function logClientIn($user,
437
+                                $password,
438
+                                IRequest $request,
439
+                                OC\Security\Bruteforce\Throttler $throttler) {
440
+        $currentDelay = $throttler->sleepDelay($request->getRemoteAddress(), 'login');
441
+
442
+        if ($this->manager instanceof PublicEmitter) {
443
+            $this->manager->emit('\OC\User', 'preLogin', [$user, $password]);
444
+        }
445
+
446
+        try {
447
+            $isTokenPassword = $this->isTokenPassword($password);
448
+        } catch (ExpiredTokenException $e) {
449
+            // Just return on an expired token no need to check further or record a failed login
450
+            return false;
451
+        }
452
+
453
+        if (!$isTokenPassword && $this->isTokenAuthEnforced()) {
454
+            throw new PasswordLoginForbiddenException();
455
+        }
456
+        if (!$isTokenPassword && $this->isTwoFactorEnforced($user)) {
457
+            throw new PasswordLoginForbiddenException();
458
+        }
459
+
460
+        // Try to login with this username and password
461
+        if (!$this->login($user, $password) ) {
462
+
463
+            // Failed, maybe the user used their email address
464
+            $users = $this->manager->getByEmail($user);
465
+            if (!(\count($users) === 1 && $this->login($users[0]->getUID(), $password))) {
466
+
467
+                $this->logger->warning('Login failed: \'' . $user . '\' (Remote IP: \'' . \OC::$server->getRequest()->getRemoteAddress() . '\')', ['app' => 'core']);
468
+
469
+                $throttler->registerAttempt('login', $request->getRemoteAddress(), ['user' => $user]);
470
+                if ($currentDelay === 0) {
471
+                    $throttler->sleepDelay($request->getRemoteAddress(), 'login');
472
+                }
473
+                return false;
474
+            }
475
+        }
476
+
477
+        if ($isTokenPassword) {
478
+            $this->session->set('app_password', $password);
479
+        } else if($this->supportsCookies($request)) {
480
+            // Password login, but cookies supported -> create (browser) session token
481
+            $this->createSessionToken($request, $this->getUser()->getUID(), $user, $password);
482
+        }
483
+
484
+        return true;
485
+    }
486
+
487
+    protected function supportsCookies(IRequest $request) {
488
+        if (!is_null($request->getCookie('cookie_test'))) {
489
+            return true;
490
+        }
491
+        setcookie('cookie_test', 'test', $this->timeFactory->getTime() + 3600);
492
+        return false;
493
+    }
494
+
495
+    private function isTokenAuthEnforced() {
496
+        return $this->config->getSystemValue('token_auth_enforced', false);
497
+    }
498
+
499
+    protected function isTwoFactorEnforced($username) {
500
+        Util::emitHook(
501
+            '\OCA\Files_Sharing\API\Server2Server',
502
+            'preLoginNameUsedAsUserName',
503
+            ['uid' => &$username]
504
+        );
505
+        $user = $this->manager->get($username);
506
+        if (is_null($user)) {
507
+            $users = $this->manager->getByEmail($username);
508
+            if (empty($users)) {
509
+                return false;
510
+            }
511
+            if (count($users) !== 1) {
512
+                return true;
513
+            }
514
+            $user = $users[0];
515
+        }
516
+        // DI not possible due to cyclic dependencies :'-/
517
+        return OC::$server->getTwoFactorAuthManager()->isTwoFactorAuthenticated($user);
518
+    }
519
+
520
+    /**
521
+     * Check if the given 'password' is actually a device token
522
+     *
523
+     * @param string $password
524
+     * @return boolean
525
+     * @throws ExpiredTokenException
526
+     */
527
+    public function isTokenPassword($password) {
528
+        try {
529
+            $this->tokenProvider->getToken($password);
530
+            return true;
531
+        } catch (ExpiredTokenException $e) {
532
+            throw $e;
533
+        } catch (InvalidTokenException $ex) {
534
+            return false;
535
+        }
536
+    }
537
+
538
+    protected function prepareUserLogin($firstTimeLogin, $refreshCsrfToken = true) {
539
+        if ($refreshCsrfToken) {
540
+            // TODO: mock/inject/use non-static
541
+            // Refresh the token
542
+            \OC::$server->getCsrfTokenManager()->refreshToken();
543
+        }
544
+
545
+        //we need to pass the user name, which may differ from login name
546
+        $user = $this->getUser()->getUID();
547
+        OC_Util::setupFS($user);
548
+
549
+        if ($firstTimeLogin) {
550
+            // TODO: lock necessary?
551
+            //trigger creation of user home and /files folder
552
+            $userFolder = \OC::$server->getUserFolder($user);
553
+
554
+            try {
555
+                // copy skeleton
556
+                \OC_Util::copySkeleton($user, $userFolder);
557
+            } catch (NotPermittedException $ex) {
558
+                // read only uses
559
+            }
560
+
561
+            // trigger any other initialization
562
+            \OC::$server->getEventDispatcher()->dispatch(IUser::class . '::firstLogin', new GenericEvent($this->getUser()));
563
+        }
564
+    }
565
+
566
+    /**
567
+     * Tries to login the user with HTTP Basic Authentication
568
+     *
569
+     * @todo do not allow basic auth if the user is 2FA enforced
570
+     * @param IRequest $request
571
+     * @param OC\Security\Bruteforce\Throttler $throttler
572
+     * @return boolean if the login was successful
573
+     */
574
+    public function tryBasicAuthLogin(IRequest $request,
575
+                                        OC\Security\Bruteforce\Throttler $throttler) {
576
+        if (!empty($request->server['PHP_AUTH_USER']) && !empty($request->server['PHP_AUTH_PW'])) {
577
+            try {
578
+                if ($this->logClientIn($request->server['PHP_AUTH_USER'], $request->server['PHP_AUTH_PW'], $request, $throttler)) {
579
+                    /**
580
+                     * Add DAV authenticated. This should in an ideal world not be
581
+                     * necessary but the iOS App reads cookies from anywhere instead
582
+                     * only the DAV endpoint.
583
+                     * This makes sure that the cookies will be valid for the whole scope
584
+                     * @see https://github.com/owncloud/core/issues/22893
585
+                     */
586
+                    $this->session->set(
587
+                        Auth::DAV_AUTHENTICATED, $this->getUser()->getUID()
588
+                    );
589
+
590
+                    // Set the last-password-confirm session to make the sudo mode work
591
+                        $this->session->set('last-password-confirm', $this->timeFactory->getTime());
592
+
593
+                    return true;
594
+                }
595
+            } catch (PasswordLoginForbiddenException $ex) {
596
+                // Nothing to do
597
+            }
598
+        }
599
+        return false;
600
+    }
601
+
602
+    /**
603
+     * Log an user in via login name and password
604
+     *
605
+     * @param string $uid
606
+     * @param string $password
607
+     * @return boolean
608
+     * @throws LoginException if an app canceld the login process or the user is not enabled
609
+     */
610
+    private function loginWithPassword($uid, $password) {
611
+        $user = $this->manager->checkPasswordNoLogging($uid, $password);
612
+        if ($user === false) {
613
+            // Password check failed
614
+            return false;
615
+        }
616
+
617
+        return $this->completeLogin($user, ['loginName' => $uid, 'password' => $password], false);
618
+    }
619
+
620
+    /**
621
+     * Log an user in with a given token (id)
622
+     *
623
+     * @param string $token
624
+     * @return boolean
625
+     * @throws LoginException if an app canceled the login process or the user is not enabled
626
+     */
627
+    private function loginWithToken($token) {
628
+        try {
629
+            $dbToken = $this->tokenProvider->getToken($token);
630
+        } catch (InvalidTokenException $ex) {
631
+            return false;
632
+        }
633
+        $uid = $dbToken->getUID();
634
+
635
+        // When logging in with token, the password must be decrypted first before passing to login hook
636
+        $password = '';
637
+        try {
638
+            $password = $this->tokenProvider->getPassword($dbToken, $token);
639
+        } catch (PasswordlessTokenException $ex) {
640
+            // Ignore and use empty string instead
641
+        }
642
+
643
+        $this->manager->emit('\OC\User', 'preLogin', [$uid, $password]);
644
+
645
+        $user = $this->manager->get($uid);
646
+        if (is_null($user)) {
647
+            // user does not exist
648
+            return false;
649
+        }
650
+
651
+        return $this->completeLogin(
652
+            $user,
653
+            [
654
+                'loginName' => $dbToken->getLoginName(),
655
+                'password' => $password,
656
+                'token' => $dbToken
657
+            ],
658
+            false);
659
+    }
660
+
661
+    /**
662
+     * Create a new session token for the given user credentials
663
+     *
664
+     * @param IRequest $request
665
+     * @param string $uid user UID
666
+     * @param string $loginName login name
667
+     * @param string $password
668
+     * @param int $remember
669
+     * @return boolean
670
+     */
671
+    public function createSessionToken(IRequest $request, $uid, $loginName, $password = null, $remember = IToken::DO_NOT_REMEMBER) {
672
+        if (is_null($this->manager->get($uid))) {
673
+            // User does not exist
674
+            return false;
675
+        }
676
+        $name = isset($request->server['HTTP_USER_AGENT']) ? $request->server['HTTP_USER_AGENT'] : 'unknown browser';
677
+        try {
678
+            $sessionId = $this->session->getId();
679
+            $pwd = $this->getPassword($password);
680
+            // Make sure the current sessionId has no leftover tokens
681
+            $this->tokenProvider->invalidateToken($sessionId);
682
+            $this->tokenProvider->generateToken($sessionId, $uid, $loginName, $pwd, $name, IToken::TEMPORARY_TOKEN, $remember);
683
+            return true;
684
+        } catch (SessionNotAvailableException $ex) {
685
+            // This can happen with OCC, where a memory session is used
686
+            // if a memory session is used, we shouldn't create a session token anyway
687
+            return false;
688
+        }
689
+    }
690
+
691
+    /**
692
+     * Checks if the given password is a token.
693
+     * If yes, the password is extracted from the token.
694
+     * If no, the same password is returned.
695
+     *
696
+     * @param string $password either the login password or a device token
697
+     * @return string|null the password or null if none was set in the token
698
+     */
699
+    private function getPassword($password) {
700
+        if (is_null($password)) {
701
+            // This is surely no token ;-)
702
+            return null;
703
+        }
704
+        try {
705
+            $token = $this->tokenProvider->getToken($password);
706
+            try {
707
+                return $this->tokenProvider->getPassword($token, $password);
708
+            } catch (PasswordlessTokenException $ex) {
709
+                return null;
710
+            }
711
+        } catch (InvalidTokenException $ex) {
712
+            return $password;
713
+        }
714
+    }
715
+
716
+    /**
717
+     * @param IToken $dbToken
718
+     * @param string $token
719
+     * @return boolean
720
+     */
721
+    private function checkTokenCredentials(IToken $dbToken, $token) {
722
+        // Check whether login credentials are still valid and the user was not disabled
723
+        // This check is performed each 5 minutes
724
+        $lastCheck = $dbToken->getLastCheck() ? : 0;
725
+        $now = $this->timeFactory->getTime();
726
+        if ($lastCheck > ($now - 60 * 5)) {
727
+            // Checked performed recently, nothing to do now
728
+            return true;
729
+        }
730
+
731
+        try {
732
+            $pwd = $this->tokenProvider->getPassword($dbToken, $token);
733
+        } catch (InvalidTokenException $ex) {
734
+            // An invalid token password was used -> log user out
735
+            return false;
736
+        } catch (PasswordlessTokenException $ex) {
737
+            // Token has no password
738
+
739
+            if (!is_null($this->activeUser) && !$this->activeUser->isEnabled()) {
740
+                $this->tokenProvider->invalidateToken($token);
741
+                return false;
742
+            }
743
+
744
+            $dbToken->setLastCheck($now);
745
+            return true;
746
+        }
747
+
748
+        // Invalidate token if the user is no longer active
749
+        if (!is_null($this->activeUser) && !$this->activeUser->isEnabled()) {
750
+            $this->tokenProvider->invalidateToken($token);
751
+            return false;
752
+        }
753
+
754
+        // If the token password is no longer valid mark it as such
755
+        if ($this->manager->checkPassword($dbToken->getLoginName(), $pwd) === false) {
756
+            $this->tokenProvider->markPasswordInvalid($dbToken, $token);
757
+            // User is logged out
758
+            return false;
759
+        }
760
+
761
+        $dbToken->setLastCheck($now);
762
+        return true;
763
+    }
764
+
765
+    /**
766
+     * Check if the given token exists and performs password/user-enabled checks
767
+     *
768
+     * Invalidates the token if checks fail
769
+     *
770
+     * @param string $token
771
+     * @param string $user login name
772
+     * @return boolean
773
+     */
774
+    private function validateToken($token, $user = null) {
775
+        try {
776
+            $dbToken = $this->tokenProvider->getToken($token);
777
+        } catch (InvalidTokenException $ex) {
778
+            return false;
779
+        }
780
+
781
+        // Check if login names match
782
+        if (!is_null($user) && $dbToken->getLoginName() !== $user) {
783
+            // TODO: this makes it imposssible to use different login names on browser and client
784
+            // e.g. login by e-mail '[email protected]' on browser for generating the token will not
785
+            //      allow to use the client token with the login name 'user'.
786
+            return false;
787
+        }
788
+
789
+        if (!$this->checkTokenCredentials($dbToken, $token)) {
790
+            return false;
791
+        }
792
+
793
+        // Update token scope
794
+        $this->lockdownManager->setToken($dbToken);
795
+
796
+        $this->tokenProvider->updateTokenActivity($dbToken);
797
+
798
+        return true;
799
+    }
800
+
801
+    /**
802
+     * Tries to login the user with auth token header
803
+     *
804
+     * @param IRequest $request
805
+     * @todo check remember me cookie
806
+     * @return boolean
807
+     */
808
+    public function tryTokenLogin(IRequest $request) {
809
+        $authHeader = $request->getHeader('Authorization');
810
+        if (strpos($authHeader, 'Bearer ') === false) {
811
+            // No auth header, let's try session id
812
+            try {
813
+                $token = $this->session->getId();
814
+            } catch (SessionNotAvailableException $ex) {
815
+                return false;
816
+            }
817
+        } else {
818
+            $token = substr($authHeader, 7);
819
+        }
820
+
821
+        if (!$this->loginWithToken($token)) {
822
+            return false;
823
+        }
824
+        if(!$this->validateToken($token)) {
825
+            return false;
826
+        }
827
+
828
+        // Set the session variable so we know this is an app password
829
+        $this->session->set('app_password', $token);
830
+
831
+        return true;
832
+    }
833
+
834
+    /**
835
+     * perform login using the magic cookie (remember login)
836
+     *
837
+     * @param string $uid the username
838
+     * @param string $currentToken
839
+     * @param string $oldSessionId
840
+     * @return bool
841
+     */
842
+    public function loginWithCookie($uid, $currentToken, $oldSessionId) {
843
+        $this->session->regenerateId();
844
+        $this->manager->emit('\OC\User', 'preRememberedLogin', [$uid]);
845
+        $user = $this->manager->get($uid);
846
+        if (is_null($user)) {
847
+            // user does not exist
848
+            return false;
849
+        }
850
+
851
+        // get stored tokens
852
+        $tokens = $this->config->getUserKeys($uid, 'login_token');
853
+        // test cookies token against stored tokens
854
+        if (!in_array($currentToken, $tokens, true)) {
855
+            return false;
856
+        }
857
+        // replace successfully used token with a new one
858
+        $this->config->deleteUserValue($uid, 'login_token', $currentToken);
859
+        $newToken = $this->random->generate(32);
860
+        $this->config->setUserValue($uid, 'login_token', $newToken, $this->timeFactory->getTime());
861
+
862
+        try {
863
+            $sessionId = $this->session->getId();
864
+            $token = $this->tokenProvider->renewSessionToken($oldSessionId, $sessionId);
865
+        } catch (SessionNotAvailableException $ex) {
866
+            return false;
867
+        } catch (InvalidTokenException $ex) {
868
+            \OC::$server->getLogger()->warning('Renewing session token failed', ['app' => 'core']);
869
+            return false;
870
+        }
871
+
872
+        $this->setMagicInCookie($user->getUID(), $newToken);
873
+
874
+        //login
875
+        $this->setUser($user);
876
+        $this->setLoginName($token->getLoginName());
877
+        $this->setToken($token->getId());
878
+        $this->lockdownManager->setToken($token);
879
+        $user->updateLastLoginTimestamp();
880
+        $password = null;
881
+        try {
882
+            $password = $this->tokenProvider->getPassword($token, $sessionId);
883
+        } catch (PasswordlessTokenException $ex) {
884
+            // Ignore
885
+        }
886
+        $this->manager->emit('\OC\User', 'postRememberedLogin', [$user, $password]);
887
+        return true;
888
+    }
889
+
890
+    /**
891
+     * @param IUser $user
892
+     */
893
+    public function createRememberMeToken(IUser $user) {
894
+        $token = $this->random->generate(32);
895
+        $this->config->setUserValue($user->getUID(), 'login_token', $token, $this->timeFactory->getTime());
896
+        $this->setMagicInCookie($user->getUID(), $token);
897
+    }
898
+
899
+    /**
900
+     * logout the user from the session
901
+     */
902
+    public function logout() {
903
+        $user = $this->getUser();
904
+        $this->manager->emit('\OC\User', 'logout', [$user]);
905
+        if ($user !== null) {
906
+            try {
907
+                $this->tokenProvider->invalidateToken($this->session->getId());
908
+            } catch (SessionNotAvailableException $ex) {
909
+
910
+            }
911
+        }
912
+        $this->setUser(null);
913
+        $this->setLoginName(null);
914
+        $this->setToken(null);
915
+        $this->unsetMagicInCookie();
916
+        $this->session->clear();
917
+        $this->manager->emit('\OC\User', 'postLogout', [$user]);
918
+    }
919
+
920
+    /**
921
+     * Set cookie value to use in next page load
922
+     *
923
+     * @param string $username username to be set
924
+     * @param string $token
925
+     */
926
+    public function setMagicInCookie($username, $token) {
927
+        $secureCookie = OC::$server->getRequest()->getServerProtocol() === 'https';
928
+        $webRoot = \OC::$WEBROOT;
929
+        if ($webRoot === '') {
930
+            $webRoot = '/';
931
+        }
932
+
933
+        $maxAge = $this->config->getSystemValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15);
934
+        \OC\Http\CookieHelper::setCookie(
935
+            'nc_username',
936
+            $username,
937
+            $maxAge,
938
+            $webRoot,
939
+            '',
940
+            $secureCookie,
941
+            true,
942
+            \OC\Http\CookieHelper::SAMESITE_LAX
943
+        );
944
+        \OC\Http\CookieHelper::setCookie(
945
+            'nc_token',
946
+            $token,
947
+            $maxAge,
948
+            $webRoot,
949
+            '',
950
+            $secureCookie,
951
+            true,
952
+            \OC\Http\CookieHelper::SAMESITE_LAX
953
+        );
954
+        try {
955
+            \OC\Http\CookieHelper::setCookie(
956
+                'nc_session_id',
957
+                $this->session->getId(),
958
+                $maxAge,
959
+                $webRoot,
960
+                '',
961
+                $secureCookie,
962
+                true,
963
+                \OC\Http\CookieHelper::SAMESITE_LAX
964
+            );
965
+        } catch (SessionNotAvailableException $ex) {
966
+            // ignore
967
+        }
968
+    }
969
+
970
+    /**
971
+     * Remove cookie for "remember username"
972
+     */
973
+    public function unsetMagicInCookie() {
974
+        //TODO: DI for cookies and IRequest
975
+        $secureCookie = OC::$server->getRequest()->getServerProtocol() === 'https';
976
+
977
+        unset($_COOKIE['nc_username']); //TODO: DI
978
+        unset($_COOKIE['nc_token']);
979
+        unset($_COOKIE['nc_session_id']);
980
+        setcookie('nc_username', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT, '', $secureCookie, true);
981
+        setcookie('nc_token', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT, '', $secureCookie, true);
982
+        setcookie('nc_session_id', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT, '', $secureCookie, true);
983
+        // old cookies might be stored under /webroot/ instead of /webroot
984
+        // and Firefox doesn't like it!
985
+        setcookie('nc_username', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
986
+        setcookie('nc_token', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
987
+        setcookie('nc_session_id', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
988
+    }
989
+
990
+    /**
991
+     * Update password of the browser session token if there is one
992
+     *
993
+     * @param string $password
994
+     */
995
+    public function updateSessionTokenPassword($password) {
996
+        try {
997
+            $sessionId = $this->session->getId();
998
+            $token = $this->tokenProvider->getToken($sessionId);
999
+            $this->tokenProvider->setPassword($token, $sessionId, $password);
1000
+        } catch (SessionNotAvailableException $ex) {
1001
+            // Nothing to do
1002
+        } catch (InvalidTokenException $ex) {
1003
+            // Nothing to do
1004
+        }
1005
+    }
1006
+
1007
+    public function updateTokens(string $uid, string $password) {
1008
+        $this->tokenProvider->updatePasswords($uid, $password);
1009
+    }
1010 1010
 
1011 1011
 
1012 1012
 }
Please login to merge, or discard this patch.
lib/private/User/Manager.php 1 patch
Indentation   +578 added lines, -578 removed lines patch added patch discarded remove patch
@@ -66,582 +66,582 @@
 block discarded – undo
66 66
  * @package OC\User
67 67
  */
68 68
 class Manager extends PublicEmitter implements IUserManager {
69
-	/**
70
-	 * @var \OCP\UserInterface[] $backends
71
-	 */
72
-	private $backends = [];
73
-
74
-	/**
75
-	 * @var \OC\User\User[] $cachedUsers
76
-	 */
77
-	private $cachedUsers = [];
78
-
79
-	/** @var IConfig */
80
-	private $config;
81
-
82
-	/** @var EventDispatcherInterface */
83
-	private $dispatcher;
84
-
85
-	/** @var IEventDispatcher */
86
-	private $eventDispatcher;
87
-
88
-	public function __construct(IConfig $config,
89
-								EventDispatcherInterface $oldDispatcher,
90
-								IEventDispatcher $eventDispatcher) {
91
-		$this->config = $config;
92
-		$this->dispatcher = $oldDispatcher;
93
-		$cachedUsers = &$this->cachedUsers;
94
-		$this->listen('\OC\User', 'postDelete', function ($user) use (&$cachedUsers) {
95
-			/** @var \OC\User\User $user */
96
-			unset($cachedUsers[$user->getUID()]);
97
-		});
98
-		$this->eventDispatcher = $eventDispatcher;
99
-	}
100
-
101
-	/**
102
-	 * Get the active backends
103
-	 * @return \OCP\UserInterface[]
104
-	 */
105
-	public function getBackends() {
106
-		return $this->backends;
107
-	}
108
-
109
-	/**
110
-	 * register a user backend
111
-	 *
112
-	 * @param \OCP\UserInterface $backend
113
-	 */
114
-	public function registerBackend($backend) {
115
-		$this->backends[] = $backend;
116
-	}
117
-
118
-	/**
119
-	 * remove a user backend
120
-	 *
121
-	 * @param \OCP\UserInterface $backend
122
-	 */
123
-	public function removeBackend($backend) {
124
-		$this->cachedUsers = [];
125
-		if (($i = array_search($backend, $this->backends)) !== false) {
126
-			unset($this->backends[$i]);
127
-		}
128
-	}
129
-
130
-	/**
131
-	 * remove all user backends
132
-	 */
133
-	public function clearBackends() {
134
-		$this->cachedUsers = [];
135
-		$this->backends = [];
136
-	}
137
-
138
-	/**
139
-	 * get a user by user id
140
-	 *
141
-	 * @param string $uid
142
-	 * @return \OC\User\User|null Either the user or null if the specified user does not exist
143
-	 */
144
-	public function get($uid) {
145
-		if (is_null($uid) || $uid === '' || $uid === false) {
146
-			return null;
147
-		}
148
-		if (isset($this->cachedUsers[$uid])) { //check the cache first to prevent having to loop over the backends
149
-			return $this->cachedUsers[$uid];
150
-		}
151
-		foreach ($this->backends as $backend) {
152
-			if ($backend->userExists($uid)) {
153
-				return $this->getUserObject($uid, $backend);
154
-			}
155
-		}
156
-		return null;
157
-	}
158
-
159
-	/**
160
-	 * get or construct the user object
161
-	 *
162
-	 * @param string $uid
163
-	 * @param \OCP\UserInterface $backend
164
-	 * @param bool $cacheUser If false the newly created user object will not be cached
165
-	 * @return \OC\User\User
166
-	 */
167
-	protected function getUserObject($uid, $backend, $cacheUser = true) {
168
-		if ($backend instanceof IGetRealUIDBackend) {
169
-			$uid = $backend->getRealUID($uid);
170
-		}
171
-
172
-		if (isset($this->cachedUsers[$uid])) {
173
-			return $this->cachedUsers[$uid];
174
-		}
175
-
176
-		$user = new User($uid, $backend, $this->dispatcher, $this, $this->config);
177
-		if ($cacheUser) {
178
-			$this->cachedUsers[$uid] = $user;
179
-		}
180
-		return $user;
181
-	}
182
-
183
-	/**
184
-	 * check if a user exists
185
-	 *
186
-	 * @param string $uid
187
-	 * @return bool
188
-	 */
189
-	public function userExists($uid) {
190
-		$user = $this->get($uid);
191
-		return ($user !== null);
192
-	}
193
-
194
-	/**
195
-	 * Check if the password is valid for the user
196
-	 *
197
-	 * @param string $loginName
198
-	 * @param string $password
199
-	 * @return mixed the User object on success, false otherwise
200
-	 */
201
-	public function checkPassword($loginName, $password) {
202
-		$result = $this->checkPasswordNoLogging($loginName, $password);
203
-
204
-		if ($result === false) {
205
-			\OC::$server->getLogger()->warning('Login failed: \''. $loginName .'\' (Remote IP: \''. \OC::$server->getRequest()->getRemoteAddress(). '\')', ['app' => 'core']);
206
-		}
207
-
208
-		return $result;
209
-	}
210
-
211
-	/**
212
-	 * Check if the password is valid for the user
213
-	 *
214
-	 * @internal
215
-	 * @param string $loginName
216
-	 * @param string $password
217
-	 * @return IUser|false the User object on success, false otherwise
218
-	 */
219
-	public function checkPasswordNoLogging($loginName, $password) {
220
-		$loginName = str_replace("\0", '', $loginName);
221
-		$password = str_replace("\0", '', $password);
222
-
223
-		foreach ($this->backends as $backend) {
224
-			if ($backend->implementsActions(Backend::CHECK_PASSWORD)) {
225
-				$uid = $backend->checkPassword($loginName, $password);
226
-				if ($uid !== false) {
227
-					return $this->getUserObject($uid, $backend);
228
-				}
229
-			}
230
-		}
231
-
232
-		return false;
233
-	}
234
-
235
-	/**
236
-	 * search by user id
237
-	 *
238
-	 * @param string $pattern
239
-	 * @param int $limit
240
-	 * @param int $offset
241
-	 * @return \OC\User\User[]
242
-	 */
243
-	public function search($pattern, $limit = null, $offset = null) {
244
-		$users = [];
245
-		foreach ($this->backends as $backend) {
246
-			$backendUsers = $backend->getUsers($pattern, $limit, $offset);
247
-			if (is_array($backendUsers)) {
248
-				foreach ($backendUsers as $uid) {
249
-					$users[$uid] = $this->getUserObject($uid, $backend);
250
-				}
251
-			}
252
-		}
253
-
254
-		uasort($users, function ($a, $b) {
255
-			/**
256
-			 * @var \OC\User\User $a
257
-			 * @var \OC\User\User $b
258
-			 */
259
-			return strcasecmp($a->getUID(), $b->getUID());
260
-		});
261
-		return $users;
262
-	}
263
-
264
-	/**
265
-	 * search by displayName
266
-	 *
267
-	 * @param string $pattern
268
-	 * @param int $limit
269
-	 * @param int $offset
270
-	 * @return \OC\User\User[]
271
-	 */
272
-	public function searchDisplayName($pattern, $limit = null, $offset = null) {
273
-		$users = [];
274
-		foreach ($this->backends as $backend) {
275
-			$backendUsers = $backend->getDisplayNames($pattern, $limit, $offset);
276
-			if (is_array($backendUsers)) {
277
-				foreach ($backendUsers as $uid => $displayName) {
278
-					$users[] = $this->getUserObject($uid, $backend);
279
-				}
280
-			}
281
-		}
282
-
283
-		usort($users, function ($a, $b) {
284
-			/**
285
-			 * @var \OC\User\User $a
286
-			 * @var \OC\User\User $b
287
-			 */
288
-			return strcasecmp($a->getDisplayName(), $b->getDisplayName());
289
-		});
290
-		return $users;
291
-	}
292
-
293
-	/**
294
-	 * @param string $uid
295
-	 * @param string $password
296
-	 * @throws \InvalidArgumentException
297
-	 * @return bool|IUser the created user or false
298
-	 */
299
-	public function createUser($uid, $password) {
300
-		$localBackends = [];
301
-		foreach ($this->backends as $backend) {
302
-			if ($backend instanceof Database) {
303
-				// First check if there is another user backend
304
-				$localBackends[] = $backend;
305
-				continue;
306
-			}
307
-
308
-			if ($backend->implementsActions(Backend::CREATE_USER)) {
309
-				return $this->createUserFromBackend($uid, $password, $backend);
310
-			}
311
-		}
312
-
313
-		foreach ($localBackends as $backend) {
314
-			if ($backend->implementsActions(Backend::CREATE_USER)) {
315
-				return $this->createUserFromBackend($uid, $password, $backend);
316
-			}
317
-		}
318
-
319
-		return false;
320
-	}
321
-
322
-	/**
323
-	 * @param string $uid
324
-	 * @param string $password
325
-	 * @param UserInterface $backend
326
-	 * @return IUser|null
327
-	 * @throws \InvalidArgumentException
328
-	 */
329
-	public function createUserFromBackend($uid, $password, UserInterface $backend) {
330
-		$l = \OC::$server->getL10N('lib');
331
-
332
-		// Check the name for bad characters
333
-		// Allowed are: "a-z", "A-Z", "0-9" and "_.@-'"
334
-		if (preg_match('/[^a-zA-Z0-9 _.@\-\']/', $uid)) {
335
-			throw new \InvalidArgumentException($l->t('Only the following characters are allowed in a username:'
336
-				. ' "a-z", "A-Z", "0-9", and "_.@-\'"'));
337
-		}
338
-
339
-		// No empty username
340
-		if (trim($uid) === '') {
341
-			throw new \InvalidArgumentException($l->t('A valid username must be provided'));
342
-		}
343
-
344
-		// No whitespace at the beginning or at the end
345
-		if (trim($uid) !== $uid) {
346
-			throw new \InvalidArgumentException($l->t('Username contains whitespace at the beginning or at the end'));
347
-		}
348
-
349
-		// Username only consists of 1 or 2 dots (directory traversal)
350
-		if ($uid === '.' || $uid === '..') {
351
-			throw new \InvalidArgumentException($l->t('Username must not consist of dots only'));
352
-		}
353
-
354
-		if (!$this->verifyUid($uid)) {
355
-			throw new \InvalidArgumentException($l->t('Username is invalid because files already exist for this user'));
356
-		}
357
-
358
-		// No empty password
359
-		if (trim($password) === '') {
360
-			throw new \InvalidArgumentException($l->t('A valid password must be provided'));
361
-		}
362
-
363
-		// Check if user already exists
364
-		if ($this->userExists($uid)) {
365
-			throw new \InvalidArgumentException($l->t('The username is already being used'));
366
-		}
367
-
368
-		$this->emit('\OC\User', 'preCreateUser', [$uid, $password]);
369
-		$this->eventDispatcher->dispatchTyped(new CreateUserEvent($uid, $password));
370
-		$state = $backend->createUser($uid, $password);
371
-		if($state === false) {
372
-			throw new \InvalidArgumentException($l->t('Could not create user'));
373
-		}
374
-		$user = $this->getUserObject($uid, $backend);
375
-		if ($user instanceof IUser) {
376
-			$this->emit('\OC\User', 'postCreateUser', [$user, $password]);
377
-			$this->eventDispatcher->dispatchTyped(new UserCreatedEvent($user, $password));
378
-		}
379
-		return $user;
380
-	}
381
-
382
-	/**
383
-	 * returns how many users per backend exist (if supported by backend)
384
-	 *
385
-	 * @param boolean $hasLoggedIn when true only users that have a lastLogin
386
-	 *                entry in the preferences table will be affected
387
-	 * @return array|int an array of backend class as key and count number as value
388
-	 *                if $hasLoggedIn is true only an int is returned
389
-	 */
390
-	public function countUsers($hasLoggedIn = false) {
391
-		if ($hasLoggedIn) {
392
-			return $this->countSeenUsers();
393
-		}
394
-		$userCountStatistics = [];
395
-		foreach ($this->backends as $backend) {
396
-			if ($backend->implementsActions(Backend::COUNT_USERS)) {
397
-				$backendUsers = $backend->countUsers();
398
-				if($backendUsers !== false) {
399
-					if($backend instanceof IUserBackend) {
400
-						$name = $backend->getBackendName();
401
-					} else {
402
-						$name = get_class($backend);
403
-					}
404
-					if(isset($userCountStatistics[$name])) {
405
-						$userCountStatistics[$name] += $backendUsers;
406
-					} else {
407
-						$userCountStatistics[$name] = $backendUsers;
408
-					}
409
-				}
410
-			}
411
-		}
412
-		return $userCountStatistics;
413
-	}
414
-
415
-	/**
416
-	 * returns how many users per backend exist in the requested groups (if supported by backend)
417
-	 *
418
-	 * @param IGroup[] $groups an array of gid to search in
419
-	 * @return array|int an array of backend class as key and count number as value
420
-	 *                if $hasLoggedIn is true only an int is returned
421
-	 */
422
-	public function countUsersOfGroups(array $groups) {
423
-		$users = [];
424
-		foreach($groups as $group) {
425
-			$usersIds = array_map(function($user) {
426
-				return $user->getUID();
427
-			}, $group->getUsers());
428
-			$users = array_merge($users, $usersIds);
429
-		}
430
-		return count(array_unique($users));
431
-	}
432
-
433
-	/**
434
-	 * The callback is executed for each user on each backend.
435
-	 * If the callback returns false no further users will be retrieved.
436
-	 *
437
-	 * @param \Closure $callback
438
-	 * @param string $search
439
-	 * @param boolean $onlySeen when true only users that have a lastLogin entry
440
-	 *                in the preferences table will be affected
441
-	 * @since 9.0.0
442
-	 */
443
-	public function callForAllUsers(\Closure $callback, $search = '', $onlySeen = false) {
444
-		if ($onlySeen) {
445
-			$this->callForSeenUsers($callback);
446
-		} else {
447
-			foreach ($this->getBackends() as $backend) {
448
-				$limit = 500;
449
-				$offset = 0;
450
-				do {
451
-					$users = $backend->getUsers($search, $limit, $offset);
452
-					foreach ($users as $uid) {
453
-						if (!$backend->userExists($uid)) {
454
-							continue;
455
-						}
456
-						$user = $this->getUserObject($uid, $backend, false);
457
-						$return = $callback($user);
458
-						if ($return === false) {
459
-							break;
460
-						}
461
-					}
462
-					$offset += $limit;
463
-				} while (count($users) >= $limit);
464
-			}
465
-		}
466
-	}
467
-
468
-	/**
469
-	 * returns how many users are disabled
470
-	 *
471
-	 * @return int
472
-	 * @since 12.0.0
473
-	 */
474
-	public function countDisabledUsers(): int {
475
-		$queryBuilder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
476
-		$queryBuilder->select($queryBuilder->func()->count('*'))
477
-			->from('preferences')
478
-			->where($queryBuilder->expr()->eq('appid', $queryBuilder->createNamedParameter('core')))
479
-			->andWhere($queryBuilder->expr()->eq('configkey', $queryBuilder->createNamedParameter('enabled')))
480
-			->andWhere($queryBuilder->expr()->eq('configvalue', $queryBuilder->createNamedParameter('false'), IQueryBuilder::PARAM_STR));
481
-
482
-
483
-		$result = $queryBuilder->execute();
484
-		$count = $result->fetchColumn();
485
-		$result->closeCursor();
486
-
487
-		if ($count !== false) {
488
-			$count = (int)$count;
489
-		} else {
490
-			$count = 0;
491
-		}
492
-
493
-		return $count;
494
-	}
495
-
496
-	/**
497
-	 * returns how many users are disabled in the requested groups
498
-	 *
499
-	 * @param array $groups groupids to search
500
-	 * @return int
501
-	 * @since 14.0.0
502
-	 */
503
-	public function countDisabledUsersOfGroups(array $groups): int {
504
-		$queryBuilder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
505
-		$queryBuilder->select($queryBuilder->createFunction('COUNT(DISTINCT ' . $queryBuilder->getColumnName('uid') . ')'))
506
-			->from('preferences', 'p')
507
-			->innerJoin('p', 'group_user', 'g', $queryBuilder->expr()->eq('p.userid', 'g.uid'))
508
-			->where($queryBuilder->expr()->eq('appid', $queryBuilder->createNamedParameter('core')))
509
-			->andWhere($queryBuilder->expr()->eq('configkey', $queryBuilder->createNamedParameter('enabled')))
510
-			->andWhere($queryBuilder->expr()->eq('configvalue', $queryBuilder->createNamedParameter('false'), IQueryBuilder::PARAM_STR))
511
-			->andWhere($queryBuilder->expr()->in('gid', $queryBuilder->createNamedParameter($groups, IQueryBuilder::PARAM_STR_ARRAY)));
512
-
513
-		$result = $queryBuilder->execute();
514
-		$count = $result->fetchColumn();
515
-		$result->closeCursor();
516
-
517
-		if ($count !== false) {
518
-			$count = (int)$count;
519
-		} else {
520
-			$count = 0;
521
-		}
522
-
523
-		return $count;
524
-	}
525
-
526
-	/**
527
-	 * returns how many users have logged in once
528
-	 *
529
-	 * @return int
530
-	 * @since 11.0.0
531
-	 */
532
-	public function countSeenUsers() {
533
-		$queryBuilder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
534
-		$queryBuilder->select($queryBuilder->func()->count('*'))
535
-			->from('preferences')
536
-			->where($queryBuilder->expr()->eq('appid', $queryBuilder->createNamedParameter('login')))
537
-			->andWhere($queryBuilder->expr()->eq('configkey', $queryBuilder->createNamedParameter('lastLogin')))
538
-			->andWhere($queryBuilder->expr()->isNotNull('configvalue'));
539
-
540
-		$query = $queryBuilder->execute();
541
-
542
-		$result = (int)$query->fetchColumn();
543
-		$query->closeCursor();
544
-
545
-		return $result;
546
-	}
547
-
548
-	/**
549
-	 * @param \Closure $callback
550
-	 * @since 11.0.0
551
-	 */
552
-	public function callForSeenUsers(\Closure $callback) {
553
-		$limit = 1000;
554
-		$offset = 0;
555
-		do {
556
-			$userIds = $this->getSeenUserIds($limit, $offset);
557
-			$offset += $limit;
558
-			foreach ($userIds as $userId) {
559
-				foreach ($this->backends as $backend) {
560
-					if ($backend->userExists($userId)) {
561
-						$user = $this->getUserObject($userId, $backend, false);
562
-						$return = $callback($user);
563
-						if ($return === false) {
564
-							return;
565
-						}
566
-						break;
567
-					}
568
-				}
569
-			}
570
-		} while (count($userIds) >= $limit);
571
-	}
572
-
573
-	/**
574
-	 * Getting all userIds that have a listLogin value requires checking the
575
-	 * value in php because on oracle you cannot use a clob in a where clause,
576
-	 * preventing us from doing a not null or length(value) > 0 check.
577
-	 *
578
-	 * @param int $limit
579
-	 * @param int $offset
580
-	 * @return string[] with user ids
581
-	 */
582
-	private function getSeenUserIds($limit = null, $offset = null) {
583
-		$queryBuilder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
584
-		$queryBuilder->select(['userid'])
585
-			->from('preferences')
586
-			->where($queryBuilder->expr()->eq(
587
-				'appid', $queryBuilder->createNamedParameter('login'))
588
-			)
589
-			->andWhere($queryBuilder->expr()->eq(
590
-				'configkey', $queryBuilder->createNamedParameter('lastLogin'))
591
-			)
592
-			->andWhere($queryBuilder->expr()->isNotNull('configvalue')
593
-			);
594
-
595
-		if ($limit !== null) {
596
-			$queryBuilder->setMaxResults($limit);
597
-		}
598
-		if ($offset !== null) {
599
-			$queryBuilder->setFirstResult($offset);
600
-		}
601
-		$query = $queryBuilder->execute();
602
-		$result = [];
603
-
604
-		while ($row = $query->fetch()) {
605
-			$result[] = $row['userid'];
606
-		}
607
-
608
-		$query->closeCursor();
609
-
610
-		return $result;
611
-	}
612
-
613
-	/**
614
-	 * @param string $email
615
-	 * @return IUser[]
616
-	 * @since 9.1.0
617
-	 */
618
-	public function getByEmail($email) {
619
-		$userIds = $this->config->getUsersForUserValueCaseInsensitive('settings', 'email', $email);
620
-
621
-		$users = array_map(function($uid) {
622
-			return $this->get($uid);
623
-		}, $userIds);
624
-
625
-		return array_values(array_filter($users, function($u) {
626
-			return ($u instanceof IUser);
627
-		}));
628
-	}
629
-
630
-	private function verifyUid(string $uid): bool {
631
-		$appdata = 'appdata_' . $this->config->getSystemValueString('instanceid');
632
-
633
-		if (\in_array($uid, [
634
-			'.htaccess',
635
-			'files_external',
636
-			'.ocdata',
637
-			'owncloud.log',
638
-			'nextcloud.log',
639
-			$appdata], true)) {
640
-			return false;
641
-		}
642
-
643
-		$dataDirectory = $this->config->getSystemValueString('datadirectory', \OC::$SERVERROOT . '/data');
644
-
645
-		return !file_exists(rtrim($dataDirectory, '/') . '/' . $uid);
646
-	}
69
+    /**
70
+     * @var \OCP\UserInterface[] $backends
71
+     */
72
+    private $backends = [];
73
+
74
+    /**
75
+     * @var \OC\User\User[] $cachedUsers
76
+     */
77
+    private $cachedUsers = [];
78
+
79
+    /** @var IConfig */
80
+    private $config;
81
+
82
+    /** @var EventDispatcherInterface */
83
+    private $dispatcher;
84
+
85
+    /** @var IEventDispatcher */
86
+    private $eventDispatcher;
87
+
88
+    public function __construct(IConfig $config,
89
+                                EventDispatcherInterface $oldDispatcher,
90
+                                IEventDispatcher $eventDispatcher) {
91
+        $this->config = $config;
92
+        $this->dispatcher = $oldDispatcher;
93
+        $cachedUsers = &$this->cachedUsers;
94
+        $this->listen('\OC\User', 'postDelete', function ($user) use (&$cachedUsers) {
95
+            /** @var \OC\User\User $user */
96
+            unset($cachedUsers[$user->getUID()]);
97
+        });
98
+        $this->eventDispatcher = $eventDispatcher;
99
+    }
100
+
101
+    /**
102
+     * Get the active backends
103
+     * @return \OCP\UserInterface[]
104
+     */
105
+    public function getBackends() {
106
+        return $this->backends;
107
+    }
108
+
109
+    /**
110
+     * register a user backend
111
+     *
112
+     * @param \OCP\UserInterface $backend
113
+     */
114
+    public function registerBackend($backend) {
115
+        $this->backends[] = $backend;
116
+    }
117
+
118
+    /**
119
+     * remove a user backend
120
+     *
121
+     * @param \OCP\UserInterface $backend
122
+     */
123
+    public function removeBackend($backend) {
124
+        $this->cachedUsers = [];
125
+        if (($i = array_search($backend, $this->backends)) !== false) {
126
+            unset($this->backends[$i]);
127
+        }
128
+    }
129
+
130
+    /**
131
+     * remove all user backends
132
+     */
133
+    public function clearBackends() {
134
+        $this->cachedUsers = [];
135
+        $this->backends = [];
136
+    }
137
+
138
+    /**
139
+     * get a user by user id
140
+     *
141
+     * @param string $uid
142
+     * @return \OC\User\User|null Either the user or null if the specified user does not exist
143
+     */
144
+    public function get($uid) {
145
+        if (is_null($uid) || $uid === '' || $uid === false) {
146
+            return null;
147
+        }
148
+        if (isset($this->cachedUsers[$uid])) { //check the cache first to prevent having to loop over the backends
149
+            return $this->cachedUsers[$uid];
150
+        }
151
+        foreach ($this->backends as $backend) {
152
+            if ($backend->userExists($uid)) {
153
+                return $this->getUserObject($uid, $backend);
154
+            }
155
+        }
156
+        return null;
157
+    }
158
+
159
+    /**
160
+     * get or construct the user object
161
+     *
162
+     * @param string $uid
163
+     * @param \OCP\UserInterface $backend
164
+     * @param bool $cacheUser If false the newly created user object will not be cached
165
+     * @return \OC\User\User
166
+     */
167
+    protected function getUserObject($uid, $backend, $cacheUser = true) {
168
+        if ($backend instanceof IGetRealUIDBackend) {
169
+            $uid = $backend->getRealUID($uid);
170
+        }
171
+
172
+        if (isset($this->cachedUsers[$uid])) {
173
+            return $this->cachedUsers[$uid];
174
+        }
175
+
176
+        $user = new User($uid, $backend, $this->dispatcher, $this, $this->config);
177
+        if ($cacheUser) {
178
+            $this->cachedUsers[$uid] = $user;
179
+        }
180
+        return $user;
181
+    }
182
+
183
+    /**
184
+     * check if a user exists
185
+     *
186
+     * @param string $uid
187
+     * @return bool
188
+     */
189
+    public function userExists($uid) {
190
+        $user = $this->get($uid);
191
+        return ($user !== null);
192
+    }
193
+
194
+    /**
195
+     * Check if the password is valid for the user
196
+     *
197
+     * @param string $loginName
198
+     * @param string $password
199
+     * @return mixed the User object on success, false otherwise
200
+     */
201
+    public function checkPassword($loginName, $password) {
202
+        $result = $this->checkPasswordNoLogging($loginName, $password);
203
+
204
+        if ($result === false) {
205
+            \OC::$server->getLogger()->warning('Login failed: \''. $loginName .'\' (Remote IP: \''. \OC::$server->getRequest()->getRemoteAddress(). '\')', ['app' => 'core']);
206
+        }
207
+
208
+        return $result;
209
+    }
210
+
211
+    /**
212
+     * Check if the password is valid for the user
213
+     *
214
+     * @internal
215
+     * @param string $loginName
216
+     * @param string $password
217
+     * @return IUser|false the User object on success, false otherwise
218
+     */
219
+    public function checkPasswordNoLogging($loginName, $password) {
220
+        $loginName = str_replace("\0", '', $loginName);
221
+        $password = str_replace("\0", '', $password);
222
+
223
+        foreach ($this->backends as $backend) {
224
+            if ($backend->implementsActions(Backend::CHECK_PASSWORD)) {
225
+                $uid = $backend->checkPassword($loginName, $password);
226
+                if ($uid !== false) {
227
+                    return $this->getUserObject($uid, $backend);
228
+                }
229
+            }
230
+        }
231
+
232
+        return false;
233
+    }
234
+
235
+    /**
236
+     * search by user id
237
+     *
238
+     * @param string $pattern
239
+     * @param int $limit
240
+     * @param int $offset
241
+     * @return \OC\User\User[]
242
+     */
243
+    public function search($pattern, $limit = null, $offset = null) {
244
+        $users = [];
245
+        foreach ($this->backends as $backend) {
246
+            $backendUsers = $backend->getUsers($pattern, $limit, $offset);
247
+            if (is_array($backendUsers)) {
248
+                foreach ($backendUsers as $uid) {
249
+                    $users[$uid] = $this->getUserObject($uid, $backend);
250
+                }
251
+            }
252
+        }
253
+
254
+        uasort($users, function ($a, $b) {
255
+            /**
256
+             * @var \OC\User\User $a
257
+             * @var \OC\User\User $b
258
+             */
259
+            return strcasecmp($a->getUID(), $b->getUID());
260
+        });
261
+        return $users;
262
+    }
263
+
264
+    /**
265
+     * search by displayName
266
+     *
267
+     * @param string $pattern
268
+     * @param int $limit
269
+     * @param int $offset
270
+     * @return \OC\User\User[]
271
+     */
272
+    public function searchDisplayName($pattern, $limit = null, $offset = null) {
273
+        $users = [];
274
+        foreach ($this->backends as $backend) {
275
+            $backendUsers = $backend->getDisplayNames($pattern, $limit, $offset);
276
+            if (is_array($backendUsers)) {
277
+                foreach ($backendUsers as $uid => $displayName) {
278
+                    $users[] = $this->getUserObject($uid, $backend);
279
+                }
280
+            }
281
+        }
282
+
283
+        usort($users, function ($a, $b) {
284
+            /**
285
+             * @var \OC\User\User $a
286
+             * @var \OC\User\User $b
287
+             */
288
+            return strcasecmp($a->getDisplayName(), $b->getDisplayName());
289
+        });
290
+        return $users;
291
+    }
292
+
293
+    /**
294
+     * @param string $uid
295
+     * @param string $password
296
+     * @throws \InvalidArgumentException
297
+     * @return bool|IUser the created user or false
298
+     */
299
+    public function createUser($uid, $password) {
300
+        $localBackends = [];
301
+        foreach ($this->backends as $backend) {
302
+            if ($backend instanceof Database) {
303
+                // First check if there is another user backend
304
+                $localBackends[] = $backend;
305
+                continue;
306
+            }
307
+
308
+            if ($backend->implementsActions(Backend::CREATE_USER)) {
309
+                return $this->createUserFromBackend($uid, $password, $backend);
310
+            }
311
+        }
312
+
313
+        foreach ($localBackends as $backend) {
314
+            if ($backend->implementsActions(Backend::CREATE_USER)) {
315
+                return $this->createUserFromBackend($uid, $password, $backend);
316
+            }
317
+        }
318
+
319
+        return false;
320
+    }
321
+
322
+    /**
323
+     * @param string $uid
324
+     * @param string $password
325
+     * @param UserInterface $backend
326
+     * @return IUser|null
327
+     * @throws \InvalidArgumentException
328
+     */
329
+    public function createUserFromBackend($uid, $password, UserInterface $backend) {
330
+        $l = \OC::$server->getL10N('lib');
331
+
332
+        // Check the name for bad characters
333
+        // Allowed are: "a-z", "A-Z", "0-9" and "_.@-'"
334
+        if (preg_match('/[^a-zA-Z0-9 _.@\-\']/', $uid)) {
335
+            throw new \InvalidArgumentException($l->t('Only the following characters are allowed in a username:'
336
+                . ' "a-z", "A-Z", "0-9", and "_.@-\'"'));
337
+        }
338
+
339
+        // No empty username
340
+        if (trim($uid) === '') {
341
+            throw new \InvalidArgumentException($l->t('A valid username must be provided'));
342
+        }
343
+
344
+        // No whitespace at the beginning or at the end
345
+        if (trim($uid) !== $uid) {
346
+            throw new \InvalidArgumentException($l->t('Username contains whitespace at the beginning or at the end'));
347
+        }
348
+
349
+        // Username only consists of 1 or 2 dots (directory traversal)
350
+        if ($uid === '.' || $uid === '..') {
351
+            throw new \InvalidArgumentException($l->t('Username must not consist of dots only'));
352
+        }
353
+
354
+        if (!$this->verifyUid($uid)) {
355
+            throw new \InvalidArgumentException($l->t('Username is invalid because files already exist for this user'));
356
+        }
357
+
358
+        // No empty password
359
+        if (trim($password) === '') {
360
+            throw new \InvalidArgumentException($l->t('A valid password must be provided'));
361
+        }
362
+
363
+        // Check if user already exists
364
+        if ($this->userExists($uid)) {
365
+            throw new \InvalidArgumentException($l->t('The username is already being used'));
366
+        }
367
+
368
+        $this->emit('\OC\User', 'preCreateUser', [$uid, $password]);
369
+        $this->eventDispatcher->dispatchTyped(new CreateUserEvent($uid, $password));
370
+        $state = $backend->createUser($uid, $password);
371
+        if($state === false) {
372
+            throw new \InvalidArgumentException($l->t('Could not create user'));
373
+        }
374
+        $user = $this->getUserObject($uid, $backend);
375
+        if ($user instanceof IUser) {
376
+            $this->emit('\OC\User', 'postCreateUser', [$user, $password]);
377
+            $this->eventDispatcher->dispatchTyped(new UserCreatedEvent($user, $password));
378
+        }
379
+        return $user;
380
+    }
381
+
382
+    /**
383
+     * returns how many users per backend exist (if supported by backend)
384
+     *
385
+     * @param boolean $hasLoggedIn when true only users that have a lastLogin
386
+     *                entry in the preferences table will be affected
387
+     * @return array|int an array of backend class as key and count number as value
388
+     *                if $hasLoggedIn is true only an int is returned
389
+     */
390
+    public function countUsers($hasLoggedIn = false) {
391
+        if ($hasLoggedIn) {
392
+            return $this->countSeenUsers();
393
+        }
394
+        $userCountStatistics = [];
395
+        foreach ($this->backends as $backend) {
396
+            if ($backend->implementsActions(Backend::COUNT_USERS)) {
397
+                $backendUsers = $backend->countUsers();
398
+                if($backendUsers !== false) {
399
+                    if($backend instanceof IUserBackend) {
400
+                        $name = $backend->getBackendName();
401
+                    } else {
402
+                        $name = get_class($backend);
403
+                    }
404
+                    if(isset($userCountStatistics[$name])) {
405
+                        $userCountStatistics[$name] += $backendUsers;
406
+                    } else {
407
+                        $userCountStatistics[$name] = $backendUsers;
408
+                    }
409
+                }
410
+            }
411
+        }
412
+        return $userCountStatistics;
413
+    }
414
+
415
+    /**
416
+     * returns how many users per backend exist in the requested groups (if supported by backend)
417
+     *
418
+     * @param IGroup[] $groups an array of gid to search in
419
+     * @return array|int an array of backend class as key and count number as value
420
+     *                if $hasLoggedIn is true only an int is returned
421
+     */
422
+    public function countUsersOfGroups(array $groups) {
423
+        $users = [];
424
+        foreach($groups as $group) {
425
+            $usersIds = array_map(function($user) {
426
+                return $user->getUID();
427
+            }, $group->getUsers());
428
+            $users = array_merge($users, $usersIds);
429
+        }
430
+        return count(array_unique($users));
431
+    }
432
+
433
+    /**
434
+     * The callback is executed for each user on each backend.
435
+     * If the callback returns false no further users will be retrieved.
436
+     *
437
+     * @param \Closure $callback
438
+     * @param string $search
439
+     * @param boolean $onlySeen when true only users that have a lastLogin entry
440
+     *                in the preferences table will be affected
441
+     * @since 9.0.0
442
+     */
443
+    public function callForAllUsers(\Closure $callback, $search = '', $onlySeen = false) {
444
+        if ($onlySeen) {
445
+            $this->callForSeenUsers($callback);
446
+        } else {
447
+            foreach ($this->getBackends() as $backend) {
448
+                $limit = 500;
449
+                $offset = 0;
450
+                do {
451
+                    $users = $backend->getUsers($search, $limit, $offset);
452
+                    foreach ($users as $uid) {
453
+                        if (!$backend->userExists($uid)) {
454
+                            continue;
455
+                        }
456
+                        $user = $this->getUserObject($uid, $backend, false);
457
+                        $return = $callback($user);
458
+                        if ($return === false) {
459
+                            break;
460
+                        }
461
+                    }
462
+                    $offset += $limit;
463
+                } while (count($users) >= $limit);
464
+            }
465
+        }
466
+    }
467
+
468
+    /**
469
+     * returns how many users are disabled
470
+     *
471
+     * @return int
472
+     * @since 12.0.0
473
+     */
474
+    public function countDisabledUsers(): int {
475
+        $queryBuilder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
476
+        $queryBuilder->select($queryBuilder->func()->count('*'))
477
+            ->from('preferences')
478
+            ->where($queryBuilder->expr()->eq('appid', $queryBuilder->createNamedParameter('core')))
479
+            ->andWhere($queryBuilder->expr()->eq('configkey', $queryBuilder->createNamedParameter('enabled')))
480
+            ->andWhere($queryBuilder->expr()->eq('configvalue', $queryBuilder->createNamedParameter('false'), IQueryBuilder::PARAM_STR));
481
+
482
+
483
+        $result = $queryBuilder->execute();
484
+        $count = $result->fetchColumn();
485
+        $result->closeCursor();
486
+
487
+        if ($count !== false) {
488
+            $count = (int)$count;
489
+        } else {
490
+            $count = 0;
491
+        }
492
+
493
+        return $count;
494
+    }
495
+
496
+    /**
497
+     * returns how many users are disabled in the requested groups
498
+     *
499
+     * @param array $groups groupids to search
500
+     * @return int
501
+     * @since 14.0.0
502
+     */
503
+    public function countDisabledUsersOfGroups(array $groups): int {
504
+        $queryBuilder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
505
+        $queryBuilder->select($queryBuilder->createFunction('COUNT(DISTINCT ' . $queryBuilder->getColumnName('uid') . ')'))
506
+            ->from('preferences', 'p')
507
+            ->innerJoin('p', 'group_user', 'g', $queryBuilder->expr()->eq('p.userid', 'g.uid'))
508
+            ->where($queryBuilder->expr()->eq('appid', $queryBuilder->createNamedParameter('core')))
509
+            ->andWhere($queryBuilder->expr()->eq('configkey', $queryBuilder->createNamedParameter('enabled')))
510
+            ->andWhere($queryBuilder->expr()->eq('configvalue', $queryBuilder->createNamedParameter('false'), IQueryBuilder::PARAM_STR))
511
+            ->andWhere($queryBuilder->expr()->in('gid', $queryBuilder->createNamedParameter($groups, IQueryBuilder::PARAM_STR_ARRAY)));
512
+
513
+        $result = $queryBuilder->execute();
514
+        $count = $result->fetchColumn();
515
+        $result->closeCursor();
516
+
517
+        if ($count !== false) {
518
+            $count = (int)$count;
519
+        } else {
520
+            $count = 0;
521
+        }
522
+
523
+        return $count;
524
+    }
525
+
526
+    /**
527
+     * returns how many users have logged in once
528
+     *
529
+     * @return int
530
+     * @since 11.0.0
531
+     */
532
+    public function countSeenUsers() {
533
+        $queryBuilder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
534
+        $queryBuilder->select($queryBuilder->func()->count('*'))
535
+            ->from('preferences')
536
+            ->where($queryBuilder->expr()->eq('appid', $queryBuilder->createNamedParameter('login')))
537
+            ->andWhere($queryBuilder->expr()->eq('configkey', $queryBuilder->createNamedParameter('lastLogin')))
538
+            ->andWhere($queryBuilder->expr()->isNotNull('configvalue'));
539
+
540
+        $query = $queryBuilder->execute();
541
+
542
+        $result = (int)$query->fetchColumn();
543
+        $query->closeCursor();
544
+
545
+        return $result;
546
+    }
547
+
548
+    /**
549
+     * @param \Closure $callback
550
+     * @since 11.0.0
551
+     */
552
+    public function callForSeenUsers(\Closure $callback) {
553
+        $limit = 1000;
554
+        $offset = 0;
555
+        do {
556
+            $userIds = $this->getSeenUserIds($limit, $offset);
557
+            $offset += $limit;
558
+            foreach ($userIds as $userId) {
559
+                foreach ($this->backends as $backend) {
560
+                    if ($backend->userExists($userId)) {
561
+                        $user = $this->getUserObject($userId, $backend, false);
562
+                        $return = $callback($user);
563
+                        if ($return === false) {
564
+                            return;
565
+                        }
566
+                        break;
567
+                    }
568
+                }
569
+            }
570
+        } while (count($userIds) >= $limit);
571
+    }
572
+
573
+    /**
574
+     * Getting all userIds that have a listLogin value requires checking the
575
+     * value in php because on oracle you cannot use a clob in a where clause,
576
+     * preventing us from doing a not null or length(value) > 0 check.
577
+     *
578
+     * @param int $limit
579
+     * @param int $offset
580
+     * @return string[] with user ids
581
+     */
582
+    private function getSeenUserIds($limit = null, $offset = null) {
583
+        $queryBuilder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
584
+        $queryBuilder->select(['userid'])
585
+            ->from('preferences')
586
+            ->where($queryBuilder->expr()->eq(
587
+                'appid', $queryBuilder->createNamedParameter('login'))
588
+            )
589
+            ->andWhere($queryBuilder->expr()->eq(
590
+                'configkey', $queryBuilder->createNamedParameter('lastLogin'))
591
+            )
592
+            ->andWhere($queryBuilder->expr()->isNotNull('configvalue')
593
+            );
594
+
595
+        if ($limit !== null) {
596
+            $queryBuilder->setMaxResults($limit);
597
+        }
598
+        if ($offset !== null) {
599
+            $queryBuilder->setFirstResult($offset);
600
+        }
601
+        $query = $queryBuilder->execute();
602
+        $result = [];
603
+
604
+        while ($row = $query->fetch()) {
605
+            $result[] = $row['userid'];
606
+        }
607
+
608
+        $query->closeCursor();
609
+
610
+        return $result;
611
+    }
612
+
613
+    /**
614
+     * @param string $email
615
+     * @return IUser[]
616
+     * @since 9.1.0
617
+     */
618
+    public function getByEmail($email) {
619
+        $userIds = $this->config->getUsersForUserValueCaseInsensitive('settings', 'email', $email);
620
+
621
+        $users = array_map(function($uid) {
622
+            return $this->get($uid);
623
+        }, $userIds);
624
+
625
+        return array_values(array_filter($users, function($u) {
626
+            return ($u instanceof IUser);
627
+        }));
628
+    }
629
+
630
+    private function verifyUid(string $uid): bool {
631
+        $appdata = 'appdata_' . $this->config->getSystemValueString('instanceid');
632
+
633
+        if (\in_array($uid, [
634
+            '.htaccess',
635
+            'files_external',
636
+            '.ocdata',
637
+            'owncloud.log',
638
+            'nextcloud.log',
639
+            $appdata], true)) {
640
+            return false;
641
+        }
642
+
643
+        $dataDirectory = $this->config->getSystemValueString('datadirectory', \OC::$SERVERROOT . '/data');
644
+
645
+        return !file_exists(rtrim($dataDirectory, '/') . '/' . $uid);
646
+    }
647 647
 }
Please login to merge, or discard this patch.
lib/private/User/User.php 1 patch
Indentation   +427 added lines, -427 removed lines patch added patch discarded remove patch
@@ -49,431 +49,431 @@
 block discarded – undo
49 49
 use Symfony\Component\EventDispatcher\GenericEvent;
50 50
 
51 51
 class User implements IUser {
52
-	/** @var string */
53
-	private $uid;
54
-
55
-	/** @var string */
56
-	private $displayName;
57
-
58
-	/** @var UserInterface|null */
59
-	private $backend;
60
-	/** @var EventDispatcherInterface */
61
-	private $dispatcher;
62
-
63
-	/** @var bool */
64
-	private $enabled;
65
-
66
-	/** @var Emitter|Manager */
67
-	private $emitter;
68
-
69
-	/** @var string */
70
-	private $home;
71
-
72
-	/** @var int */
73
-	private $lastLogin;
74
-
75
-	/** @var \OCP\IConfig */
76
-	private $config;
77
-
78
-	/** @var IAvatarManager */
79
-	private $avatarManager;
80
-
81
-	/** @var IURLGenerator */
82
-	private $urlGenerator;
83
-
84
-	public function __construct(string $uid, ?UserInterface $backend, EventDispatcherInterface $dispatcher, $emitter = null, IConfig $config = null, $urlGenerator = null) {
85
-		$this->uid = $uid;
86
-		$this->backend = $backend;
87
-		$this->dispatcher = $dispatcher;
88
-		$this->emitter = $emitter;
89
-		if(is_null($config)) {
90
-			$config = \OC::$server->getConfig();
91
-		}
92
-		$this->config = $config;
93
-		$this->urlGenerator = $urlGenerator;
94
-		$enabled = $this->config->getUserValue($uid, 'core', 'enabled', 'true');
95
-		$this->enabled = ($enabled === 'true');
96
-		$this->lastLogin = $this->config->getUserValue($uid, 'login', 'lastLogin', 0);
97
-		if (is_null($this->urlGenerator)) {
98
-			$this->urlGenerator = \OC::$server->getURLGenerator();
99
-		}
100
-	}
101
-
102
-	/**
103
-	 * get the user id
104
-	 *
105
-	 * @return string
106
-	 */
107
-	public function getUID() {
108
-		return $this->uid;
109
-	}
110
-
111
-	/**
112
-	 * get the display name for the user, if no specific display name is set it will fallback to the user id
113
-	 *
114
-	 * @return string
115
-	 */
116
-	public function getDisplayName() {
117
-		if (!isset($this->displayName)) {
118
-			$displayName = '';
119
-			if ($this->backend && $this->backend->implementsActions(Backend::GET_DISPLAYNAME)) {
120
-				// get display name and strip whitespace from the beginning and end of it
121
-				$backendDisplayName = $this->backend->getDisplayName($this->uid);
122
-				if (is_string($backendDisplayName)) {
123
-					$displayName = trim($backendDisplayName);
124
-				}
125
-			}
126
-
127
-			if (!empty($displayName)) {
128
-				$this->displayName = $displayName;
129
-			} else {
130
-				$this->displayName = $this->uid;
131
-			}
132
-		}
133
-		return $this->displayName;
134
-	}
135
-
136
-	/**
137
-	 * set the displayname for the user
138
-	 *
139
-	 * @param string $displayName
140
-	 * @return bool
141
-	 */
142
-	public function setDisplayName($displayName) {
143
-		$displayName = trim($displayName);
144
-		$oldDisplayName = $this->getDisplayName();
145
-		if ($this->backend->implementsActions(Backend::SET_DISPLAYNAME) && !empty($displayName) && $displayName !== $oldDisplayName) {
146
-			$result = $this->backend->setDisplayName($this->uid, $displayName);
147
-			if ($result) {
148
-				$this->displayName = $displayName;
149
-				$this->triggerChange('displayName', $displayName, $oldDisplayName);
150
-			}
151
-			return $result !== false;
152
-		}
153
-		return false;
154
-	}
155
-
156
-	/**
157
-	 * set the email address of the user
158
-	 *
159
-	 * @param string|null $mailAddress
160
-	 * @return void
161
-	 * @since 9.0.0
162
-	 */
163
-	public function setEMailAddress($mailAddress) {
164
-		$oldMailAddress = $this->getEMailAddress();
165
-		if($oldMailAddress !== $mailAddress) {
166
-			if($mailAddress === '') {
167
-				$this->config->deleteUserValue($this->uid, 'settings', 'email');
168
-			} else {
169
-				$this->config->setUserValue($this->uid, 'settings', 'email', $mailAddress);
170
-			}
171
-			$this->triggerChange('eMailAddress', $mailAddress, $oldMailAddress);
172
-		}
173
-	}
174
-
175
-	/**
176
-	 * returns the timestamp of the user's last login or 0 if the user did never
177
-	 * login
178
-	 *
179
-	 * @return int
180
-	 */
181
-	public function getLastLogin() {
182
-		return $this->lastLogin;
183
-	}
184
-
185
-	/**
186
-	 * updates the timestamp of the most recent login of this user
187
-	 */
188
-	public function updateLastLoginTimestamp() {
189
-		$firstTimeLogin = ($this->lastLogin === 0);
190
-		$this->lastLogin = time();
191
-		$this->config->setUserValue(
192
-			$this->uid, 'login', 'lastLogin', $this->lastLogin);
193
-
194
-		return $firstTimeLogin;
195
-	}
196
-
197
-	/**
198
-	 * Delete the user
199
-	 *
200
-	 * @return bool
201
-	 */
202
-	public function delete() {
203
-		$this->dispatcher->dispatch(IUser::class . '::preDelete', new GenericEvent($this));
204
-		if ($this->emitter) {
205
-			$this->emitter->emit('\OC\User', 'preDelete', [$this]);
206
-		}
207
-		// get the home now because it won't return it after user deletion
208
-		$homePath = $this->getHome();
209
-		$result = $this->backend->deleteUser($this->uid);
210
-		if ($result) {
211
-
212
-			// FIXME: Feels like an hack - suggestions?
213
-
214
-			$groupManager = \OC::$server->getGroupManager();
215
-			// We have to delete the user from all groups
216
-			foreach ($groupManager->getUserGroupIds($this) as $groupId) {
217
-				$group = $groupManager->get($groupId);
218
-				if ($group) {
219
-					\OC_Hook::emit("OC_Group", "pre_removeFromGroup", ["run" => true, "uid" => $this->uid, "gid" => $groupId]);
220
-					$group->removeUser($this);
221
-					\OC_Hook::emit("OC_User", "post_removeFromGroup", ["uid" => $this->uid, "gid" => $groupId]);
222
-				}
223
-			}
224
-			// Delete the user's keys in preferences
225
-			\OC::$server->getConfig()->deleteAllUserValues($this->uid);
226
-
227
-			// Delete user files in /data/
228
-			if ($homePath !== false) {
229
-				// FIXME: this operates directly on FS, should use View instead...
230
-				// also this is not testable/mockable...
231
-				\OC_Helper::rmdirr($homePath);
232
-			}
233
-
234
-			// Delete the users entry in the storage table
235
-			Storage::remove('home::' . $this->uid);
236
-
237
-			\OC::$server->getCommentsManager()->deleteReferencesOfActor('users', $this->uid);
238
-			\OC::$server->getCommentsManager()->deleteReadMarksFromUser($this);
239
-
240
-			$notification = \OC::$server->getNotificationManager()->createNotification();
241
-			$notification->setUser($this->uid);
242
-			\OC::$server->getNotificationManager()->markProcessed($notification);
243
-
244
-			/** @var AccountManager $accountManager */
245
-			$accountManager = \OC::$server->query(AccountManager::class);
246
-			$accountManager->deleteUser($this);
247
-
248
-			$this->dispatcher->dispatch(IUser::class . '::postDelete', new GenericEvent($this));
249
-			if ($this->emitter) {
250
-				$this->emitter->emit('\OC\User', 'postDelete', [$this]);
251
-			}
252
-		}
253
-		return !($result === false);
254
-	}
255
-
256
-	/**
257
-	 * Set the password of the user
258
-	 *
259
-	 * @param string $password
260
-	 * @param string $recoveryPassword for the encryption app to reset encryption keys
261
-	 * @return bool
262
-	 */
263
-	public function setPassword($password, $recoveryPassword = null) {
264
-		$this->dispatcher->dispatch(IUser::class . '::preSetPassword', new GenericEvent($this, [
265
-			'password' => $password,
266
-			'recoveryPassword' => $recoveryPassword,
267
-		]));
268
-		if ($this->emitter) {
269
-			$this->emitter->emit('\OC\User', 'preSetPassword', [$this, $password, $recoveryPassword]);
270
-		}
271
-		if ($this->backend->implementsActions(Backend::SET_PASSWORD)) {
272
-			$result = $this->backend->setPassword($this->uid, $password);
273
-			$this->dispatcher->dispatch(IUser::class . '::postSetPassword', new GenericEvent($this, [
274
-				'password' => $password,
275
-				'recoveryPassword' => $recoveryPassword,
276
-			]));
277
-			if ($this->emitter) {
278
-				$this->emitter->emit('\OC\User', 'postSetPassword', [$this, $password, $recoveryPassword]);
279
-			}
280
-			return !($result === false);
281
-		} else {
282
-			return false;
283
-		}
284
-	}
285
-
286
-	/**
287
-	 * get the users home folder to mount
288
-	 *
289
-	 * @return string
290
-	 */
291
-	public function getHome() {
292
-		if (!$this->home) {
293
-			if ($this->backend->implementsActions(Backend::GET_HOME) and $home = $this->backend->getHome($this->uid)) {
294
-				$this->home = $home;
295
-			} elseif ($this->config) {
296
-				$this->home = $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/' . $this->uid;
297
-			} else {
298
-				$this->home = \OC::$SERVERROOT . '/data/' . $this->uid;
299
-			}
300
-		}
301
-		return $this->home;
302
-	}
303
-
304
-	/**
305
-	 * Get the name of the backend class the user is connected with
306
-	 *
307
-	 * @return string
308
-	 */
309
-	public function getBackendClassName() {
310
-		if($this->backend instanceof IUserBackend) {
311
-			return $this->backend->getBackendName();
312
-		}
313
-		return get_class($this->backend);
314
-	}
315
-
316
-	public function getBackend() {
317
-		return $this->backend;
318
-	}
319
-
320
-	/**
321
-	 * check if the backend allows the user to change his avatar on Personal page
322
-	 *
323
-	 * @return bool
324
-	 */
325
-	public function canChangeAvatar() {
326
-		if ($this->backend->implementsActions(Backend::PROVIDE_AVATAR)) {
327
-			return $this->backend->canChangeAvatar($this->uid);
328
-		}
329
-		return true;
330
-	}
331
-
332
-	/**
333
-	 * check if the backend supports changing passwords
334
-	 *
335
-	 * @return bool
336
-	 */
337
-	public function canChangePassword() {
338
-		return $this->backend->implementsActions(Backend::SET_PASSWORD);
339
-	}
340
-
341
-	/**
342
-	 * check if the backend supports changing display names
343
-	 *
344
-	 * @return bool
345
-	 */
346
-	public function canChangeDisplayName() {
347
-		if ($this->config->getSystemValue('allow_user_to_change_display_name') === false) {
348
-			return false;
349
-		}
350
-		return $this->backend->implementsActions(Backend::SET_DISPLAYNAME);
351
-	}
352
-
353
-	/**
354
-	 * check if the user is enabled
355
-	 *
356
-	 * @return bool
357
-	 */
358
-	public function isEnabled() {
359
-		return $this->enabled;
360
-	}
361
-
362
-	/**
363
-	 * set the enabled status for the user
364
-	 *
365
-	 * @param bool $enabled
366
-	 */
367
-	public function setEnabled(bool $enabled = true) {
368
-		$oldStatus = $this->isEnabled();
369
-		$this->enabled = $enabled;
370
-		if ($oldStatus !== $this->enabled) {
371
-			// TODO: First change the value, then trigger the event as done for all other properties.
372
-			$this->triggerChange('enabled', $enabled, $oldStatus);
373
-			$this->config->setUserValue($this->uid, 'core', 'enabled', $enabled ? 'true' : 'false');
374
-		}
375
-	}
376
-
377
-	/**
378
-	 * get the users email address
379
-	 *
380
-	 * @return string|null
381
-	 * @since 9.0.0
382
-	 */
383
-	public function getEMailAddress() {
384
-		return $this->config->getUserValue($this->uid, 'settings', 'email', null);
385
-	}
386
-
387
-	/**
388
-	 * get the users' quota
389
-	 *
390
-	 * @return string
391
-	 * @since 9.0.0
392
-	 */
393
-	public function getQuota() {
394
-		$quota = $this->config->getUserValue($this->uid, 'files', 'quota', 'default');
395
-		if($quota === 'default') {
396
-			$quota = $this->config->getAppValue('files', 'default_quota', 'none');
397
-		}
398
-		return $quota;
399
-	}
400
-
401
-	/**
402
-	 * set the users' quota
403
-	 *
404
-	 * @param string $quota
405
-	 * @return void
406
-	 * @since 9.0.0
407
-	 */
408
-	public function setQuota($quota) {
409
-		$oldQuota = $this->config->getUserValue($this->uid, 'files', 'quota', '');
410
-		if($quota !== 'none' and $quota !== 'default') {
411
-			$quota = OC_Helper::computerFileSize($quota);
412
-			$quota = OC_Helper::humanFileSize($quota);
413
-		}
414
-		if($quota !== $oldQuota) {
415
-			$this->config->setUserValue($this->uid, 'files', 'quota', $quota);
416
-			$this->triggerChange('quota', $quota, $oldQuota);
417
-		}
418
-	}
419
-
420
-	/**
421
-	 * get the avatar image if it exists
422
-	 *
423
-	 * @param int $size
424
-	 * @return IImage|null
425
-	 * @since 9.0.0
426
-	 */
427
-	public function getAvatarImage($size) {
428
-		// delay the initialization
429
-		if (is_null($this->avatarManager)) {
430
-			$this->avatarManager = \OC::$server->getAvatarManager();
431
-		}
432
-
433
-		$avatar = $this->avatarManager->getAvatar($this->uid);
434
-		$image = $avatar->get(-1);
435
-		if ($image) {
436
-			return $image;
437
-		}
438
-
439
-		return null;
440
-	}
441
-
442
-	/**
443
-	 * get the federation cloud id
444
-	 *
445
-	 * @return string
446
-	 * @since 9.0.0
447
-	 */
448
-	public function getCloudId() {
449
-		$uid = $this->getUID();
450
-		$server = $this->urlGenerator->getAbsoluteURL('/');
451
-		$server =  rtrim( $this->removeProtocolFromUrl($server), '/');
452
-		return \OC::$server->getCloudIdManager()->getCloudId($uid, $server)->getId();
453
-	}
454
-
455
-	/**
456
-	 * @param string $url
457
-	 * @return string
458
-	 */
459
-	private function removeProtocolFromUrl($url) {
460
-		if (strpos($url, 'https://') === 0) {
461
-			return substr($url, strlen('https://'));
462
-		} else if (strpos($url, 'http://') === 0) {
463
-			return substr($url, strlen('http://'));
464
-		}
465
-
466
-		return $url;
467
-	}
468
-
469
-	public function triggerChange($feature, $value = null, $oldValue = null) {
470
-		$this->dispatcher->dispatch(IUser::class . '::changeUser', new GenericEvent($this, [
471
-			'feature' => $feature,
472
-			'value' => $value,
473
-			'oldValue' => $oldValue,
474
-		]));
475
-		if ($this->emitter) {
476
-			$this->emitter->emit('\OC\User', 'changeUser', [$this, $feature, $value, $oldValue]);
477
-		}
478
-	}
52
+    /** @var string */
53
+    private $uid;
54
+
55
+    /** @var string */
56
+    private $displayName;
57
+
58
+    /** @var UserInterface|null */
59
+    private $backend;
60
+    /** @var EventDispatcherInterface */
61
+    private $dispatcher;
62
+
63
+    /** @var bool */
64
+    private $enabled;
65
+
66
+    /** @var Emitter|Manager */
67
+    private $emitter;
68
+
69
+    /** @var string */
70
+    private $home;
71
+
72
+    /** @var int */
73
+    private $lastLogin;
74
+
75
+    /** @var \OCP\IConfig */
76
+    private $config;
77
+
78
+    /** @var IAvatarManager */
79
+    private $avatarManager;
80
+
81
+    /** @var IURLGenerator */
82
+    private $urlGenerator;
83
+
84
+    public function __construct(string $uid, ?UserInterface $backend, EventDispatcherInterface $dispatcher, $emitter = null, IConfig $config = null, $urlGenerator = null) {
85
+        $this->uid = $uid;
86
+        $this->backend = $backend;
87
+        $this->dispatcher = $dispatcher;
88
+        $this->emitter = $emitter;
89
+        if(is_null($config)) {
90
+            $config = \OC::$server->getConfig();
91
+        }
92
+        $this->config = $config;
93
+        $this->urlGenerator = $urlGenerator;
94
+        $enabled = $this->config->getUserValue($uid, 'core', 'enabled', 'true');
95
+        $this->enabled = ($enabled === 'true');
96
+        $this->lastLogin = $this->config->getUserValue($uid, 'login', 'lastLogin', 0);
97
+        if (is_null($this->urlGenerator)) {
98
+            $this->urlGenerator = \OC::$server->getURLGenerator();
99
+        }
100
+    }
101
+
102
+    /**
103
+     * get the user id
104
+     *
105
+     * @return string
106
+     */
107
+    public function getUID() {
108
+        return $this->uid;
109
+    }
110
+
111
+    /**
112
+     * get the display name for the user, if no specific display name is set it will fallback to the user id
113
+     *
114
+     * @return string
115
+     */
116
+    public function getDisplayName() {
117
+        if (!isset($this->displayName)) {
118
+            $displayName = '';
119
+            if ($this->backend && $this->backend->implementsActions(Backend::GET_DISPLAYNAME)) {
120
+                // get display name and strip whitespace from the beginning and end of it
121
+                $backendDisplayName = $this->backend->getDisplayName($this->uid);
122
+                if (is_string($backendDisplayName)) {
123
+                    $displayName = trim($backendDisplayName);
124
+                }
125
+            }
126
+
127
+            if (!empty($displayName)) {
128
+                $this->displayName = $displayName;
129
+            } else {
130
+                $this->displayName = $this->uid;
131
+            }
132
+        }
133
+        return $this->displayName;
134
+    }
135
+
136
+    /**
137
+     * set the displayname for the user
138
+     *
139
+     * @param string $displayName
140
+     * @return bool
141
+     */
142
+    public function setDisplayName($displayName) {
143
+        $displayName = trim($displayName);
144
+        $oldDisplayName = $this->getDisplayName();
145
+        if ($this->backend->implementsActions(Backend::SET_DISPLAYNAME) && !empty($displayName) && $displayName !== $oldDisplayName) {
146
+            $result = $this->backend->setDisplayName($this->uid, $displayName);
147
+            if ($result) {
148
+                $this->displayName = $displayName;
149
+                $this->triggerChange('displayName', $displayName, $oldDisplayName);
150
+            }
151
+            return $result !== false;
152
+        }
153
+        return false;
154
+    }
155
+
156
+    /**
157
+     * set the email address of the user
158
+     *
159
+     * @param string|null $mailAddress
160
+     * @return void
161
+     * @since 9.0.0
162
+     */
163
+    public function setEMailAddress($mailAddress) {
164
+        $oldMailAddress = $this->getEMailAddress();
165
+        if($oldMailAddress !== $mailAddress) {
166
+            if($mailAddress === '') {
167
+                $this->config->deleteUserValue($this->uid, 'settings', 'email');
168
+            } else {
169
+                $this->config->setUserValue($this->uid, 'settings', 'email', $mailAddress);
170
+            }
171
+            $this->triggerChange('eMailAddress', $mailAddress, $oldMailAddress);
172
+        }
173
+    }
174
+
175
+    /**
176
+     * returns the timestamp of the user's last login or 0 if the user did never
177
+     * login
178
+     *
179
+     * @return int
180
+     */
181
+    public function getLastLogin() {
182
+        return $this->lastLogin;
183
+    }
184
+
185
+    /**
186
+     * updates the timestamp of the most recent login of this user
187
+     */
188
+    public function updateLastLoginTimestamp() {
189
+        $firstTimeLogin = ($this->lastLogin === 0);
190
+        $this->lastLogin = time();
191
+        $this->config->setUserValue(
192
+            $this->uid, 'login', 'lastLogin', $this->lastLogin);
193
+
194
+        return $firstTimeLogin;
195
+    }
196
+
197
+    /**
198
+     * Delete the user
199
+     *
200
+     * @return bool
201
+     */
202
+    public function delete() {
203
+        $this->dispatcher->dispatch(IUser::class . '::preDelete', new GenericEvent($this));
204
+        if ($this->emitter) {
205
+            $this->emitter->emit('\OC\User', 'preDelete', [$this]);
206
+        }
207
+        // get the home now because it won't return it after user deletion
208
+        $homePath = $this->getHome();
209
+        $result = $this->backend->deleteUser($this->uid);
210
+        if ($result) {
211
+
212
+            // FIXME: Feels like an hack - suggestions?
213
+
214
+            $groupManager = \OC::$server->getGroupManager();
215
+            // We have to delete the user from all groups
216
+            foreach ($groupManager->getUserGroupIds($this) as $groupId) {
217
+                $group = $groupManager->get($groupId);
218
+                if ($group) {
219
+                    \OC_Hook::emit("OC_Group", "pre_removeFromGroup", ["run" => true, "uid" => $this->uid, "gid" => $groupId]);
220
+                    $group->removeUser($this);
221
+                    \OC_Hook::emit("OC_User", "post_removeFromGroup", ["uid" => $this->uid, "gid" => $groupId]);
222
+                }
223
+            }
224
+            // Delete the user's keys in preferences
225
+            \OC::$server->getConfig()->deleteAllUserValues($this->uid);
226
+
227
+            // Delete user files in /data/
228
+            if ($homePath !== false) {
229
+                // FIXME: this operates directly on FS, should use View instead...
230
+                // also this is not testable/mockable...
231
+                \OC_Helper::rmdirr($homePath);
232
+            }
233
+
234
+            // Delete the users entry in the storage table
235
+            Storage::remove('home::' . $this->uid);
236
+
237
+            \OC::$server->getCommentsManager()->deleteReferencesOfActor('users', $this->uid);
238
+            \OC::$server->getCommentsManager()->deleteReadMarksFromUser($this);
239
+
240
+            $notification = \OC::$server->getNotificationManager()->createNotification();
241
+            $notification->setUser($this->uid);
242
+            \OC::$server->getNotificationManager()->markProcessed($notification);
243
+
244
+            /** @var AccountManager $accountManager */
245
+            $accountManager = \OC::$server->query(AccountManager::class);
246
+            $accountManager->deleteUser($this);
247
+
248
+            $this->dispatcher->dispatch(IUser::class . '::postDelete', new GenericEvent($this));
249
+            if ($this->emitter) {
250
+                $this->emitter->emit('\OC\User', 'postDelete', [$this]);
251
+            }
252
+        }
253
+        return !($result === false);
254
+    }
255
+
256
+    /**
257
+     * Set the password of the user
258
+     *
259
+     * @param string $password
260
+     * @param string $recoveryPassword for the encryption app to reset encryption keys
261
+     * @return bool
262
+     */
263
+    public function setPassword($password, $recoveryPassword = null) {
264
+        $this->dispatcher->dispatch(IUser::class . '::preSetPassword', new GenericEvent($this, [
265
+            'password' => $password,
266
+            'recoveryPassword' => $recoveryPassword,
267
+        ]));
268
+        if ($this->emitter) {
269
+            $this->emitter->emit('\OC\User', 'preSetPassword', [$this, $password, $recoveryPassword]);
270
+        }
271
+        if ($this->backend->implementsActions(Backend::SET_PASSWORD)) {
272
+            $result = $this->backend->setPassword($this->uid, $password);
273
+            $this->dispatcher->dispatch(IUser::class . '::postSetPassword', new GenericEvent($this, [
274
+                'password' => $password,
275
+                'recoveryPassword' => $recoveryPassword,
276
+            ]));
277
+            if ($this->emitter) {
278
+                $this->emitter->emit('\OC\User', 'postSetPassword', [$this, $password, $recoveryPassword]);
279
+            }
280
+            return !($result === false);
281
+        } else {
282
+            return false;
283
+        }
284
+    }
285
+
286
+    /**
287
+     * get the users home folder to mount
288
+     *
289
+     * @return string
290
+     */
291
+    public function getHome() {
292
+        if (!$this->home) {
293
+            if ($this->backend->implementsActions(Backend::GET_HOME) and $home = $this->backend->getHome($this->uid)) {
294
+                $this->home = $home;
295
+            } elseif ($this->config) {
296
+                $this->home = $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/' . $this->uid;
297
+            } else {
298
+                $this->home = \OC::$SERVERROOT . '/data/' . $this->uid;
299
+            }
300
+        }
301
+        return $this->home;
302
+    }
303
+
304
+    /**
305
+     * Get the name of the backend class the user is connected with
306
+     *
307
+     * @return string
308
+     */
309
+    public function getBackendClassName() {
310
+        if($this->backend instanceof IUserBackend) {
311
+            return $this->backend->getBackendName();
312
+        }
313
+        return get_class($this->backend);
314
+    }
315
+
316
+    public function getBackend() {
317
+        return $this->backend;
318
+    }
319
+
320
+    /**
321
+     * check if the backend allows the user to change his avatar on Personal page
322
+     *
323
+     * @return bool
324
+     */
325
+    public function canChangeAvatar() {
326
+        if ($this->backend->implementsActions(Backend::PROVIDE_AVATAR)) {
327
+            return $this->backend->canChangeAvatar($this->uid);
328
+        }
329
+        return true;
330
+    }
331
+
332
+    /**
333
+     * check if the backend supports changing passwords
334
+     *
335
+     * @return bool
336
+     */
337
+    public function canChangePassword() {
338
+        return $this->backend->implementsActions(Backend::SET_PASSWORD);
339
+    }
340
+
341
+    /**
342
+     * check if the backend supports changing display names
343
+     *
344
+     * @return bool
345
+     */
346
+    public function canChangeDisplayName() {
347
+        if ($this->config->getSystemValue('allow_user_to_change_display_name') === false) {
348
+            return false;
349
+        }
350
+        return $this->backend->implementsActions(Backend::SET_DISPLAYNAME);
351
+    }
352
+
353
+    /**
354
+     * check if the user is enabled
355
+     *
356
+     * @return bool
357
+     */
358
+    public function isEnabled() {
359
+        return $this->enabled;
360
+    }
361
+
362
+    /**
363
+     * set the enabled status for the user
364
+     *
365
+     * @param bool $enabled
366
+     */
367
+    public function setEnabled(bool $enabled = true) {
368
+        $oldStatus = $this->isEnabled();
369
+        $this->enabled = $enabled;
370
+        if ($oldStatus !== $this->enabled) {
371
+            // TODO: First change the value, then trigger the event as done for all other properties.
372
+            $this->triggerChange('enabled', $enabled, $oldStatus);
373
+            $this->config->setUserValue($this->uid, 'core', 'enabled', $enabled ? 'true' : 'false');
374
+        }
375
+    }
376
+
377
+    /**
378
+     * get the users email address
379
+     *
380
+     * @return string|null
381
+     * @since 9.0.0
382
+     */
383
+    public function getEMailAddress() {
384
+        return $this->config->getUserValue($this->uid, 'settings', 'email', null);
385
+    }
386
+
387
+    /**
388
+     * get the users' quota
389
+     *
390
+     * @return string
391
+     * @since 9.0.0
392
+     */
393
+    public function getQuota() {
394
+        $quota = $this->config->getUserValue($this->uid, 'files', 'quota', 'default');
395
+        if($quota === 'default') {
396
+            $quota = $this->config->getAppValue('files', 'default_quota', 'none');
397
+        }
398
+        return $quota;
399
+    }
400
+
401
+    /**
402
+     * set the users' quota
403
+     *
404
+     * @param string $quota
405
+     * @return void
406
+     * @since 9.0.0
407
+     */
408
+    public function setQuota($quota) {
409
+        $oldQuota = $this->config->getUserValue($this->uid, 'files', 'quota', '');
410
+        if($quota !== 'none' and $quota !== 'default') {
411
+            $quota = OC_Helper::computerFileSize($quota);
412
+            $quota = OC_Helper::humanFileSize($quota);
413
+        }
414
+        if($quota !== $oldQuota) {
415
+            $this->config->setUserValue($this->uid, 'files', 'quota', $quota);
416
+            $this->triggerChange('quota', $quota, $oldQuota);
417
+        }
418
+    }
419
+
420
+    /**
421
+     * get the avatar image if it exists
422
+     *
423
+     * @param int $size
424
+     * @return IImage|null
425
+     * @since 9.0.0
426
+     */
427
+    public function getAvatarImage($size) {
428
+        // delay the initialization
429
+        if (is_null($this->avatarManager)) {
430
+            $this->avatarManager = \OC::$server->getAvatarManager();
431
+        }
432
+
433
+        $avatar = $this->avatarManager->getAvatar($this->uid);
434
+        $image = $avatar->get(-1);
435
+        if ($image) {
436
+            return $image;
437
+        }
438
+
439
+        return null;
440
+    }
441
+
442
+    /**
443
+     * get the federation cloud id
444
+     *
445
+     * @return string
446
+     * @since 9.0.0
447
+     */
448
+    public function getCloudId() {
449
+        $uid = $this->getUID();
450
+        $server = $this->urlGenerator->getAbsoluteURL('/');
451
+        $server =  rtrim( $this->removeProtocolFromUrl($server), '/');
452
+        return \OC::$server->getCloudIdManager()->getCloudId($uid, $server)->getId();
453
+    }
454
+
455
+    /**
456
+     * @param string $url
457
+     * @return string
458
+     */
459
+    private function removeProtocolFromUrl($url) {
460
+        if (strpos($url, 'https://') === 0) {
461
+            return substr($url, strlen('https://'));
462
+        } else if (strpos($url, 'http://') === 0) {
463
+            return substr($url, strlen('http://'));
464
+        }
465
+
466
+        return $url;
467
+    }
468
+
469
+    public function triggerChange($feature, $value = null, $oldValue = null) {
470
+        $this->dispatcher->dispatch(IUser::class . '::changeUser', new GenericEvent($this, [
471
+            'feature' => $feature,
472
+            'value' => $value,
473
+            'oldValue' => $oldValue,
474
+        ]));
475
+        if ($this->emitter) {
476
+            $this->emitter->emit('\OC\User', 'changeUser', [$this, $feature, $value, $oldValue]);
477
+        }
478
+    }
479 479
 }
Please login to merge, or discard this patch.
lib/private/Log/ErrorHandler.php 1 patch
Indentation   +59 added lines, -59 removed lines patch added patch discarded remove patch
@@ -28,74 +28,74 @@
 block discarded – undo
28 28
 use OCP\ILogger;
29 29
 
30 30
 class ErrorHandler {
31
-	/** @var ILogger */
32
-	private static $logger;
31
+    /** @var ILogger */
32
+    private static $logger;
33 33
 
34
-	/**
35
-	 * remove password in URLs
36
-	 * @param string $msg
37
-	 * @return string
38
-	 */
39
-	protected static function removePassword($msg) {
40
-		return preg_replace('/\/\/(.*):(.*)@/', '//xxx:xxx@', $msg);
41
-	}
34
+    /**
35
+     * remove password in URLs
36
+     * @param string $msg
37
+     * @return string
38
+     */
39
+    protected static function removePassword($msg) {
40
+        return preg_replace('/\/\/(.*):(.*)@/', '//xxx:xxx@', $msg);
41
+    }
42 42
 
43
-	public static function register($debug=false) {
44
-		$handler = new ErrorHandler();
43
+    public static function register($debug=false) {
44
+        $handler = new ErrorHandler();
45 45
 
46
-		if ($debug) {
47
-			set_error_handler([$handler, 'onAll'], E_ALL);
48
-			if (\OC::$CLI) {
49
-				set_exception_handler(['OC_Template', 'printExceptionErrorPage']);
50
-			}
51
-		} else {
52
-			set_error_handler([$handler, 'onError']);
53
-		}
54
-		register_shutdown_function([$handler, 'onShutdown']);
55
-		set_exception_handler([$handler, 'onException']);
56
-	}
46
+        if ($debug) {
47
+            set_error_handler([$handler, 'onAll'], E_ALL);
48
+            if (\OC::$CLI) {
49
+                set_exception_handler(['OC_Template', 'printExceptionErrorPage']);
50
+            }
51
+        } else {
52
+            set_error_handler([$handler, 'onError']);
53
+        }
54
+        register_shutdown_function([$handler, 'onShutdown']);
55
+        set_exception_handler([$handler, 'onException']);
56
+    }
57 57
 
58
-	public static function setLogger(ILogger $logger) {
59
-		self::$logger = $logger;
60
-	}
58
+    public static function setLogger(ILogger $logger) {
59
+        self::$logger = $logger;
60
+    }
61 61
 
62
-	//Fatal errors handler
63
-	public static function onShutdown() {
64
-		$error = error_get_last();
65
-		if($error && self::$logger) {
66
-			//ob_end_clean();
67
-			$msg = $error['message'] . ' at ' . $error['file'] . '#' . $error['line'];
68
-			self::$logger->critical(self::removePassword($msg), ['app' => 'PHP']);
69
-		}
70
-	}
62
+    //Fatal errors handler
63
+    public static function onShutdown() {
64
+        $error = error_get_last();
65
+        if($error && self::$logger) {
66
+            //ob_end_clean();
67
+            $msg = $error['message'] . ' at ' . $error['file'] . '#' . $error['line'];
68
+            self::$logger->critical(self::removePassword($msg), ['app' => 'PHP']);
69
+        }
70
+    }
71 71
 
72
-	/**
73
-	 * 	Uncaught exception handler
74
-	 *
75
-	 * @param \Exception $exception
76
-	 */
77
-	public static function onException($exception) {
78
-		$class = get_class($exception);
79
-		$msg = $exception->getMessage();
80
-		$msg = "$class: $msg at " . $exception->getFile() . '#' . $exception->getLine();
81
-		self::$logger->critical(self::removePassword($msg), ['app' => 'PHP']);
82
-	}
72
+    /**
73
+     * 	Uncaught exception handler
74
+     *
75
+     * @param \Exception $exception
76
+     */
77
+    public static function onException($exception) {
78
+        $class = get_class($exception);
79
+        $msg = $exception->getMessage();
80
+        $msg = "$class: $msg at " . $exception->getFile() . '#' . $exception->getLine();
81
+        self::$logger->critical(self::removePassword($msg), ['app' => 'PHP']);
82
+    }
83 83
 
84
-	//Recoverable errors handler
85
-	public static function onError($number, $message, $file, $line) {
86
-		if (error_reporting() === 0) {
87
-			return;
88
-		}
89
-		$msg = $message . ' at ' . $file . '#' . $line;
90
-		self::$logger->error(self::removePassword($msg), ['app' => 'PHP']);
84
+    //Recoverable errors handler
85
+    public static function onError($number, $message, $file, $line) {
86
+        if (error_reporting() === 0) {
87
+            return;
88
+        }
89
+        $msg = $message . ' at ' . $file . '#' . $line;
90
+        self::$logger->error(self::removePassword($msg), ['app' => 'PHP']);
91 91
 
92
-	}
92
+    }
93 93
 
94
-	//Recoverable handler which catch all errors, warnings and notices
95
-	public static function onAll($number, $message, $file, $line) {
96
-		$msg = $message . ' at ' . $file . '#' . $line;
97
-		self::$logger->debug(self::removePassword($msg), ['app' => 'PHP']);
94
+    //Recoverable handler which catch all errors, warnings and notices
95
+    public static function onAll($number, $message, $file, $line) {
96
+        $msg = $message . ' at ' . $file . '#' . $line;
97
+        self::$logger->debug(self::removePassword($msg), ['app' => 'PHP']);
98 98
 
99
-	}
99
+    }
100 100
 
101 101
 }
Please login to merge, or discard this patch.
lib/private/Log/File.php 1 patch
Indentation   +102 added lines, -102 removed lines patch added patch discarded remove patch
@@ -46,110 +46,110 @@
 block discarded – undo
46 46
  */
47 47
 
48 48
 class File extends LogDetails implements IWriter, IFileBased {
49
-	/** @var string */
50
-	protected $logFile;
51
-	/** @var int */
52
-	protected $logFileMode;
53
-	/** @var SystemConfig */
54
-	private $config;
49
+    /** @var string */
50
+    protected $logFile;
51
+    /** @var int */
52
+    protected $logFileMode;
53
+    /** @var SystemConfig */
54
+    private $config;
55 55
 
56
-	public function __construct(string $path, string $fallbackPath = '', SystemConfig $config) {
57
-		parent::__construct($config);
58
-		$this->logFile = $path;
59
-		if (!file_exists($this->logFile)) {
60
-			if(
61
-				(
62
-					!is_writable(dirname($this->logFile))
63
-					|| !touch($this->logFile)
64
-				)
65
-				&& $fallbackPath !== ''
66
-			) {
67
-				$this->logFile = $fallbackPath;
68
-			}
69
-		}
70
-		$this->config = $config;
71
-		$this->logFileMode = $config->getValue('logfilemode', 0640);
72
-	}
56
+    public function __construct(string $path, string $fallbackPath = '', SystemConfig $config) {
57
+        parent::__construct($config);
58
+        $this->logFile = $path;
59
+        if (!file_exists($this->logFile)) {
60
+            if(
61
+                (
62
+                    !is_writable(dirname($this->logFile))
63
+                    || !touch($this->logFile)
64
+                )
65
+                && $fallbackPath !== ''
66
+            ) {
67
+                $this->logFile = $fallbackPath;
68
+            }
69
+        }
70
+        $this->config = $config;
71
+        $this->logFileMode = $config->getValue('logfilemode', 0640);
72
+    }
73 73
 
74
-	/**
75
-	 * write a message in the log
76
-	 * @param string $app
77
-	 * @param string|array $message
78
-	 * @param int $level
79
-	 */
80
-	public function write(string $app, $message, int $level) {
81
-		$entry = $this->logDetailsAsJSON($app, $message, $level);
82
-		$handle = @fopen($this->logFile, 'a');
83
-		if ($this->logFileMode > 0 && (fileperms($this->logFile) & 0777) != $this->logFileMode) {
84
-			@chmod($this->logFile, $this->logFileMode);
85
-		}
86
-		if ($handle) {
87
-			fwrite($handle, $entry."\n");
88
-			fclose($handle);
89
-		} else {
90
-			// Fall back to error_log
91
-			error_log($entry);
92
-		}
93
-		if (php_sapi_name() === 'cli-server') {
94
-			if (!\is_string($message)) {
95
-				$message = json_encode($message);
96
-			}
97
-			error_log($message, 4);
98
-		}
99
-	}
74
+    /**
75
+     * write a message in the log
76
+     * @param string $app
77
+     * @param string|array $message
78
+     * @param int $level
79
+     */
80
+    public function write(string $app, $message, int $level) {
81
+        $entry = $this->logDetailsAsJSON($app, $message, $level);
82
+        $handle = @fopen($this->logFile, 'a');
83
+        if ($this->logFileMode > 0 && (fileperms($this->logFile) & 0777) != $this->logFileMode) {
84
+            @chmod($this->logFile, $this->logFileMode);
85
+        }
86
+        if ($handle) {
87
+            fwrite($handle, $entry."\n");
88
+            fclose($handle);
89
+        } else {
90
+            // Fall back to error_log
91
+            error_log($entry);
92
+        }
93
+        if (php_sapi_name() === 'cli-server') {
94
+            if (!\is_string($message)) {
95
+                $message = json_encode($message);
96
+            }
97
+            error_log($message, 4);
98
+        }
99
+    }
100 100
 
101
-	/**
102
-	 * get entries from the log in reverse chronological order
103
-	 * @param int $limit
104
-	 * @param int $offset
105
-	 * @return array
106
-	 */
107
-	public function getEntries(int $limit=50, int $offset=0):array {
108
-		$minLevel = $this->config->getValue("loglevel", ILogger::WARN);
109
-		$entries = [];
110
-		$handle = @fopen($this->logFile, 'rb');
111
-		if ($handle) {
112
-			fseek($handle, 0, SEEK_END);
113
-			$pos = ftell($handle);
114
-			$line = '';
115
-			$entriesCount = 0;
116
-			$lines = 0;
117
-			// Loop through each character of the file looking for new lines
118
-			while ($pos >= 0 && ($limit === null ||$entriesCount < $limit)) {
119
-				fseek($handle, $pos);
120
-				$ch = fgetc($handle);
121
-				if ($ch == "\n" || $pos == 0) {
122
-					if ($line != '') {
123
-						// Add the first character if at the start of the file,
124
-						// because it doesn't hit the else in the loop
125
-						if ($pos == 0) {
126
-							$line = $ch.$line;
127
-						}
128
-						$entry = json_decode($line);
129
-						// Add the line as an entry if it is passed the offset and is equal or above the log level
130
-						if ($entry->level >= $minLevel) {
131
-							$lines++;
132
-							if ($lines > $offset) {
133
-								$entries[] = $entry;
134
-								$entriesCount++;
135
-							}
136
-						}
137
-						$line = '';
138
-					}
139
-				} else {
140
-					$line = $ch.$line;
141
-				}
142
-				$pos--;
143
-			}
144
-			fclose($handle);
145
-		}
146
-		return $entries;
147
-	}
101
+    /**
102
+     * get entries from the log in reverse chronological order
103
+     * @param int $limit
104
+     * @param int $offset
105
+     * @return array
106
+     */
107
+    public function getEntries(int $limit=50, int $offset=0):array {
108
+        $minLevel = $this->config->getValue("loglevel", ILogger::WARN);
109
+        $entries = [];
110
+        $handle = @fopen($this->logFile, 'rb');
111
+        if ($handle) {
112
+            fseek($handle, 0, SEEK_END);
113
+            $pos = ftell($handle);
114
+            $line = '';
115
+            $entriesCount = 0;
116
+            $lines = 0;
117
+            // Loop through each character of the file looking for new lines
118
+            while ($pos >= 0 && ($limit === null ||$entriesCount < $limit)) {
119
+                fseek($handle, $pos);
120
+                $ch = fgetc($handle);
121
+                if ($ch == "\n" || $pos == 0) {
122
+                    if ($line != '') {
123
+                        // Add the first character if at the start of the file,
124
+                        // because it doesn't hit the else in the loop
125
+                        if ($pos == 0) {
126
+                            $line = $ch.$line;
127
+                        }
128
+                        $entry = json_decode($line);
129
+                        // Add the line as an entry if it is passed the offset and is equal or above the log level
130
+                        if ($entry->level >= $minLevel) {
131
+                            $lines++;
132
+                            if ($lines > $offset) {
133
+                                $entries[] = $entry;
134
+                                $entriesCount++;
135
+                            }
136
+                        }
137
+                        $line = '';
138
+                    }
139
+                } else {
140
+                    $line = $ch.$line;
141
+                }
142
+                $pos--;
143
+            }
144
+            fclose($handle);
145
+        }
146
+        return $entries;
147
+    }
148 148
 
149
-	/**
150
-	 * @return string
151
-	 */
152
-	public function getLogFilePath():string {
153
-		return $this->logFile;
154
-	}
149
+    /**
150
+     * @return string
151
+     */
152
+    public function getLogFilePath():string {
153
+        return $this->logFile;
154
+    }
155 155
 }
Please login to merge, or discard this patch.