Passed
Push — master ( f0dd71...c56a27 )
by Christoph
11:49 queued 12s
created
apps/files_sharing/lib/MountProvider.php 2 patches
Indentation   +199 added lines, -199 removed lines patch added patch discarded remove patch
@@ -39,203 +39,203 @@
 block discarded – undo
39 39
 use OCP\Share\IShare;
40 40
 
41 41
 class MountProvider implements IMountProvider {
42
-	/**
43
-	 * @var \OCP\IConfig
44
-	 */
45
-	protected $config;
46
-
47
-	/**
48
-	 * @var IManager
49
-	 */
50
-	protected $shareManager;
51
-
52
-	/**
53
-	 * @var ILogger
54
-	 */
55
-	protected $logger;
56
-
57
-	/**
58
-	 * @param \OCP\IConfig $config
59
-	 * @param IManager $shareManager
60
-	 * @param ILogger $logger
61
-	 */
62
-	public function __construct(IConfig $config, IManager $shareManager, ILogger $logger) {
63
-		$this->config = $config;
64
-		$this->shareManager = $shareManager;
65
-		$this->logger = $logger;
66
-	}
67
-
68
-
69
-	/**
70
-	 * Get all mountpoints applicable for the user and check for shares where we need to update the etags
71
-	 *
72
-	 * @param \OCP\IUser $user
73
-	 * @param \OCP\Files\Storage\IStorageFactory $storageFactory
74
-	 * @return \OCP\Files\Mount\IMountPoint[]
75
-	 */
76
-	public function getMountsForUser(IUser $user, IStorageFactory $storageFactory) {
77
-
78
-		$shares = $this->shareManager->getSharedWith($user->getUID(), \OCP\Share::SHARE_TYPE_USER, null, -1);
79
-		$shares = array_merge($shares, $this->shareManager->getSharedWith($user->getUID(), \OCP\Share::SHARE_TYPE_GROUP, null, -1));
80
-		$shares = array_merge($shares, $this->shareManager->getSharedWith($user->getUID(), \OCP\Share::SHARE_TYPE_CIRCLE, null, -1));
81
-		$shares = array_merge($shares, $this->shareManager->getSharedWith($user->getUID(), \OCP\Share::SHARE_TYPE_ROOM, null, -1));
82
-
83
-		// filter out excluded shares and group shares that includes self
84
-		$shares = array_filter($shares, function (\OCP\Share\IShare $share) use ($user) {
85
-			return $share->getPermissions() > 0 && $share->getShareOwner() !== $user->getUID();
86
-		});
87
-
88
-		$superShares = $this->buildSuperShares($shares, $user);
89
-
90
-		$mounts = [];
91
-		$view = new View('/' . $user->getUID() . '/files');
92
-		$ownerViews = [];
93
-		$sharingDisabledForUser = $this->shareManager->sharingDisabledForUser($user->getUID());
94
-		$foldersExistCache = new CappedMemoryCache();
95
-		foreach ($superShares as $share) {
96
-			try {
97
-				/** @var \OCP\Share\IShare $parentShare */
98
-				$parentShare = $share[0];
99
-
100
-				if ($parentShare->getStatus() !== IShare::STATUS_ACCEPTED &&
101
-					($parentShare->getShareType() === IShare::TYPE_GROUP ||
102
-						$parentShare->getShareType() === IShare::TYPE_USERGROUP ||
103
-						$parentShare->getShareType() === IShare::TYPE_USER)) {
104
-					continue;
105
-				}
106
-
107
-				$owner = $parentShare->getShareOwner();
108
-				if (!isset($ownerViews[$owner])) {
109
-					$ownerViews[$owner] = new View('/' . $parentShare->getShareOwner() . '/files');
110
-				}
111
-				$mount = new SharedMount(
112
-					'\OCA\Files_Sharing\SharedStorage',
113
-					$mounts,
114
-					[
115
-						'user' => $user->getUID(),
116
-						// parent share
117
-						'superShare' => $parentShare,
118
-						// children/component of the superShare
119
-						'groupedShares' => $share[1],
120
-						'ownerView' => $ownerViews[$owner],
121
-						'sharingDisabledForUser' => $sharingDisabledForUser
122
-					],
123
-					$storageFactory,
124
-					$view,
125
-					$foldersExistCache
126
-				);
127
-				$mounts[$mount->getMountPoint()] = $mount;
128
-			} catch (\Exception $e) {
129
-				$this->logger->logException($e);
130
-				$this->logger->error('Error while trying to create shared mount');
131
-			}
132
-		}
133
-
134
-		// array_filter removes the null values from the array
135
-		return array_values(array_filter($mounts));
136
-	}
137
-
138
-	/**
139
-	 * Groups shares by path (nodeId) and target path
140
-	 *
141
-	 * @param \OCP\Share\IShare[] $shares
142
-	 * @return \OCP\Share\IShare[][] array of grouped shares, each element in the
143
-	 * array is a group which itself is an array of shares
144
-	 */
145
-	private function groupShares(array $shares) {
146
-		$tmp = [];
147
-
148
-		foreach ($shares as $share) {
149
-			if (!isset($tmp[$share->getNodeId()])) {
150
-				$tmp[$share->getNodeId()] = [];
151
-			}
152
-			$tmp[$share->getNodeId()][] = $share;
153
-		}
154
-
155
-		$result = [];
156
-		// sort by stime, the super share will be based on the least recent share
157
-		foreach ($tmp as &$tmp2) {
158
-			@usort($tmp2, function ($a, $b) {
159
-				if ($a->getShareTime() <= $b->getShareTime()) {
160
-					return -1;
161
-				}
162
-				return 1;
163
-			});
164
-			$result[] = $tmp2;
165
-		}
166
-
167
-		return array_values($result);
168
-	}
169
-
170
-	/**
171
-	 * Build super shares (virtual share) by grouping them by node id and target,
172
-	 * then for each group compute the super share and return it along with the matching
173
-	 * grouped shares. The most permissive permissions are used based on the permissions
174
-	 * of all shares within the group.
175
-	 *
176
-	 * @param \OCP\Share\IShare[] $allShares
177
-	 * @param \OCP\IUser $user user
178
-	 * @return array Tuple of [superShare, groupedShares]
179
-	 */
180
-	private function buildSuperShares(array $allShares, \OCP\IUser $user) {
181
-		$result = [];
182
-
183
-		$groupedShares = $this->groupShares($allShares);
184
-
185
-		/** @var \OCP\Share\IShare[] $shares */
186
-		foreach ($groupedShares as $shares) {
187
-			if (count($shares) === 0) {
188
-				continue;
189
-			}
190
-
191
-			$superShare = $this->shareManager->newShare();
192
-
193
-			// compute super share based on first entry of the group
194
-			$superShare->setId($shares[0]->getId())
195
-				->setShareOwner($shares[0]->getShareOwner())
196
-				->setNodeId($shares[0]->getNodeId())
197
-				->setShareType($shares[0]->getShareType())
198
-				->setTarget($shares[0]->getTarget());
199
-
200
-			// use most permissive permissions
201
-			$permissions = 0;
202
-			$status = IShare::STATUS_PENDING;
203
-			foreach ($shares as $share) {
204
-				$permissions |= $share->getPermissions();
205
-				$status = max($status, $share->getStatus());
206
-
207
-				if ($share->getTarget() !== $superShare->getTarget()) {
208
-					// adjust target, for database consistency
209
-					$share->setTarget($superShare->getTarget());
210
-					try {
211
-						$this->shareManager->moveShare($share, $user->getUID());
212
-					} catch (\InvalidArgumentException $e) {
213
-						// ignore as it is not important and we don't want to
214
-						// block FS setup
215
-
216
-						// the subsequent code anyway only uses the target of the
217
-						// super share
218
-
219
-						// such issue can usually happen when dealing with
220
-						// null groups which usually appear with group backend
221
-						// caching inconsistencies
222
-						$this->logger->debug(
223
-							'Could not adjust share target for share ' . $share->getId() . ' to make it consistent: ' . $e->getMessage(),
224
-							['app' => 'files_sharing']
225
-						);
226
-					}
227
-				}
228
-				if (!is_null($share->getNodeCacheEntry())) {
229
-					$superShare->setNodeCacheEntry($share->getNodeCacheEntry());
230
-				}
231
-			}
232
-
233
-			$superShare->setPermissions($permissions)
234
-				->setStatus($status);
235
-
236
-			$result[] = [$superShare, $shares];
237
-		}
238
-
239
-		return $result;
240
-	}
42
+    /**
43
+     * @var \OCP\IConfig
44
+     */
45
+    protected $config;
46
+
47
+    /**
48
+     * @var IManager
49
+     */
50
+    protected $shareManager;
51
+
52
+    /**
53
+     * @var ILogger
54
+     */
55
+    protected $logger;
56
+
57
+    /**
58
+     * @param \OCP\IConfig $config
59
+     * @param IManager $shareManager
60
+     * @param ILogger $logger
61
+     */
62
+    public function __construct(IConfig $config, IManager $shareManager, ILogger $logger) {
63
+        $this->config = $config;
64
+        $this->shareManager = $shareManager;
65
+        $this->logger = $logger;
66
+    }
67
+
68
+
69
+    /**
70
+     * Get all mountpoints applicable for the user and check for shares where we need to update the etags
71
+     *
72
+     * @param \OCP\IUser $user
73
+     * @param \OCP\Files\Storage\IStorageFactory $storageFactory
74
+     * @return \OCP\Files\Mount\IMountPoint[]
75
+     */
76
+    public function getMountsForUser(IUser $user, IStorageFactory $storageFactory) {
77
+
78
+        $shares = $this->shareManager->getSharedWith($user->getUID(), \OCP\Share::SHARE_TYPE_USER, null, -1);
79
+        $shares = array_merge($shares, $this->shareManager->getSharedWith($user->getUID(), \OCP\Share::SHARE_TYPE_GROUP, null, -1));
80
+        $shares = array_merge($shares, $this->shareManager->getSharedWith($user->getUID(), \OCP\Share::SHARE_TYPE_CIRCLE, null, -1));
81
+        $shares = array_merge($shares, $this->shareManager->getSharedWith($user->getUID(), \OCP\Share::SHARE_TYPE_ROOM, null, -1));
82
+
83
+        // filter out excluded shares and group shares that includes self
84
+        $shares = array_filter($shares, function (\OCP\Share\IShare $share) use ($user) {
85
+            return $share->getPermissions() > 0 && $share->getShareOwner() !== $user->getUID();
86
+        });
87
+
88
+        $superShares = $this->buildSuperShares($shares, $user);
89
+
90
+        $mounts = [];
91
+        $view = new View('/' . $user->getUID() . '/files');
92
+        $ownerViews = [];
93
+        $sharingDisabledForUser = $this->shareManager->sharingDisabledForUser($user->getUID());
94
+        $foldersExistCache = new CappedMemoryCache();
95
+        foreach ($superShares as $share) {
96
+            try {
97
+                /** @var \OCP\Share\IShare $parentShare */
98
+                $parentShare = $share[0];
99
+
100
+                if ($parentShare->getStatus() !== IShare::STATUS_ACCEPTED &&
101
+                    ($parentShare->getShareType() === IShare::TYPE_GROUP ||
102
+                        $parentShare->getShareType() === IShare::TYPE_USERGROUP ||
103
+                        $parentShare->getShareType() === IShare::TYPE_USER)) {
104
+                    continue;
105
+                }
106
+
107
+                $owner = $parentShare->getShareOwner();
108
+                if (!isset($ownerViews[$owner])) {
109
+                    $ownerViews[$owner] = new View('/' . $parentShare->getShareOwner() . '/files');
110
+                }
111
+                $mount = new SharedMount(
112
+                    '\OCA\Files_Sharing\SharedStorage',
113
+                    $mounts,
114
+                    [
115
+                        'user' => $user->getUID(),
116
+                        // parent share
117
+                        'superShare' => $parentShare,
118
+                        // children/component of the superShare
119
+                        'groupedShares' => $share[1],
120
+                        'ownerView' => $ownerViews[$owner],
121
+                        'sharingDisabledForUser' => $sharingDisabledForUser
122
+                    ],
123
+                    $storageFactory,
124
+                    $view,
125
+                    $foldersExistCache
126
+                );
127
+                $mounts[$mount->getMountPoint()] = $mount;
128
+            } catch (\Exception $e) {
129
+                $this->logger->logException($e);
130
+                $this->logger->error('Error while trying to create shared mount');
131
+            }
132
+        }
133
+
134
+        // array_filter removes the null values from the array
135
+        return array_values(array_filter($mounts));
136
+    }
137
+
138
+    /**
139
+     * Groups shares by path (nodeId) and target path
140
+     *
141
+     * @param \OCP\Share\IShare[] $shares
142
+     * @return \OCP\Share\IShare[][] array of grouped shares, each element in the
143
+     * array is a group which itself is an array of shares
144
+     */
145
+    private function groupShares(array $shares) {
146
+        $tmp = [];
147
+
148
+        foreach ($shares as $share) {
149
+            if (!isset($tmp[$share->getNodeId()])) {
150
+                $tmp[$share->getNodeId()] = [];
151
+            }
152
+            $tmp[$share->getNodeId()][] = $share;
153
+        }
154
+
155
+        $result = [];
156
+        // sort by stime, the super share will be based on the least recent share
157
+        foreach ($tmp as &$tmp2) {
158
+            @usort($tmp2, function ($a, $b) {
159
+                if ($a->getShareTime() <= $b->getShareTime()) {
160
+                    return -1;
161
+                }
162
+                return 1;
163
+            });
164
+            $result[] = $tmp2;
165
+        }
166
+
167
+        return array_values($result);
168
+    }
169
+
170
+    /**
171
+     * Build super shares (virtual share) by grouping them by node id and target,
172
+     * then for each group compute the super share and return it along with the matching
173
+     * grouped shares. The most permissive permissions are used based on the permissions
174
+     * of all shares within the group.
175
+     *
176
+     * @param \OCP\Share\IShare[] $allShares
177
+     * @param \OCP\IUser $user user
178
+     * @return array Tuple of [superShare, groupedShares]
179
+     */
180
+    private function buildSuperShares(array $allShares, \OCP\IUser $user) {
181
+        $result = [];
182
+
183
+        $groupedShares = $this->groupShares($allShares);
184
+
185
+        /** @var \OCP\Share\IShare[] $shares */
186
+        foreach ($groupedShares as $shares) {
187
+            if (count($shares) === 0) {
188
+                continue;
189
+            }
190
+
191
+            $superShare = $this->shareManager->newShare();
192
+
193
+            // compute super share based on first entry of the group
194
+            $superShare->setId($shares[0]->getId())
195
+                ->setShareOwner($shares[0]->getShareOwner())
196
+                ->setNodeId($shares[0]->getNodeId())
197
+                ->setShareType($shares[0]->getShareType())
198
+                ->setTarget($shares[0]->getTarget());
199
+
200
+            // use most permissive permissions
201
+            $permissions = 0;
202
+            $status = IShare::STATUS_PENDING;
203
+            foreach ($shares as $share) {
204
+                $permissions |= $share->getPermissions();
205
+                $status = max($status, $share->getStatus());
206
+
207
+                if ($share->getTarget() !== $superShare->getTarget()) {
208
+                    // adjust target, for database consistency
209
+                    $share->setTarget($superShare->getTarget());
210
+                    try {
211
+                        $this->shareManager->moveShare($share, $user->getUID());
212
+                    } catch (\InvalidArgumentException $e) {
213
+                        // ignore as it is not important and we don't want to
214
+                        // block FS setup
215
+
216
+                        // the subsequent code anyway only uses the target of the
217
+                        // super share
218
+
219
+                        // such issue can usually happen when dealing with
220
+                        // null groups which usually appear with group backend
221
+                        // caching inconsistencies
222
+                        $this->logger->debug(
223
+                            'Could not adjust share target for share ' . $share->getId() . ' to make it consistent: ' . $e->getMessage(),
224
+                            ['app' => 'files_sharing']
225
+                        );
226
+                    }
227
+                }
228
+                if (!is_null($share->getNodeCacheEntry())) {
229
+                    $superShare->setNodeCacheEntry($share->getNodeCacheEntry());
230
+                }
231
+            }
232
+
233
+            $superShare->setPermissions($permissions)
234
+                ->setStatus($status);
235
+
236
+            $result[] = [$superShare, $shares];
237
+        }
238
+
239
+        return $result;
240
+    }
241 241
 }
Please login to merge, or discard this patch.
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -81,14 +81,14 @@  discard block
 block discarded – undo
81 81
 		$shares = array_merge($shares, $this->shareManager->getSharedWith($user->getUID(), \OCP\Share::SHARE_TYPE_ROOM, null, -1));
82 82
 
83 83
 		// filter out excluded shares and group shares that includes self
84
-		$shares = array_filter($shares, function (\OCP\Share\IShare $share) use ($user) {
84
+		$shares = array_filter($shares, function(\OCP\Share\IShare $share) use ($user) {
85 85
 			return $share->getPermissions() > 0 && $share->getShareOwner() !== $user->getUID();
86 86
 		});
87 87
 
88 88
 		$superShares = $this->buildSuperShares($shares, $user);
89 89
 
90 90
 		$mounts = [];
91
-		$view = new View('/' . $user->getUID() . '/files');
91
+		$view = new View('/'.$user->getUID().'/files');
92 92
 		$ownerViews = [];
93 93
 		$sharingDisabledForUser = $this->shareManager->sharingDisabledForUser($user->getUID());
94 94
 		$foldersExistCache = new CappedMemoryCache();
@@ -106,7 +106,7 @@  discard block
 block discarded – undo
106 106
 
107 107
 				$owner = $parentShare->getShareOwner();
108 108
 				if (!isset($ownerViews[$owner])) {
109
-					$ownerViews[$owner] = new View('/' . $parentShare->getShareOwner() . '/files');
109
+					$ownerViews[$owner] = new View('/'.$parentShare->getShareOwner().'/files');
110 110
 				}
111 111
 				$mount = new SharedMount(
112 112
 					'\OCA\Files_Sharing\SharedStorage',
@@ -155,7 +155,7 @@  discard block
 block discarded – undo
155 155
 		$result = [];
156 156
 		// sort by stime, the super share will be based on the least recent share
157 157
 		foreach ($tmp as &$tmp2) {
158
-			@usort($tmp2, function ($a, $b) {
158
+			@usort($tmp2, function($a, $b) {
159 159
 				if ($a->getShareTime() <= $b->getShareTime()) {
160 160
 					return -1;
161 161
 				}
@@ -220,7 +220,7 @@  discard block
 block discarded – undo
220 220
 						// null groups which usually appear with group backend
221 221
 						// caching inconsistencies
222 222
 						$this->logger->debug(
223
-							'Could not adjust share target for share ' . $share->getId() . ' to make it consistent: ' . $e->getMessage(),
223
+							'Could not adjust share target for share '.$share->getId().' to make it consistent: '.$e->getMessage(),
224 224
 							['app' => 'files_sharing']
225 225
 						);
226 226
 					}
Please login to merge, or discard this patch.
apps/files_sharing/lib/Collaboration/ShareRecipientSorter.php 2 patches
Indentation   +64 added lines, -64 removed lines patch added patch discarded remove patch
@@ -32,78 +32,78 @@
 block discarded – undo
32 32
 
33 33
 class ShareRecipientSorter implements ISorter {
34 34
 
35
-	/** @var IManager */
36
-	private $shareManager;
37
-	/** @var Folder */
38
-	private $rootFolder;
39
-	/** @var IUserSession */
40
-	private $userSession;
35
+    /** @var IManager */
36
+    private $shareManager;
37
+    /** @var Folder */
38
+    private $rootFolder;
39
+    /** @var IUserSession */
40
+    private $userSession;
41 41
 
42
-	public function __construct(IManager $shareManager, IRootFolder $rootFolder, IUserSession $userSession) {
43
-		$this->shareManager = $shareManager;
44
-		$this->rootFolder = $rootFolder;
45
-		$this->userSession = $userSession;
46
-	}
42
+    public function __construct(IManager $shareManager, IRootFolder $rootFolder, IUserSession $userSession) {
43
+        $this->shareManager = $shareManager;
44
+        $this->rootFolder = $rootFolder;
45
+        $this->userSession = $userSession;
46
+    }
47 47
 
48
-	public function getId() {
49
-		return 'share-recipients';
50
-	}
48
+    public function getId() {
49
+        return 'share-recipients';
50
+    }
51 51
 
52
-	public function sort(array &$sortArray, array $context) {
53
-		// let's be tolerant. Comments  uses "files" by default, other usages are often singular
54
-		if($context['itemType'] !== 'files' && $context['itemType'] !== 'file') {
55
-			return;
56
-		}
57
-		$user = $this->userSession->getUser();
58
-		if($user === null) {
59
-			return;
60
-		}
61
-		$userFolder = $this->rootFolder->getUserFolder($user->getUID());
62
-		/** @var Node[] $nodes */
63
-		$nodes = $userFolder->getById((int)$context['itemId']);
64
-		if(count($nodes) === 0) {
65
-			return;
66
-		}
67
-		$al = $this->shareManager->getAccessList($nodes[0]);
52
+    public function sort(array &$sortArray, array $context) {
53
+        // let's be tolerant. Comments  uses "files" by default, other usages are often singular
54
+        if($context['itemType'] !== 'files' && $context['itemType'] !== 'file') {
55
+            return;
56
+        }
57
+        $user = $this->userSession->getUser();
58
+        if($user === null) {
59
+            return;
60
+        }
61
+        $userFolder = $this->rootFolder->getUserFolder($user->getUID());
62
+        /** @var Node[] $nodes */
63
+        $nodes = $userFolder->getById((int)$context['itemId']);
64
+        if(count($nodes) === 0) {
65
+            return;
66
+        }
67
+        $al = $this->shareManager->getAccessList($nodes[0]);
68 68
 
69
-		foreach ($sortArray as $type => &$byType) {
70
-			if(!isset($al[$type]) || !is_array($al[$type])) {
71
-				continue;
72
-			}
69
+        foreach ($sortArray as $type => &$byType) {
70
+            if(!isset($al[$type]) || !is_array($al[$type])) {
71
+                continue;
72
+            }
73 73
 
74
-			// at least on PHP 5.6 usort turned out to be not stable. So we add
75
-			// the current index to the value and compare it on a draw
76
-			$i = 0;
77
-			$workArray = array_map(function ($element) use (&$i) {
78
-				return [$i++, $element];
79
-			}, $byType);
74
+            // at least on PHP 5.6 usort turned out to be not stable. So we add
75
+            // the current index to the value and compare it on a draw
76
+            $i = 0;
77
+            $workArray = array_map(function ($element) use (&$i) {
78
+                return [$i++, $element];
79
+            }, $byType);
80 80
 
81
-			usort($workArray, function ($a, $b) use ($al, $type) {
82
-				$result = $this->compare($a[1], $b[1], $al[$type]);
83
-				if($result === 0) {
84
-					$result = $a[0] - $b[0];
85
-				}
86
-				return $result;
87
-			});
81
+            usort($workArray, function ($a, $b) use ($al, $type) {
82
+                $result = $this->compare($a[1], $b[1], $al[$type]);
83
+                if($result === 0) {
84
+                    $result = $a[0] - $b[0];
85
+                }
86
+                return $result;
87
+            });
88 88
 
89
-			// and remove the index values again
90
-			$byType = array_column($workArray, 1);
91
-		}
92
-	}
89
+            // and remove the index values again
90
+            $byType = array_column($workArray, 1);
91
+        }
92
+    }
93 93
 
94
-	/**
95
-	 * @param array $a
96
-	 * @param array $b
97
-	 * @param array $al
98
-	 * @return int
99
-	 */
100
-	protected function compare(array $a, array $b, array $al) {
101
-		$a = $a['value']['shareWith'];
102
-		$b = $b['value']['shareWith'];
94
+    /**
95
+     * @param array $a
96
+     * @param array $b
97
+     * @param array $al
98
+     * @return int
99
+     */
100
+    protected function compare(array $a, array $b, array $al) {
101
+        $a = $a['value']['shareWith'];
102
+        $b = $b['value']['shareWith'];
103 103
 
104
-		$valueA = (int)in_array($a, $al, true);
105
-		$valueB = (int)in_array($b, $al, true);
104
+        $valueA = (int)in_array($a, $al, true);
105
+        $valueB = (int)in_array($b, $al, true);
106 106
 
107
-		return $valueB - $valueA;
108
-	}
107
+        return $valueB - $valueA;
108
+    }
109 109
 }
Please login to merge, or discard this patch.
Spacing   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -51,36 +51,36 @@  discard block
 block discarded – undo
51 51
 
52 52
 	public function sort(array &$sortArray, array $context) {
53 53
 		// let's be tolerant. Comments  uses "files" by default, other usages are often singular
54
-		if($context['itemType'] !== 'files' && $context['itemType'] !== 'file') {
54
+		if ($context['itemType'] !== 'files' && $context['itemType'] !== 'file') {
55 55
 			return;
56 56
 		}
57 57
 		$user = $this->userSession->getUser();
58
-		if($user === null) {
58
+		if ($user === null) {
59 59
 			return;
60 60
 		}
61 61
 		$userFolder = $this->rootFolder->getUserFolder($user->getUID());
62 62
 		/** @var Node[] $nodes */
63
-		$nodes = $userFolder->getById((int)$context['itemId']);
64
-		if(count($nodes) === 0) {
63
+		$nodes = $userFolder->getById((int) $context['itemId']);
64
+		if (count($nodes) === 0) {
65 65
 			return;
66 66
 		}
67 67
 		$al = $this->shareManager->getAccessList($nodes[0]);
68 68
 
69 69
 		foreach ($sortArray as $type => &$byType) {
70
-			if(!isset($al[$type]) || !is_array($al[$type])) {
70
+			if (!isset($al[$type]) || !is_array($al[$type])) {
71 71
 				continue;
72 72
 			}
73 73
 
74 74
 			// at least on PHP 5.6 usort turned out to be not stable. So we add
75 75
 			// the current index to the value and compare it on a draw
76 76
 			$i = 0;
77
-			$workArray = array_map(function ($element) use (&$i) {
77
+			$workArray = array_map(function($element) use (&$i) {
78 78
 				return [$i++, $element];
79 79
 			}, $byType);
80 80
 
81
-			usort($workArray, function ($a, $b) use ($al, $type) {
81
+			usort($workArray, function($a, $b) use ($al, $type) {
82 82
 				$result = $this->compare($a[1], $b[1], $al[$type]);
83
-				if($result === 0) {
83
+				if ($result === 0) {
84 84
 					$result = $a[0] - $b[0];
85 85
 				}
86 86
 				return $result;
@@ -101,8 +101,8 @@  discard block
 block discarded – undo
101 101
 		$a = $a['value']['shareWith'];
102 102
 		$b = $b['value']['shareWith'];
103 103
 
104
-		$valueA = (int)in_array($a, $al, true);
105
-		$valueB = (int)in_array($b, $al, true);
104
+		$valueA = (int) in_array($a, $al, true);
105
+		$valueB = (int) in_array($b, $al, true);
106 106
 
107 107
 		return $valueB - $valueA;
108 108
 	}
Please login to merge, or discard this patch.
apps/theming/lib/ThemingDefaults.php 2 patches
Indentation   +375 added lines, -375 removed lines patch added patch discarded remove patch
@@ -50,379 +50,379 @@
 block discarded – undo
50 50
 
51 51
 class ThemingDefaults extends \OC_Defaults {
52 52
 
53
-	/** @var IConfig */
54
-	private $config;
55
-	/** @var IL10N */
56
-	private $l;
57
-	/** @var ImageManager */
58
-	private $imageManager;
59
-	/** @var IURLGenerator */
60
-	private $urlGenerator;
61
-	/** @var ICacheFactory */
62
-	private $cacheFactory;
63
-	/** @var Util */
64
-	private $util;
65
-	/** @var IAppManager */
66
-	private $appManager;
67
-	/** @var INavigationManager */
68
-	private $navigationManager;
69
-
70
-	/** @var string */
71
-	private $name;
72
-	/** @var string */
73
-	private $title;
74
-	/** @var string */
75
-	private $entity;
76
-	/** @var string */
77
-	private $url;
78
-	/** @var string */
79
-	private $color;
80
-
81
-	/** @var string */
82
-	private $iTunesAppId;
83
-	/** @var string */
84
-	private $iOSClientUrl;
85
-	/** @var string */
86
-	private $AndroidClientUrl;
87
-
88
-	/**
89
-	 * ThemingDefaults constructor.
90
-	 *
91
-	 * @param IConfig $config
92
-	 * @param IL10N $l
93
-	 * @param ImageManager $imageManager
94
-	 * @param IURLGenerator $urlGenerator
95
-	 * @param ICacheFactory $cacheFactory
96
-	 * @param Util $util
97
-	 * @param IAppManager $appManager
98
-	 */
99
-	public function __construct(IConfig $config,
100
-								IL10N $l,
101
-								IURLGenerator $urlGenerator,
102
-								ICacheFactory $cacheFactory,
103
-								Util $util,
104
-								ImageManager $imageManager,
105
-								IAppManager $appManager,
106
-								INavigationManager $navigationManager
107
-	) {
108
-		parent::__construct();
109
-		$this->config = $config;
110
-		$this->l = $l;
111
-		$this->imageManager = $imageManager;
112
-		$this->urlGenerator = $urlGenerator;
113
-		$this->cacheFactory = $cacheFactory;
114
-		$this->util = $util;
115
-		$this->appManager = $appManager;
116
-		$this->navigationManager = $navigationManager;
117
-
118
-		$this->name = parent::getName();
119
-		$this->title = parent::getTitle();
120
-		$this->entity = parent::getEntity();
121
-		$this->url = parent::getBaseUrl();
122
-		$this->color = parent::getColorPrimary();
123
-		$this->iTunesAppId = parent::getiTunesAppId();
124
-		$this->iOSClientUrl = parent::getiOSClientUrl();
125
-		$this->AndroidClientUrl = parent::getAndroidClientUrl();
126
-	}
127
-
128
-	public function getName() {
129
-		return strip_tags($this->config->getAppValue('theming', 'name', $this->name));
130
-	}
131
-
132
-	public function getHTMLName() {
133
-		return $this->config->getAppValue('theming', 'name', $this->name);
134
-	}
135
-
136
-	public function getTitle() {
137
-		return strip_tags($this->config->getAppValue('theming', 'name', $this->title));
138
-	}
139
-
140
-	public function getEntity() {
141
-		return strip_tags($this->config->getAppValue('theming', 'name', $this->entity));
142
-	}
143
-
144
-	public function getBaseUrl() {
145
-		return $this->config->getAppValue('theming', 'url', $this->url);
146
-	}
147
-
148
-	public function getSlogan() {
149
-		return \OCP\Util::sanitizeHTML($this->config->getAppValue('theming', 'slogan', parent::getSlogan()));
150
-	}
151
-
152
-	public function getImprintUrl() {
153
-		return (string)$this->config->getAppValue('theming', 'imprintUrl', '');
154
-	}
155
-
156
-	public function getPrivacyUrl() {
157
-		return (string)$this->config->getAppValue('theming', 'privacyUrl', '');
158
-	}
159
-
160
-	public function getShortFooter() {
161
-		$slogan = $this->getSlogan();
162
-		$baseUrl = $this->getBaseUrl();
163
-		if ($baseUrl !== '') {
164
-			$footer = '<a href="' . $baseUrl . '" target="_blank"' .
165
-				' rel="noreferrer noopener" class="entity-name">' . $this->getEntity() . '</a>';
166
-		} else {
167
-			$footer = '<span class="entity-name">' .$this->getEntity() . '</span>';
168
-		}
169
-		$footer .= ($slogan !== '' ? ' – ' . $slogan : '');
170
-
171
-		$links = [
172
-			[
173
-				'text' => $this->l->t('Legal notice'),
174
-				'url' => (string)$this->getImprintUrl()
175
-			],
176
-			[
177
-				'text' => $this->l->t('Privacy policy'),
178
-				'url' => (string)$this->getPrivacyUrl()
179
-			],
180
-		];
181
-
182
-		$navigation = $this->navigationManager->getAll(INavigationManager::TYPE_GUEST);
183
-		$guestNavigation = array_map(function ($nav) {
184
-			return [
185
-				'text' => $nav['name'],
186
-				'url' => $nav['href']
187
-			];
188
-		}, $navigation);
189
-		$links = array_merge($links, $guestNavigation);
190
-
191
-		$legalLinks = ''; $divider = '';
192
-		foreach($links as $link) {
193
-			if($link['url'] !== ''
194
-				&& filter_var($link['url'], FILTER_VALIDATE_URL)
195
-			) {
196
-				$legalLinks .= $divider . '<a href="' . $link['url'] . '" class="legal" target="_blank"' .
197
-					' rel="noreferrer noopener">' . $link['text'] . '</a>';
198
-				$divider = ' · ';
199
-			}
200
-		}
201
-		if($legalLinks !== '' ) {
202
-			$footer .= '<br/>' . $legalLinks;
203
-		}
204
-
205
-		return $footer;
206
-	}
207
-
208
-	/**
209
-	 * Color that is used for the header as well as for mail headers
210
-	 *
211
-	 * @return string
212
-	 */
213
-	public function getColorPrimary() {
214
-		return $this->config->getAppValue('theming', 'color', $this->color);
215
-	}
216
-
217
-	/**
218
-	 * Themed logo url
219
-	 *
220
-	 * @param bool $useSvg Whether to point to the SVG image or a fallback
221
-	 * @return string
222
-	 */
223
-	public function getLogo($useSvg = true): string {
224
-		$logo = $this->config->getAppValue('theming', 'logoMime', false);
225
-
226
-		$logoExists = true;
227
-		try {
228
-			$this->imageManager->getImage('logo', $useSvg);
229
-		} catch (\Exception $e) {
230
-			$logoExists = false;
231
-		}
232
-
233
-		$cacheBusterCounter = $this->config->getAppValue('theming', 'cachebuster', '0');
234
-
235
-		if(!$logo || !$logoExists) {
236
-			if($useSvg) {
237
-				$logo = $this->urlGenerator->imagePath('core', 'logo/logo.svg');
238
-			} else {
239
-				$logo = $this->urlGenerator->imagePath('core', 'logo/logo.png');
240
-			}
241
-			return $logo . '?v=' . $cacheBusterCounter;
242
-		}
243
-
244
-		return $this->urlGenerator->linkToRoute('theming.Theming.getImage', [ 'key' => 'logo', 'useSvg' => $useSvg, 'v' => $cacheBusterCounter ]);
245
-	}
246
-
247
-	/**
248
-	 * Themed background image url
249
-	 *
250
-	 * @return string
251
-	 */
252
-	public function getBackground(): string {
253
-		return $this->imageManager->getImageUrl('background');
254
-	}
255
-
256
-	/**
257
-	 * @return string
258
-	 */
259
-	public function getiTunesAppId() {
260
-		return $this->config->getAppValue('theming', 'iTunesAppId', $this->iTunesAppId);
261
-	}
262
-
263
-	/**
264
-	 * @return string
265
-	 */
266
-	public function getiOSClientUrl() {
267
-		return $this->config->getAppValue('theming', 'iOSClientUrl', $this->iOSClientUrl);
268
-	}
269
-
270
-	/**
271
-	 * @return string
272
-	 */
273
-	public function getAndroidClientUrl() {
274
-		return $this->config->getAppValue('theming', 'AndroidClientUrl', $this->AndroidClientUrl);
275
-	}
276
-
277
-
278
-	/**
279
-	 * @return array scss variables to overwrite
280
-	 */
281
-	public function getScssVariables() {
282
-		$cache = $this->cacheFactory->createDistributed('theming-' . $this->urlGenerator->getBaseUrl());
283
-		if ($value = $cache->get('getScssVariables')) {
284
-			return $value;
285
-		}
286
-
287
-		$variables = [
288
-			'theming-cachebuster' => "'" . $this->config->getAppValue('theming', 'cachebuster', '0') . "'",
289
-			'theming-logo-mime' => "'" . $this->config->getAppValue('theming', 'logoMime') . "'",
290
-			'theming-background-mime' => "'" . $this->config->getAppValue('theming', 'backgroundMime') . "'",
291
-			'theming-logoheader-mime' => "'" . $this->config->getAppValue('theming', 'logoheaderMime') . "'",
292
-			'theming-favicon-mime' => "'" . $this->config->getAppValue('theming', 'faviconMime') . "'"
293
-		];
294
-
295
-		$variables['image-logo'] = "url('".$this->imageManager->getImageUrl('logo')."')";
296
-		$variables['image-logoheader'] = "url('".$this->imageManager->getImageUrl('logoheader')."')";
297
-		$variables['image-favicon'] = "url('".$this->imageManager->getImageUrl('favicon')."')";
298
-		$variables['image-login-background'] = "url('".$this->imageManager->getImageUrl('background')."')";
299
-		$variables['image-login-plain'] = 'false';
300
-
301
-		if ($this->config->getAppValue('theming', 'color', null) !== null) {
302
-			$variables['color-primary'] = $this->getColorPrimary();
303
-			$variables['color-primary-text'] = $this->getTextColorPrimary();
304
-			$variables['color-primary-element'] = $this->util->elementColor($this->getColorPrimary());
305
-		}
306
-
307
-		if ($this->config->getAppValue('theming', 'backgroundMime', null) === 'backgroundColor') {
308
-			$variables['image-login-plain'] = 'true';
309
-		}
310
-
311
-		$variables['has-legal-links'] = 'false';
312
-		if($this->getImprintUrl() !== '' || $this->getPrivacyUrl() !== '') {
313
-			$variables['has-legal-links'] = 'true';
314
-		}
315
-
316
-		$cache->set('getScssVariables', $variables);
317
-		return $variables;
318
-	}
319
-
320
-	/**
321
-	 * Check if the image should be replaced by the theming app
322
-	 * and return the new image location then
323
-	 *
324
-	 * @param string $app name of the app
325
-	 * @param string $image filename of the image
326
-	 * @return bool|string false if image should not replaced, otherwise the location of the image
327
-	 */
328
-	public function replaceImagePath($app, $image) {
329
-		if ($app === '' || $app === 'files_sharing') {
330
-			$app = 'core';
331
-		}
332
-		$cacheBusterValue = $this->config->getAppValue('theming', 'cachebuster', '0');
333
-
334
-		try {
335
-			$customFavicon = $this->imageManager->getImage('favicon');
336
-		} catch (NotFoundException $e) {
337
-			$customFavicon = null;
338
-		}
339
-
340
-		$route = false;
341
-		if ($image === 'favicon.ico' && ($customFavicon !== null || $this->imageManager->shouldReplaceIcons())) {
342
-			$route = $this->urlGenerator->linkToRoute('theming.Icon.getFavicon', ['app' => $app]);
343
-		}
344
-		if (($image === 'favicon-touch.png' || $image === 'favicon-fb.png') && ($customFavicon !== null || $this->imageManager->shouldReplaceIcons())) {
345
-			$route = $this->urlGenerator->linkToRoute('theming.Icon.getTouchIcon', ['app' => $app]);
346
-		}
347
-		if ($image === 'manifest.json') {
348
-			try {
349
-				$appPath = $this->appManager->getAppPath($app);
350
-				if (file_exists($appPath . '/img/manifest.json')) {
351
-					return false;
352
-				}
353
-			} catch (AppPathNotFoundException $e) {}
354
-			$route = $this->urlGenerator->linkToRoute('theming.Theming.getManifest');
355
-		}
356
-		if (strpos($image, 'filetypes/') === 0 && file_exists(\OC::$SERVERROOT . '/core/img/' . $image )) {
357
-			$route = $this->urlGenerator->linkToRoute('theming.Icon.getThemedIcon', ['app' => $app, 'image' => $image]);
358
-		}
359
-
360
-		if ($route) {
361
-			return $route . '?v=' . $cacheBusterValue;
362
-		}
363
-
364
-		return false;
365
-	}
366
-
367
-	/**
368
-	 * Increases the cache buster key
369
-	 */
370
-	private function increaseCacheBuster() {
371
-		$cacheBusterKey = $this->config->getAppValue('theming', 'cachebuster', '0');
372
-		$this->config->setAppValue('theming', 'cachebuster', (int)$cacheBusterKey+1);
373
-		$this->cacheFactory->createDistributed('theming-')->clear();
374
-		$this->cacheFactory->createDistributed('imagePath')->clear();
375
-
376
-	}
377
-
378
-	/**
379
-	 * Update setting in the database
380
-	 *
381
-	 * @param string $setting
382
-	 * @param string $value
383
-	 */
384
-	public function set($setting, $value) {
385
-		$this->config->setAppValue('theming', $setting, $value);
386
-		$this->increaseCacheBuster();
387
-	}
388
-
389
-	/**
390
-	 * Revert settings to the default value
391
-	 *
392
-	 * @param string $setting setting which should be reverted
393
-	 * @return string default value
394
-	 */
395
-	public function undo($setting) {
396
-		$this->config->deleteAppValue('theming', $setting);
397
-		$this->increaseCacheBuster();
398
-
399
-		switch ($setting) {
400
-			case 'name':
401
-				$returnValue = $this->getEntity();
402
-				break;
403
-			case 'url':
404
-				$returnValue = $this->getBaseUrl();
405
-				break;
406
-			case 'slogan':
407
-				$returnValue = $this->getSlogan();
408
-				break;
409
-			case 'color':
410
-				$returnValue = $this->getColorPrimary();
411
-				break;
412
-			default:
413
-				$returnValue = '';
414
-				break;
415
-		}
416
-
417
-		return $returnValue;
418
-	}
419
-
420
-	/**
421
-	 * Color of text in the header and primary buttons
422
-	 *
423
-	 * @return string
424
-	 */
425
-	public function getTextColorPrimary() {
426
-		return $this->util->invertTextColor($this->getColorPrimary()) ? '#000000' : '#ffffff';
427
-	}
53
+    /** @var IConfig */
54
+    private $config;
55
+    /** @var IL10N */
56
+    private $l;
57
+    /** @var ImageManager */
58
+    private $imageManager;
59
+    /** @var IURLGenerator */
60
+    private $urlGenerator;
61
+    /** @var ICacheFactory */
62
+    private $cacheFactory;
63
+    /** @var Util */
64
+    private $util;
65
+    /** @var IAppManager */
66
+    private $appManager;
67
+    /** @var INavigationManager */
68
+    private $navigationManager;
69
+
70
+    /** @var string */
71
+    private $name;
72
+    /** @var string */
73
+    private $title;
74
+    /** @var string */
75
+    private $entity;
76
+    /** @var string */
77
+    private $url;
78
+    /** @var string */
79
+    private $color;
80
+
81
+    /** @var string */
82
+    private $iTunesAppId;
83
+    /** @var string */
84
+    private $iOSClientUrl;
85
+    /** @var string */
86
+    private $AndroidClientUrl;
87
+
88
+    /**
89
+     * ThemingDefaults constructor.
90
+     *
91
+     * @param IConfig $config
92
+     * @param IL10N $l
93
+     * @param ImageManager $imageManager
94
+     * @param IURLGenerator $urlGenerator
95
+     * @param ICacheFactory $cacheFactory
96
+     * @param Util $util
97
+     * @param IAppManager $appManager
98
+     */
99
+    public function __construct(IConfig $config,
100
+                                IL10N $l,
101
+                                IURLGenerator $urlGenerator,
102
+                                ICacheFactory $cacheFactory,
103
+                                Util $util,
104
+                                ImageManager $imageManager,
105
+                                IAppManager $appManager,
106
+                                INavigationManager $navigationManager
107
+    ) {
108
+        parent::__construct();
109
+        $this->config = $config;
110
+        $this->l = $l;
111
+        $this->imageManager = $imageManager;
112
+        $this->urlGenerator = $urlGenerator;
113
+        $this->cacheFactory = $cacheFactory;
114
+        $this->util = $util;
115
+        $this->appManager = $appManager;
116
+        $this->navigationManager = $navigationManager;
117
+
118
+        $this->name = parent::getName();
119
+        $this->title = parent::getTitle();
120
+        $this->entity = parent::getEntity();
121
+        $this->url = parent::getBaseUrl();
122
+        $this->color = parent::getColorPrimary();
123
+        $this->iTunesAppId = parent::getiTunesAppId();
124
+        $this->iOSClientUrl = parent::getiOSClientUrl();
125
+        $this->AndroidClientUrl = parent::getAndroidClientUrl();
126
+    }
127
+
128
+    public function getName() {
129
+        return strip_tags($this->config->getAppValue('theming', 'name', $this->name));
130
+    }
131
+
132
+    public function getHTMLName() {
133
+        return $this->config->getAppValue('theming', 'name', $this->name);
134
+    }
135
+
136
+    public function getTitle() {
137
+        return strip_tags($this->config->getAppValue('theming', 'name', $this->title));
138
+    }
139
+
140
+    public function getEntity() {
141
+        return strip_tags($this->config->getAppValue('theming', 'name', $this->entity));
142
+    }
143
+
144
+    public function getBaseUrl() {
145
+        return $this->config->getAppValue('theming', 'url', $this->url);
146
+    }
147
+
148
+    public function getSlogan() {
149
+        return \OCP\Util::sanitizeHTML($this->config->getAppValue('theming', 'slogan', parent::getSlogan()));
150
+    }
151
+
152
+    public function getImprintUrl() {
153
+        return (string)$this->config->getAppValue('theming', 'imprintUrl', '');
154
+    }
155
+
156
+    public function getPrivacyUrl() {
157
+        return (string)$this->config->getAppValue('theming', 'privacyUrl', '');
158
+    }
159
+
160
+    public function getShortFooter() {
161
+        $slogan = $this->getSlogan();
162
+        $baseUrl = $this->getBaseUrl();
163
+        if ($baseUrl !== '') {
164
+            $footer = '<a href="' . $baseUrl . '" target="_blank"' .
165
+                ' rel="noreferrer noopener" class="entity-name">' . $this->getEntity() . '</a>';
166
+        } else {
167
+            $footer = '<span class="entity-name">' .$this->getEntity() . '</span>';
168
+        }
169
+        $footer .= ($slogan !== '' ? ' – ' . $slogan : '');
170
+
171
+        $links = [
172
+            [
173
+                'text' => $this->l->t('Legal notice'),
174
+                'url' => (string)$this->getImprintUrl()
175
+            ],
176
+            [
177
+                'text' => $this->l->t('Privacy policy'),
178
+                'url' => (string)$this->getPrivacyUrl()
179
+            ],
180
+        ];
181
+
182
+        $navigation = $this->navigationManager->getAll(INavigationManager::TYPE_GUEST);
183
+        $guestNavigation = array_map(function ($nav) {
184
+            return [
185
+                'text' => $nav['name'],
186
+                'url' => $nav['href']
187
+            ];
188
+        }, $navigation);
189
+        $links = array_merge($links, $guestNavigation);
190
+
191
+        $legalLinks = ''; $divider = '';
192
+        foreach($links as $link) {
193
+            if($link['url'] !== ''
194
+                && filter_var($link['url'], FILTER_VALIDATE_URL)
195
+            ) {
196
+                $legalLinks .= $divider . '<a href="' . $link['url'] . '" class="legal" target="_blank"' .
197
+                    ' rel="noreferrer noopener">' . $link['text'] . '</a>';
198
+                $divider = ' · ';
199
+            }
200
+        }
201
+        if($legalLinks !== '' ) {
202
+            $footer .= '<br/>' . $legalLinks;
203
+        }
204
+
205
+        return $footer;
206
+    }
207
+
208
+    /**
209
+     * Color that is used for the header as well as for mail headers
210
+     *
211
+     * @return string
212
+     */
213
+    public function getColorPrimary() {
214
+        return $this->config->getAppValue('theming', 'color', $this->color);
215
+    }
216
+
217
+    /**
218
+     * Themed logo url
219
+     *
220
+     * @param bool $useSvg Whether to point to the SVG image or a fallback
221
+     * @return string
222
+     */
223
+    public function getLogo($useSvg = true): string {
224
+        $logo = $this->config->getAppValue('theming', 'logoMime', false);
225
+
226
+        $logoExists = true;
227
+        try {
228
+            $this->imageManager->getImage('logo', $useSvg);
229
+        } catch (\Exception $e) {
230
+            $logoExists = false;
231
+        }
232
+
233
+        $cacheBusterCounter = $this->config->getAppValue('theming', 'cachebuster', '0');
234
+
235
+        if(!$logo || !$logoExists) {
236
+            if($useSvg) {
237
+                $logo = $this->urlGenerator->imagePath('core', 'logo/logo.svg');
238
+            } else {
239
+                $logo = $this->urlGenerator->imagePath('core', 'logo/logo.png');
240
+            }
241
+            return $logo . '?v=' . $cacheBusterCounter;
242
+        }
243
+
244
+        return $this->urlGenerator->linkToRoute('theming.Theming.getImage', [ 'key' => 'logo', 'useSvg' => $useSvg, 'v' => $cacheBusterCounter ]);
245
+    }
246
+
247
+    /**
248
+     * Themed background image url
249
+     *
250
+     * @return string
251
+     */
252
+    public function getBackground(): string {
253
+        return $this->imageManager->getImageUrl('background');
254
+    }
255
+
256
+    /**
257
+     * @return string
258
+     */
259
+    public function getiTunesAppId() {
260
+        return $this->config->getAppValue('theming', 'iTunesAppId', $this->iTunesAppId);
261
+    }
262
+
263
+    /**
264
+     * @return string
265
+     */
266
+    public function getiOSClientUrl() {
267
+        return $this->config->getAppValue('theming', 'iOSClientUrl', $this->iOSClientUrl);
268
+    }
269
+
270
+    /**
271
+     * @return string
272
+     */
273
+    public function getAndroidClientUrl() {
274
+        return $this->config->getAppValue('theming', 'AndroidClientUrl', $this->AndroidClientUrl);
275
+    }
276
+
277
+
278
+    /**
279
+     * @return array scss variables to overwrite
280
+     */
281
+    public function getScssVariables() {
282
+        $cache = $this->cacheFactory->createDistributed('theming-' . $this->urlGenerator->getBaseUrl());
283
+        if ($value = $cache->get('getScssVariables')) {
284
+            return $value;
285
+        }
286
+
287
+        $variables = [
288
+            'theming-cachebuster' => "'" . $this->config->getAppValue('theming', 'cachebuster', '0') . "'",
289
+            'theming-logo-mime' => "'" . $this->config->getAppValue('theming', 'logoMime') . "'",
290
+            'theming-background-mime' => "'" . $this->config->getAppValue('theming', 'backgroundMime') . "'",
291
+            'theming-logoheader-mime' => "'" . $this->config->getAppValue('theming', 'logoheaderMime') . "'",
292
+            'theming-favicon-mime' => "'" . $this->config->getAppValue('theming', 'faviconMime') . "'"
293
+        ];
294
+
295
+        $variables['image-logo'] = "url('".$this->imageManager->getImageUrl('logo')."')";
296
+        $variables['image-logoheader'] = "url('".$this->imageManager->getImageUrl('logoheader')."')";
297
+        $variables['image-favicon'] = "url('".$this->imageManager->getImageUrl('favicon')."')";
298
+        $variables['image-login-background'] = "url('".$this->imageManager->getImageUrl('background')."')";
299
+        $variables['image-login-plain'] = 'false';
300
+
301
+        if ($this->config->getAppValue('theming', 'color', null) !== null) {
302
+            $variables['color-primary'] = $this->getColorPrimary();
303
+            $variables['color-primary-text'] = $this->getTextColorPrimary();
304
+            $variables['color-primary-element'] = $this->util->elementColor($this->getColorPrimary());
305
+        }
306
+
307
+        if ($this->config->getAppValue('theming', 'backgroundMime', null) === 'backgroundColor') {
308
+            $variables['image-login-plain'] = 'true';
309
+        }
310
+
311
+        $variables['has-legal-links'] = 'false';
312
+        if($this->getImprintUrl() !== '' || $this->getPrivacyUrl() !== '') {
313
+            $variables['has-legal-links'] = 'true';
314
+        }
315
+
316
+        $cache->set('getScssVariables', $variables);
317
+        return $variables;
318
+    }
319
+
320
+    /**
321
+     * Check if the image should be replaced by the theming app
322
+     * and return the new image location then
323
+     *
324
+     * @param string $app name of the app
325
+     * @param string $image filename of the image
326
+     * @return bool|string false if image should not replaced, otherwise the location of the image
327
+     */
328
+    public function replaceImagePath($app, $image) {
329
+        if ($app === '' || $app === 'files_sharing') {
330
+            $app = 'core';
331
+        }
332
+        $cacheBusterValue = $this->config->getAppValue('theming', 'cachebuster', '0');
333
+
334
+        try {
335
+            $customFavicon = $this->imageManager->getImage('favicon');
336
+        } catch (NotFoundException $e) {
337
+            $customFavicon = null;
338
+        }
339
+
340
+        $route = false;
341
+        if ($image === 'favicon.ico' && ($customFavicon !== null || $this->imageManager->shouldReplaceIcons())) {
342
+            $route = $this->urlGenerator->linkToRoute('theming.Icon.getFavicon', ['app' => $app]);
343
+        }
344
+        if (($image === 'favicon-touch.png' || $image === 'favicon-fb.png') && ($customFavicon !== null || $this->imageManager->shouldReplaceIcons())) {
345
+            $route = $this->urlGenerator->linkToRoute('theming.Icon.getTouchIcon', ['app' => $app]);
346
+        }
347
+        if ($image === 'manifest.json') {
348
+            try {
349
+                $appPath = $this->appManager->getAppPath($app);
350
+                if (file_exists($appPath . '/img/manifest.json')) {
351
+                    return false;
352
+                }
353
+            } catch (AppPathNotFoundException $e) {}
354
+            $route = $this->urlGenerator->linkToRoute('theming.Theming.getManifest');
355
+        }
356
+        if (strpos($image, 'filetypes/') === 0 && file_exists(\OC::$SERVERROOT . '/core/img/' . $image )) {
357
+            $route = $this->urlGenerator->linkToRoute('theming.Icon.getThemedIcon', ['app' => $app, 'image' => $image]);
358
+        }
359
+
360
+        if ($route) {
361
+            return $route . '?v=' . $cacheBusterValue;
362
+        }
363
+
364
+        return false;
365
+    }
366
+
367
+    /**
368
+     * Increases the cache buster key
369
+     */
370
+    private function increaseCacheBuster() {
371
+        $cacheBusterKey = $this->config->getAppValue('theming', 'cachebuster', '0');
372
+        $this->config->setAppValue('theming', 'cachebuster', (int)$cacheBusterKey+1);
373
+        $this->cacheFactory->createDistributed('theming-')->clear();
374
+        $this->cacheFactory->createDistributed('imagePath')->clear();
375
+
376
+    }
377
+
378
+    /**
379
+     * Update setting in the database
380
+     *
381
+     * @param string $setting
382
+     * @param string $value
383
+     */
384
+    public function set($setting, $value) {
385
+        $this->config->setAppValue('theming', $setting, $value);
386
+        $this->increaseCacheBuster();
387
+    }
388
+
389
+    /**
390
+     * Revert settings to the default value
391
+     *
392
+     * @param string $setting setting which should be reverted
393
+     * @return string default value
394
+     */
395
+    public function undo($setting) {
396
+        $this->config->deleteAppValue('theming', $setting);
397
+        $this->increaseCacheBuster();
398
+
399
+        switch ($setting) {
400
+            case 'name':
401
+                $returnValue = $this->getEntity();
402
+                break;
403
+            case 'url':
404
+                $returnValue = $this->getBaseUrl();
405
+                break;
406
+            case 'slogan':
407
+                $returnValue = $this->getSlogan();
408
+                break;
409
+            case 'color':
410
+                $returnValue = $this->getColorPrimary();
411
+                break;
412
+            default:
413
+                $returnValue = '';
414
+                break;
415
+        }
416
+
417
+        return $returnValue;
418
+    }
419
+
420
+    /**
421
+     * Color of text in the header and primary buttons
422
+     *
423
+     * @return string
424
+     */
425
+    public function getTextColorPrimary() {
426
+        return $this->util->invertTextColor($this->getColorPrimary()) ? '#000000' : '#ffffff';
427
+    }
428 428
 }
Please login to merge, or discard this patch.
Spacing   +30 added lines, -30 removed lines patch added patch discarded remove patch
@@ -150,37 +150,37 @@  discard block
 block discarded – undo
150 150
 	}
151 151
 
152 152
 	public function getImprintUrl() {
153
-		return (string)$this->config->getAppValue('theming', 'imprintUrl', '');
153
+		return (string) $this->config->getAppValue('theming', 'imprintUrl', '');
154 154
 	}
155 155
 
156 156
 	public function getPrivacyUrl() {
157
-		return (string)$this->config->getAppValue('theming', 'privacyUrl', '');
157
+		return (string) $this->config->getAppValue('theming', 'privacyUrl', '');
158 158
 	}
159 159
 
160 160
 	public function getShortFooter() {
161 161
 		$slogan = $this->getSlogan();
162 162
 		$baseUrl = $this->getBaseUrl();
163 163
 		if ($baseUrl !== '') {
164
-			$footer = '<a href="' . $baseUrl . '" target="_blank"' .
165
-				' rel="noreferrer noopener" class="entity-name">' . $this->getEntity() . '</a>';
164
+			$footer = '<a href="'.$baseUrl.'" target="_blank"'.
165
+				' rel="noreferrer noopener" class="entity-name">'.$this->getEntity().'</a>';
166 166
 		} else {
167
-			$footer = '<span class="entity-name">' .$this->getEntity() . '</span>';
167
+			$footer = '<span class="entity-name">'.$this->getEntity().'</span>';
168 168
 		}
169
-		$footer .= ($slogan !== '' ? ' – ' . $slogan : '');
169
+		$footer .= ($slogan !== '' ? ' – '.$slogan : '');
170 170
 
171 171
 		$links = [
172 172
 			[
173 173
 				'text' => $this->l->t('Legal notice'),
174
-				'url' => (string)$this->getImprintUrl()
174
+				'url' => (string) $this->getImprintUrl()
175 175
 			],
176 176
 			[
177 177
 				'text' => $this->l->t('Privacy policy'),
178
-				'url' => (string)$this->getPrivacyUrl()
178
+				'url' => (string) $this->getPrivacyUrl()
179 179
 			],
180 180
 		];
181 181
 
182 182
 		$navigation = $this->navigationManager->getAll(INavigationManager::TYPE_GUEST);
183
-		$guestNavigation = array_map(function ($nav) {
183
+		$guestNavigation = array_map(function($nav) {
184 184
 			return [
185 185
 				'text' => $nav['name'],
186 186
 				'url' => $nav['href']
@@ -189,17 +189,17 @@  discard block
 block discarded – undo
189 189
 		$links = array_merge($links, $guestNavigation);
190 190
 
191 191
 		$legalLinks = ''; $divider = '';
192
-		foreach($links as $link) {
193
-			if($link['url'] !== ''
192
+		foreach ($links as $link) {
193
+			if ($link['url'] !== ''
194 194
 				&& filter_var($link['url'], FILTER_VALIDATE_URL)
195 195
 			) {
196
-				$legalLinks .= $divider . '<a href="' . $link['url'] . '" class="legal" target="_blank"' .
197
-					' rel="noreferrer noopener">' . $link['text'] . '</a>';
196
+				$legalLinks .= $divider.'<a href="'.$link['url'].'" class="legal" target="_blank"'.
197
+					' rel="noreferrer noopener">'.$link['text'].'</a>';
198 198
 				$divider = ' · ';
199 199
 			}
200 200
 		}
201
-		if($legalLinks !== '' ) {
202
-			$footer .= '<br/>' . $legalLinks;
201
+		if ($legalLinks !== '') {
202
+			$footer .= '<br/>'.$legalLinks;
203 203
 		}
204 204
 
205 205
 		return $footer;
@@ -232,16 +232,16 @@  discard block
 block discarded – undo
232 232
 
233 233
 		$cacheBusterCounter = $this->config->getAppValue('theming', 'cachebuster', '0');
234 234
 
235
-		if(!$logo || !$logoExists) {
236
-			if($useSvg) {
235
+		if (!$logo || !$logoExists) {
236
+			if ($useSvg) {
237 237
 				$logo = $this->urlGenerator->imagePath('core', 'logo/logo.svg');
238 238
 			} else {
239 239
 				$logo = $this->urlGenerator->imagePath('core', 'logo/logo.png');
240 240
 			}
241
-			return $logo . '?v=' . $cacheBusterCounter;
241
+			return $logo.'?v='.$cacheBusterCounter;
242 242
 		}
243 243
 
244
-		return $this->urlGenerator->linkToRoute('theming.Theming.getImage', [ 'key' => 'logo', 'useSvg' => $useSvg, 'v' => $cacheBusterCounter ]);
244
+		return $this->urlGenerator->linkToRoute('theming.Theming.getImage', ['key' => 'logo', 'useSvg' => $useSvg, 'v' => $cacheBusterCounter]);
245 245
 	}
246 246
 
247 247
 	/**
@@ -279,17 +279,17 @@  discard block
 block discarded – undo
279 279
 	 * @return array scss variables to overwrite
280 280
 	 */
281 281
 	public function getScssVariables() {
282
-		$cache = $this->cacheFactory->createDistributed('theming-' . $this->urlGenerator->getBaseUrl());
282
+		$cache = $this->cacheFactory->createDistributed('theming-'.$this->urlGenerator->getBaseUrl());
283 283
 		if ($value = $cache->get('getScssVariables')) {
284 284
 			return $value;
285 285
 		}
286 286
 
287 287
 		$variables = [
288
-			'theming-cachebuster' => "'" . $this->config->getAppValue('theming', 'cachebuster', '0') . "'",
289
-			'theming-logo-mime' => "'" . $this->config->getAppValue('theming', 'logoMime') . "'",
290
-			'theming-background-mime' => "'" . $this->config->getAppValue('theming', 'backgroundMime') . "'",
291
-			'theming-logoheader-mime' => "'" . $this->config->getAppValue('theming', 'logoheaderMime') . "'",
292
-			'theming-favicon-mime' => "'" . $this->config->getAppValue('theming', 'faviconMime') . "'"
288
+			'theming-cachebuster' => "'".$this->config->getAppValue('theming', 'cachebuster', '0')."'",
289
+			'theming-logo-mime' => "'".$this->config->getAppValue('theming', 'logoMime')."'",
290
+			'theming-background-mime' => "'".$this->config->getAppValue('theming', 'backgroundMime')."'",
291
+			'theming-logoheader-mime' => "'".$this->config->getAppValue('theming', 'logoheaderMime')."'",
292
+			'theming-favicon-mime' => "'".$this->config->getAppValue('theming', 'faviconMime')."'"
293 293
 		];
294 294
 
295 295
 		$variables['image-logo'] = "url('".$this->imageManager->getImageUrl('logo')."')";
@@ -309,7 +309,7 @@  discard block
 block discarded – undo
309 309
 		}
310 310
 
311 311
 		$variables['has-legal-links'] = 'false';
312
-		if($this->getImprintUrl() !== '' || $this->getPrivacyUrl() !== '') {
312
+		if ($this->getImprintUrl() !== '' || $this->getPrivacyUrl() !== '') {
313 313
 			$variables['has-legal-links'] = 'true';
314 314
 		}
315 315
 
@@ -347,18 +347,18 @@  discard block
 block discarded – undo
347 347
 		if ($image === 'manifest.json') {
348 348
 			try {
349 349
 				$appPath = $this->appManager->getAppPath($app);
350
-				if (file_exists($appPath . '/img/manifest.json')) {
350
+				if (file_exists($appPath.'/img/manifest.json')) {
351 351
 					return false;
352 352
 				}
353 353
 			} catch (AppPathNotFoundException $e) {}
354 354
 			$route = $this->urlGenerator->linkToRoute('theming.Theming.getManifest');
355 355
 		}
356
-		if (strpos($image, 'filetypes/') === 0 && file_exists(\OC::$SERVERROOT . '/core/img/' . $image )) {
356
+		if (strpos($image, 'filetypes/') === 0 && file_exists(\OC::$SERVERROOT.'/core/img/'.$image)) {
357 357
 			$route = $this->urlGenerator->linkToRoute('theming.Icon.getThemedIcon', ['app' => $app, 'image' => $image]);
358 358
 		}
359 359
 
360 360
 		if ($route) {
361
-			return $route . '?v=' . $cacheBusterValue;
361
+			return $route.'?v='.$cacheBusterValue;
362 362
 		}
363 363
 
364 364
 		return false;
@@ -369,7 +369,7 @@  discard block
 block discarded – undo
369 369
 	 */
370 370
 	private function increaseCacheBuster() {
371 371
 		$cacheBusterKey = $this->config->getAppValue('theming', 'cachebuster', '0');
372
-		$this->config->setAppValue('theming', 'cachebuster', (int)$cacheBusterKey+1);
372
+		$this->config->setAppValue('theming', 'cachebuster', (int) $cacheBusterKey + 1);
373 373
 		$this->cacheFactory->createDistributed('theming-')->clear();
374 374
 		$this->cacheFactory->createDistributed('imagePath')->clear();
375 375
 
Please login to merge, or discard this patch.
apps/federatedfilesharing/lib/AppInfo/Application.php 2 patches
Indentation   +129 added lines, -129 removed lines patch added patch discarded remove patch
@@ -40,135 +40,135 @@
 block discarded – undo
40 40
 
41 41
 class Application extends App {
42 42
 
43
-	/** @var FederatedShareProvider */
44
-	protected $federatedShareProvider;
45
-
46
-	public function __construct() {
47
-		parent::__construct('federatedfilesharing');
48
-
49
-		$container = $this->getContainer();
50
-		$server = $container->getServer();
51
-
52
-		$cloudFederationManager = $server->getCloudFederationProviderManager();
53
-		$cloudFederationManager->addCloudFederationProvider('file',
54
-			'Federated Files Sharing',
55
-			function () use ($container) {
56
-				$server = $container->getServer();
57
-				return new CloudFederationProviderFiles(
58
-					$server->getAppManager(),
59
-					$server->query(FederatedShareProvider::class),
60
-					$server->query(AddressHandler::class),
61
-					$server->getLogger(),
62
-					$server->getUserManager(),
63
-					$server->getShareManager(),
64
-					$server->getCloudIdManager(),
65
-					$server->getActivityManager(),
66
-					$server->getNotificationManager(),
67
-					$server->getURLGenerator(),
68
-					$server->getCloudFederationFactory(),
69
-					$server->getCloudFederationProviderManager(),
70
-					$server->getDatabaseConnection(),
71
-					$server->getGroupManager()
72
-				);
73
-			});
74
-
75
-		$container->registerService('RequestHandlerController', function (SimpleContainer $c) use ($server) {
76
-			$addressHandler = new AddressHandler(
77
-				$server->getURLGenerator(),
78
-				$server->getL10N('federatedfilesharing'),
79
-				$server->getCloudIdManager()
80
-			);
81
-			$notification = new Notifications(
82
-				$addressHandler,
83
-				$server->getHTTPClientService(),
84
-				$server->query(\OCP\OCS\IDiscoveryService::class),
85
-				\OC::$server->getJobList(),
86
-				\OC::$server->getCloudFederationProviderManager(),
87
-				\OC::$server->getCloudFederationFactory()
88
-			);
89
-			return new RequestHandlerController(
90
-				$c->query('AppName'),
91
-				$server->getRequest(),
92
-				$this->getFederatedShareProvider(),
93
-				$server->getDatabaseConnection(),
94
-				$server->getShareManager(),
95
-				$notification,
96
-				$addressHandler,
97
-				$server->getUserManager(),
98
-				$server->getCloudIdManager(),
99
-				$server->getLogger(),
100
-				$server->getCloudFederationFactory(),
101
-				$server->getCloudFederationProviderManager()
102
-			);
103
-		});
104
-
105
-		// register events listeners
106
-		$eventDispatcher = $server->getEventDispatcher();
107
-		$manager = $server->getNotificationManager();
108
-		$federatedShareProvider = $this->getFederatedShareProvider();
109
-
110
-		$manager->registerNotifierService(Notifier::class);
43
+    /** @var FederatedShareProvider */
44
+    protected $federatedShareProvider;
45
+
46
+    public function __construct() {
47
+        parent::__construct('federatedfilesharing');
48
+
49
+        $container = $this->getContainer();
50
+        $server = $container->getServer();
51
+
52
+        $cloudFederationManager = $server->getCloudFederationProviderManager();
53
+        $cloudFederationManager->addCloudFederationProvider('file',
54
+            'Federated Files Sharing',
55
+            function () use ($container) {
56
+                $server = $container->getServer();
57
+                return new CloudFederationProviderFiles(
58
+                    $server->getAppManager(),
59
+                    $server->query(FederatedShareProvider::class),
60
+                    $server->query(AddressHandler::class),
61
+                    $server->getLogger(),
62
+                    $server->getUserManager(),
63
+                    $server->getShareManager(),
64
+                    $server->getCloudIdManager(),
65
+                    $server->getActivityManager(),
66
+                    $server->getNotificationManager(),
67
+                    $server->getURLGenerator(),
68
+                    $server->getCloudFederationFactory(),
69
+                    $server->getCloudFederationProviderManager(),
70
+                    $server->getDatabaseConnection(),
71
+                    $server->getGroupManager()
72
+                );
73
+            });
74
+
75
+        $container->registerService('RequestHandlerController', function (SimpleContainer $c) use ($server) {
76
+            $addressHandler = new AddressHandler(
77
+                $server->getURLGenerator(),
78
+                $server->getL10N('federatedfilesharing'),
79
+                $server->getCloudIdManager()
80
+            );
81
+            $notification = new Notifications(
82
+                $addressHandler,
83
+                $server->getHTTPClientService(),
84
+                $server->query(\OCP\OCS\IDiscoveryService::class),
85
+                \OC::$server->getJobList(),
86
+                \OC::$server->getCloudFederationProviderManager(),
87
+                \OC::$server->getCloudFederationFactory()
88
+            );
89
+            return new RequestHandlerController(
90
+                $c->query('AppName'),
91
+                $server->getRequest(),
92
+                $this->getFederatedShareProvider(),
93
+                $server->getDatabaseConnection(),
94
+                $server->getShareManager(),
95
+                $notification,
96
+                $addressHandler,
97
+                $server->getUserManager(),
98
+                $server->getCloudIdManager(),
99
+                $server->getLogger(),
100
+                $server->getCloudFederationFactory(),
101
+                $server->getCloudFederationProviderManager()
102
+            );
103
+        });
104
+
105
+        // register events listeners
106
+        $eventDispatcher = $server->getEventDispatcher();
107
+        $manager = $server->getNotificationManager();
108
+        $federatedShareProvider = $this->getFederatedShareProvider();
109
+
110
+        $manager->registerNotifierService(Notifier::class);
111 111
 		
112
-		$eventDispatcher->addListener(
113
-			'OCA\Files::loadAdditionalScripts',
114
-			function () use ($federatedShareProvider) {
115
-				if ($federatedShareProvider->isIncomingServer2serverShareEnabled()) {
116
-					\OCP\Util::addScript('federatedfilesharing', 'external');
117
-				}
118
-			}
119
-		);
120
-
121
-	}
122
-
123
-	/**
124
-	 * get instance of federated share provider
125
-	 *
126
-	 * @return FederatedShareProvider
127
-	 */
128
-	public function getFederatedShareProvider() {
129
-		if ($this->federatedShareProvider === null) {
130
-			$this->initFederatedShareProvider();
131
-		}
132
-		return $this->federatedShareProvider;
133
-	}
134
-
135
-	/**
136
-	 * initialize federated share provider
137
-	 */
138
-	protected function initFederatedShareProvider() {
139
-		$c = $this->getContainer();
140
-		$addressHandler = new \OCA\FederatedFileSharing\AddressHandler(
141
-			\OC::$server->getURLGenerator(),
142
-			\OC::$server->getL10N('federatedfilesharing'),
143
-			\OC::$server->getCloudIdManager()
144
-		);
145
-		$notifications = new \OCA\FederatedFileSharing\Notifications(
146
-			$addressHandler,
147
-			\OC::$server->getHTTPClientService(),
148
-			\OC::$server->query(\OCP\OCS\IDiscoveryService::class),
149
-			\OC::$server->getJobList(),
150
-			\OC::$server->getCloudFederationProviderManager(),
151
-			\OC::$server->getCloudFederationFactory()
152
-		);
153
-		$tokenHandler = new \OCA\FederatedFileSharing\TokenHandler(
154
-			\OC::$server->getSecureRandom()
155
-		);
156
-
157
-		$this->federatedShareProvider = new \OCA\FederatedFileSharing\FederatedShareProvider(
158
-			\OC::$server->getDatabaseConnection(),
159
-			$addressHandler,
160
-			$notifications,
161
-			$tokenHandler,
162
-			\OC::$server->getL10N('federatedfilesharing'),
163
-			\OC::$server->getLogger(),
164
-			\OC::$server->getLazyRootFolder(),
165
-			\OC::$server->getConfig(),
166
-			\OC::$server->getUserManager(),
167
-			\OC::$server->getCloudIdManager(),
168
-			$c->query(IConfig::class),
169
-			\OC::$server->getCloudFederationProviderManager()
170
-
171
-		);
172
-	}
112
+        $eventDispatcher->addListener(
113
+            'OCA\Files::loadAdditionalScripts',
114
+            function () use ($federatedShareProvider) {
115
+                if ($federatedShareProvider->isIncomingServer2serverShareEnabled()) {
116
+                    \OCP\Util::addScript('federatedfilesharing', 'external');
117
+                }
118
+            }
119
+        );
120
+
121
+    }
122
+
123
+    /**
124
+     * get instance of federated share provider
125
+     *
126
+     * @return FederatedShareProvider
127
+     */
128
+    public function getFederatedShareProvider() {
129
+        if ($this->federatedShareProvider === null) {
130
+            $this->initFederatedShareProvider();
131
+        }
132
+        return $this->federatedShareProvider;
133
+    }
134
+
135
+    /**
136
+     * initialize federated share provider
137
+     */
138
+    protected function initFederatedShareProvider() {
139
+        $c = $this->getContainer();
140
+        $addressHandler = new \OCA\FederatedFileSharing\AddressHandler(
141
+            \OC::$server->getURLGenerator(),
142
+            \OC::$server->getL10N('federatedfilesharing'),
143
+            \OC::$server->getCloudIdManager()
144
+        );
145
+        $notifications = new \OCA\FederatedFileSharing\Notifications(
146
+            $addressHandler,
147
+            \OC::$server->getHTTPClientService(),
148
+            \OC::$server->query(\OCP\OCS\IDiscoveryService::class),
149
+            \OC::$server->getJobList(),
150
+            \OC::$server->getCloudFederationProviderManager(),
151
+            \OC::$server->getCloudFederationFactory()
152
+        );
153
+        $tokenHandler = new \OCA\FederatedFileSharing\TokenHandler(
154
+            \OC::$server->getSecureRandom()
155
+        );
156
+
157
+        $this->federatedShareProvider = new \OCA\FederatedFileSharing\FederatedShareProvider(
158
+            \OC::$server->getDatabaseConnection(),
159
+            $addressHandler,
160
+            $notifications,
161
+            $tokenHandler,
162
+            \OC::$server->getL10N('federatedfilesharing'),
163
+            \OC::$server->getLogger(),
164
+            \OC::$server->getLazyRootFolder(),
165
+            \OC::$server->getConfig(),
166
+            \OC::$server->getUserManager(),
167
+            \OC::$server->getCloudIdManager(),
168
+            $c->query(IConfig::class),
169
+            \OC::$server->getCloudFederationProviderManager()
170
+
171
+        );
172
+    }
173 173
 
174 174
 }
Please login to merge, or discard this patch.
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -52,7 +52,7 @@  discard block
 block discarded – undo
52 52
 		$cloudFederationManager = $server->getCloudFederationProviderManager();
53 53
 		$cloudFederationManager->addCloudFederationProvider('file',
54 54
 			'Federated Files Sharing',
55
-			function () use ($container) {
55
+			function() use ($container) {
56 56
 				$server = $container->getServer();
57 57
 				return new CloudFederationProviderFiles(
58 58
 					$server->getAppManager(),
@@ -72,7 +72,7 @@  discard block
 block discarded – undo
72 72
 				);
73 73
 			});
74 74
 
75
-		$container->registerService('RequestHandlerController', function (SimpleContainer $c) use ($server) {
75
+		$container->registerService('RequestHandlerController', function(SimpleContainer $c) use ($server) {
76 76
 			$addressHandler = new AddressHandler(
77 77
 				$server->getURLGenerator(),
78 78
 				$server->getL10N('federatedfilesharing'),
@@ -111,7 +111,7 @@  discard block
 block discarded – undo
111 111
 		
112 112
 		$eventDispatcher->addListener(
113 113
 			'OCA\Files::loadAdditionalScripts',
114
-			function () use ($federatedShareProvider) {
114
+			function() use ($federatedShareProvider) {
115 115
 				if ($federatedShareProvider->isIncomingServer2serverShareEnabled()) {
116 116
 					\OCP\Util::addScript('federatedfilesharing', 'external');
117 117
 				}
Please login to merge, or discard this patch.
apps/testing/lib/AppInfo/Application.php 1 patch
Indentation   +12 added lines, -12 removed lines patch added patch discarded remove patch
@@ -28,18 +28,18 @@
 block discarded – undo
28 28
 use OCP\AppFramework\App;
29 29
 
30 30
 class Application extends App {
31
-	public function __construct(array $urlParams = []) {
32
-		$appName = 'testing';
33
-		parent::__construct($appName, $urlParams);
31
+    public function __construct(array $urlParams = []) {
32
+        $appName = 'testing';
33
+        parent::__construct($appName, $urlParams);
34 34
 
35
-		$c = $this->getContainer();
36
-		$config = $c->getServer()->getConfig();
37
-		if ($config->getAppValue($appName, 'enable_alt_user_backend', 'no') === 'yes') {
38
-			$userManager = $c->getServer()->getUserManager();
35
+        $c = $this->getContainer();
36
+        $config = $c->getServer()->getConfig();
37
+        if ($config->getAppValue($appName, 'enable_alt_user_backend', 'no') === 'yes') {
38
+            $userManager = $c->getServer()->getUserManager();
39 39
 
40
-			// replace all user backends with this one
41
-			$userManager->clearBackends();
42
-			$userManager->registerBackend($c->query(AlternativeHomeUserBackend::class));
43
-		}
44
-	}
40
+            // replace all user backends with this one
41
+            $userManager->clearBackends();
42
+            $userManager->registerBackend($c->query(AlternativeHomeUserBackend::class));
43
+        }
44
+    }
45 45
 }
Please login to merge, or discard this patch.
lib/private/Security/TrustedDomainHelper.php 2 patches
Indentation   +63 added lines, -63 removed lines patch added patch discarded remove patch
@@ -36,73 +36,73 @@
 block discarded – undo
36 36
  * @package OC\Security
37 37
  */
38 38
 class TrustedDomainHelper {
39
-	/** @var IConfig */
40
-	private $config;
39
+    /** @var IConfig */
40
+    private $config;
41 41
 
42
-	/**
43
-	 * @param IConfig $config
44
-	 */
45
-	public function __construct(IConfig $config) {
46
-		$this->config = $config;
47
-	}
42
+    /**
43
+     * @param IConfig $config
44
+     */
45
+    public function __construct(IConfig $config) {
46
+        $this->config = $config;
47
+    }
48 48
 
49
-	/**
50
-	 * Strips a potential port from a domain (in format domain:port)
51
-	 * @param string $host
52
-	 * @return string $host without appended port
53
-	 */
54
-	private function getDomainWithoutPort($host) {
55
-		$pos = strrpos($host, ':');
56
-		if ($pos !== false) {
57
-			$port = substr($host, $pos + 1);
58
-			if (is_numeric($port)) {
59
-				$host = substr($host, 0, $pos);
60
-			}
61
-		}
62
-		return $host;
63
-	}
49
+    /**
50
+     * Strips a potential port from a domain (in format domain:port)
51
+     * @param string $host
52
+     * @return string $host without appended port
53
+     */
54
+    private function getDomainWithoutPort($host) {
55
+        $pos = strrpos($host, ':');
56
+        if ($pos !== false) {
57
+            $port = substr($host, $pos + 1);
58
+            if (is_numeric($port)) {
59
+                $host = substr($host, 0, $pos);
60
+            }
61
+        }
62
+        return $host;
63
+    }
64 64
 
65
-	/**
66
-	 * Checks whether a domain is considered as trusted from the list
67
-	 * of trusted domains. If no trusted domains have been configured, returns
68
-	 * true.
69
-	 * This is used to prevent Host Header Poisoning.
70
-	 * @param string $domainWithPort
71
-	 * @return bool true if the given domain is trusted or if no trusted domains
72
-	 * have been configured
73
-	 */
74
-	public function isTrustedDomain($domainWithPort) {
75
-		// overwritehost is always trusted
76
-		if ($this->config->getSystemValue('overwritehost') !== '') {
77
-			return true;
78
-		}
65
+    /**
66
+     * Checks whether a domain is considered as trusted from the list
67
+     * of trusted domains. If no trusted domains have been configured, returns
68
+     * true.
69
+     * This is used to prevent Host Header Poisoning.
70
+     * @param string $domainWithPort
71
+     * @return bool true if the given domain is trusted or if no trusted domains
72
+     * have been configured
73
+     */
74
+    public function isTrustedDomain($domainWithPort) {
75
+        // overwritehost is always trusted
76
+        if ($this->config->getSystemValue('overwritehost') !== '') {
77
+            return true;
78
+        }
79 79
 
80
-		$domain = $this->getDomainWithoutPort($domainWithPort);
80
+        $domain = $this->getDomainWithoutPort($domainWithPort);
81 81
 
82
-		// Read trusted domains from config
83
-		$trustedList = $this->config->getSystemValue('trusted_domains', []);
84
-		if (!is_array($trustedList)) {
85
-			return false;
86
-		}
82
+        // Read trusted domains from config
83
+        $trustedList = $this->config->getSystemValue('trusted_domains', []);
84
+        if (!is_array($trustedList)) {
85
+            return false;
86
+        }
87 87
 
88
-		// Always allow access from localhost
89
-		if (preg_match(Request::REGEX_LOCALHOST, $domain) === 1) {
90
-			return true;
91
-		}
92
-		// Reject misformed domains in any case
93
-		if (strpos($domain,'-') === 0 || strpos($domain,'..') !== false) {
94
-			return false;
95
-		}
96
-		// Match, allowing for * wildcards
97
-		foreach ($trustedList as $trusted) {
98
-			if (gettype($trusted) !== 'string') {
99
-				break;
100
-			}
101
-			$regex = '/^' . implode('[-\.a-zA-Z0-9]*', array_map(function ($v) { return preg_quote($v, '/'); }, explode('*', $trusted))) . '$/i';
102
-			if (preg_match($regex, $domain) || preg_match($regex, $domainWithPort)) {
103
-				return true;
104
-			}
105
-		}
106
-		return false;
107
-	}
88
+        // Always allow access from localhost
89
+        if (preg_match(Request::REGEX_LOCALHOST, $domain) === 1) {
90
+            return true;
91
+        }
92
+        // Reject misformed domains in any case
93
+        if (strpos($domain,'-') === 0 || strpos($domain,'..') !== false) {
94
+            return false;
95
+        }
96
+        // Match, allowing for * wildcards
97
+        foreach ($trustedList as $trusted) {
98
+            if (gettype($trusted) !== 'string') {
99
+                break;
100
+            }
101
+            $regex = '/^' . implode('[-\.a-zA-Z0-9]*', array_map(function ($v) { return preg_quote($v, '/'); }, explode('*', $trusted))) . '$/i';
102
+            if (preg_match($regex, $domain) || preg_match($regex, $domainWithPort)) {
103
+                return true;
104
+            }
105
+        }
106
+        return false;
107
+    }
108 108
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -90,7 +90,7 @@  discard block
 block discarded – undo
90 90
 			return true;
91 91
 		}
92 92
 		// Reject misformed domains in any case
93
-		if (strpos($domain,'-') === 0 || strpos($domain,'..') !== false) {
93
+		if (strpos($domain, '-') === 0 || strpos($domain, '..') !== false) {
94 94
 			return false;
95 95
 		}
96 96
 		// Match, allowing for * wildcards
@@ -98,7 +98,7 @@  discard block
 block discarded – undo
98 98
 			if (gettype($trusted) !== 'string') {
99 99
 				break;
100 100
 			}
101
-			$regex = '/^' . implode('[-\.a-zA-Z0-9]*', array_map(function ($v) { return preg_quote($v, '/'); }, explode('*', $trusted))) . '$/i';
101
+			$regex = '/^'.implode('[-\.a-zA-Z0-9]*', array_map(function($v) { return preg_quote($v, '/'); }, explode('*', $trusted))).'$/i';
102 102
 			if (preg_match($regex, $domain) || preg_match($regex, $domainWithPort)) {
103 103
 				return true;
104 104
 			}
Please login to merge, or discard this patch.
lib/private/Security/Bruteforce/Throttler.php 2 patches
Indentation   +237 added lines, -237 removed lines patch added patch discarded remove patch
@@ -48,241 +48,241 @@
 block discarded – undo
48 48
  * @package OC\Security\Bruteforce
49 49
  */
50 50
 class Throttler {
51
-	const LOGIN_ACTION = 'login';
52
-
53
-	/** @var IDBConnection */
54
-	private $db;
55
-	/** @var ITimeFactory */
56
-	private $timeFactory;
57
-	/** @var ILogger */
58
-	private $logger;
59
-	/** @var IConfig */
60
-	private $config;
61
-
62
-	/**
63
-	 * @param IDBConnection $db
64
-	 * @param ITimeFactory $timeFactory
65
-	 * @param ILogger $logger
66
-	 * @param IConfig $config
67
-	 */
68
-	public function __construct(IDBConnection $db,
69
-								ITimeFactory $timeFactory,
70
-								ILogger $logger,
71
-								IConfig $config) {
72
-		$this->db = $db;
73
-		$this->timeFactory = $timeFactory;
74
-		$this->logger = $logger;
75
-		$this->config = $config;
76
-	}
77
-
78
-	/**
79
-	 * Convert a number of seconds into the appropriate DateInterval
80
-	 *
81
-	 * @param int $expire
82
-	 * @return \DateInterval
83
-	 */
84
-	private function getCutoff($expire) {
85
-		$d1 = new \DateTime();
86
-		$d2 = clone $d1;
87
-		$d2->sub(new \DateInterval('PT' . $expire . 'S'));
88
-		return $d2->diff($d1);
89
-	}
90
-
91
-	/**
92
-	 * Register a failed attempt to bruteforce a security control
93
-	 *
94
-	 * @param string $action
95
-	 * @param string $ip
96
-	 * @param array $metadata Optional metadata logged to the database
97
-	 * @suppress SqlInjectionChecker
98
-	 */
99
-	public function registerAttempt($action,
100
-									$ip,
101
-									array $metadata = []) {
102
-		// No need to log if the bruteforce protection is disabled
103
-		if($this->config->getSystemValue('auth.bruteforce.protection.enabled', true) === false) {
104
-			return;
105
-		}
106
-
107
-		$ipAddress = new IpAddress($ip);
108
-		$values = [
109
-			'action' => $action,
110
-			'occurred' => $this->timeFactory->getTime(),
111
-			'ip' => (string)$ipAddress,
112
-			'subnet' => $ipAddress->getSubnet(),
113
-			'metadata' => json_encode($metadata),
114
-		];
115
-
116
-		$this->logger->notice(
117
-			sprintf(
118
-				'Bruteforce attempt from "%s" detected for action "%s".',
119
-				$ip,
120
-				$action
121
-			),
122
-			[
123
-				'app' => 'core',
124
-			]
125
-		);
126
-
127
-		$qb = $this->db->getQueryBuilder();
128
-		$qb->insert('bruteforce_attempts');
129
-		foreach($values as $column => $value) {
130
-			$qb->setValue($column, $qb->createNamedParameter($value));
131
-		}
132
-		$qb->execute();
133
-	}
134
-
135
-	/**
136
-	 * Check if the IP is whitelisted
137
-	 *
138
-	 * @param string $ip
139
-	 * @return bool
140
-	 */
141
-	private function isIPWhitelisted($ip) {
142
-		if($this->config->getSystemValue('auth.bruteforce.protection.enabled', true) === false) {
143
-			return true;
144
-		}
145
-
146
-		$keys = $this->config->getAppKeys('bruteForce');
147
-		$keys = array_filter($keys, function ($key) {
148
-			$regex = '/^whitelist_/S';
149
-			return preg_match($regex, $key) === 1;
150
-		});
151
-
152
-		if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
153
-			$type = 4;
154
-		} else if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
155
-			$type = 6;
156
-		} else {
157
-			return false;
158
-		}
159
-
160
-		$ip = inet_pton($ip);
161
-
162
-		foreach ($keys as $key) {
163
-			$cidr = $this->config->getAppValue('bruteForce', $key, null);
164
-
165
-			$cx = explode('/', $cidr);
166
-			$addr = $cx[0];
167
-			$mask = (int)$cx[1];
168
-
169
-			// Do not compare ipv4 to ipv6
170
-			if (($type === 4 && !filter_var($addr, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) ||
171
-				($type === 6 && !filter_var($addr, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6))) {
172
-				continue;
173
-			}
174
-
175
-			$addr = inet_pton($addr);
176
-
177
-			$valid = true;
178
-			for($i = 0; $i < $mask; $i++) {
179
-				$part = ord($addr[(int)($i/8)]);
180
-				$orig = ord($ip[(int)($i/8)]);
181
-
182
-				$bitmask = 1 << (7 - ($i % 8));
183
-
184
-				$part = $part & $bitmask;
185
-				$orig = $orig & $bitmask;
186
-
187
-				if ($part !== $orig) {
188
-					$valid = false;
189
-					break;
190
-				}
191
-			}
192
-
193
-			if ($valid === true) {
194
-				return true;
195
-			}
196
-		}
197
-
198
-		return false;
199
-
200
-	}
201
-
202
-	/**
203
-	 * Get the throttling delay (in milliseconds)
204
-	 *
205
-	 * @param string $ip
206
-	 * @param string $action optionally filter by action
207
-	 * @return int
208
-	 */
209
-	public function getDelay($ip, $action = '') {
210
-		$ipAddress = new IpAddress($ip);
211
-		if ($this->isIPWhitelisted((string)$ipAddress)) {
212
-			return 0;
213
-		}
214
-
215
-		$cutoffTime = (new \DateTime())
216
-			->sub($this->getCutoff(43200))
217
-			->getTimestamp();
218
-
219
-		$qb = $this->db->getQueryBuilder();
220
-		$qb->select('*')
221
-			->from('bruteforce_attempts')
222
-			->where($qb->expr()->gt('occurred', $qb->createNamedParameter($cutoffTime)))
223
-			->andWhere($qb->expr()->eq('subnet', $qb->createNamedParameter($ipAddress->getSubnet())));
224
-
225
-		if ($action !== '') {
226
-			$qb->andWhere($qb->expr()->eq('action', $qb->createNamedParameter($action)));
227
-		}
228
-
229
-		$attempts = count($qb->execute()->fetchAll());
230
-
231
-		if ($attempts === 0) {
232
-			return 0;
233
-		}
234
-
235
-		$maxDelay = 25;
236
-		$firstDelay = 0.1;
237
-		if ($attempts > (8 * PHP_INT_SIZE - 1))  {
238
-			// Don't ever overflow. Just assume the maxDelay time:s
239
-			$firstDelay = $maxDelay;
240
-		} else {
241
-			$firstDelay *= pow(2, $attempts);
242
-			if ($firstDelay > $maxDelay) {
243
-				$firstDelay = $maxDelay;
244
-			}
245
-		}
246
-		return (int) \ceil($firstDelay * 1000);
247
-	}
248
-
249
-	/**
250
-	 * Reset the throttling delay for an IP address, action and metadata
251
-	 *
252
-	 * @param string $ip
253
-	 * @param string $action
254
-	 * @param string $metadata
255
-	 */
256
-	public function resetDelay($ip, $action, $metadata) {
257
-		$ipAddress = new IpAddress($ip);
258
-		if ($this->isIPWhitelisted((string)$ipAddress)) {
259
-			return;
260
-		}
261
-
262
-		$cutoffTime = (new \DateTime())
263
-			->sub($this->getCutoff(43200))
264
-			->getTimestamp();
265
-
266
-		$qb = $this->db->getQueryBuilder();
267
-		$qb->delete('bruteforce_attempts')
268
-			->where($qb->expr()->gt('occurred', $qb->createNamedParameter($cutoffTime)))
269
-			->andWhere($qb->expr()->eq('subnet', $qb->createNamedParameter($ipAddress->getSubnet())))
270
-			->andWhere($qb->expr()->eq('action', $qb->createNamedParameter($action)))
271
-			->andWhere($qb->expr()->eq('metadata', $qb->createNamedParameter(json_encode($metadata))));
272
-
273
-		$qb->execute();
274
-	}
275
-
276
-	/**
277
-	 * Will sleep for the defined amount of time
278
-	 *
279
-	 * @param string $ip
280
-	 * @param string $action optionally filter by action
281
-	 * @return int the time spent sleeping
282
-	 */
283
-	public function sleepDelay($ip, $action = '') {
284
-		$delay = $this->getDelay($ip, $action);
285
-		usleep($delay * 1000);
286
-		return $delay;
287
-	}
51
+    const LOGIN_ACTION = 'login';
52
+
53
+    /** @var IDBConnection */
54
+    private $db;
55
+    /** @var ITimeFactory */
56
+    private $timeFactory;
57
+    /** @var ILogger */
58
+    private $logger;
59
+    /** @var IConfig */
60
+    private $config;
61
+
62
+    /**
63
+     * @param IDBConnection $db
64
+     * @param ITimeFactory $timeFactory
65
+     * @param ILogger $logger
66
+     * @param IConfig $config
67
+     */
68
+    public function __construct(IDBConnection $db,
69
+                                ITimeFactory $timeFactory,
70
+                                ILogger $logger,
71
+                                IConfig $config) {
72
+        $this->db = $db;
73
+        $this->timeFactory = $timeFactory;
74
+        $this->logger = $logger;
75
+        $this->config = $config;
76
+    }
77
+
78
+    /**
79
+     * Convert a number of seconds into the appropriate DateInterval
80
+     *
81
+     * @param int $expire
82
+     * @return \DateInterval
83
+     */
84
+    private function getCutoff($expire) {
85
+        $d1 = new \DateTime();
86
+        $d2 = clone $d1;
87
+        $d2->sub(new \DateInterval('PT' . $expire . 'S'));
88
+        return $d2->diff($d1);
89
+    }
90
+
91
+    /**
92
+     * Register a failed attempt to bruteforce a security control
93
+     *
94
+     * @param string $action
95
+     * @param string $ip
96
+     * @param array $metadata Optional metadata logged to the database
97
+     * @suppress SqlInjectionChecker
98
+     */
99
+    public function registerAttempt($action,
100
+                                    $ip,
101
+                                    array $metadata = []) {
102
+        // No need to log if the bruteforce protection is disabled
103
+        if($this->config->getSystemValue('auth.bruteforce.protection.enabled', true) === false) {
104
+            return;
105
+        }
106
+
107
+        $ipAddress = new IpAddress($ip);
108
+        $values = [
109
+            'action' => $action,
110
+            'occurred' => $this->timeFactory->getTime(),
111
+            'ip' => (string)$ipAddress,
112
+            'subnet' => $ipAddress->getSubnet(),
113
+            'metadata' => json_encode($metadata),
114
+        ];
115
+
116
+        $this->logger->notice(
117
+            sprintf(
118
+                'Bruteforce attempt from "%s" detected for action "%s".',
119
+                $ip,
120
+                $action
121
+            ),
122
+            [
123
+                'app' => 'core',
124
+            ]
125
+        );
126
+
127
+        $qb = $this->db->getQueryBuilder();
128
+        $qb->insert('bruteforce_attempts');
129
+        foreach($values as $column => $value) {
130
+            $qb->setValue($column, $qb->createNamedParameter($value));
131
+        }
132
+        $qb->execute();
133
+    }
134
+
135
+    /**
136
+     * Check if the IP is whitelisted
137
+     *
138
+     * @param string $ip
139
+     * @return bool
140
+     */
141
+    private function isIPWhitelisted($ip) {
142
+        if($this->config->getSystemValue('auth.bruteforce.protection.enabled', true) === false) {
143
+            return true;
144
+        }
145
+
146
+        $keys = $this->config->getAppKeys('bruteForce');
147
+        $keys = array_filter($keys, function ($key) {
148
+            $regex = '/^whitelist_/S';
149
+            return preg_match($regex, $key) === 1;
150
+        });
151
+
152
+        if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
153
+            $type = 4;
154
+        } else if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
155
+            $type = 6;
156
+        } else {
157
+            return false;
158
+        }
159
+
160
+        $ip = inet_pton($ip);
161
+
162
+        foreach ($keys as $key) {
163
+            $cidr = $this->config->getAppValue('bruteForce', $key, null);
164
+
165
+            $cx = explode('/', $cidr);
166
+            $addr = $cx[0];
167
+            $mask = (int)$cx[1];
168
+
169
+            // Do not compare ipv4 to ipv6
170
+            if (($type === 4 && !filter_var($addr, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) ||
171
+                ($type === 6 && !filter_var($addr, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6))) {
172
+                continue;
173
+            }
174
+
175
+            $addr = inet_pton($addr);
176
+
177
+            $valid = true;
178
+            for($i = 0; $i < $mask; $i++) {
179
+                $part = ord($addr[(int)($i/8)]);
180
+                $orig = ord($ip[(int)($i/8)]);
181
+
182
+                $bitmask = 1 << (7 - ($i % 8));
183
+
184
+                $part = $part & $bitmask;
185
+                $orig = $orig & $bitmask;
186
+
187
+                if ($part !== $orig) {
188
+                    $valid = false;
189
+                    break;
190
+                }
191
+            }
192
+
193
+            if ($valid === true) {
194
+                return true;
195
+            }
196
+        }
197
+
198
+        return false;
199
+
200
+    }
201
+
202
+    /**
203
+     * Get the throttling delay (in milliseconds)
204
+     *
205
+     * @param string $ip
206
+     * @param string $action optionally filter by action
207
+     * @return int
208
+     */
209
+    public function getDelay($ip, $action = '') {
210
+        $ipAddress = new IpAddress($ip);
211
+        if ($this->isIPWhitelisted((string)$ipAddress)) {
212
+            return 0;
213
+        }
214
+
215
+        $cutoffTime = (new \DateTime())
216
+            ->sub($this->getCutoff(43200))
217
+            ->getTimestamp();
218
+
219
+        $qb = $this->db->getQueryBuilder();
220
+        $qb->select('*')
221
+            ->from('bruteforce_attempts')
222
+            ->where($qb->expr()->gt('occurred', $qb->createNamedParameter($cutoffTime)))
223
+            ->andWhere($qb->expr()->eq('subnet', $qb->createNamedParameter($ipAddress->getSubnet())));
224
+
225
+        if ($action !== '') {
226
+            $qb->andWhere($qb->expr()->eq('action', $qb->createNamedParameter($action)));
227
+        }
228
+
229
+        $attempts = count($qb->execute()->fetchAll());
230
+
231
+        if ($attempts === 0) {
232
+            return 0;
233
+        }
234
+
235
+        $maxDelay = 25;
236
+        $firstDelay = 0.1;
237
+        if ($attempts > (8 * PHP_INT_SIZE - 1))  {
238
+            // Don't ever overflow. Just assume the maxDelay time:s
239
+            $firstDelay = $maxDelay;
240
+        } else {
241
+            $firstDelay *= pow(2, $attempts);
242
+            if ($firstDelay > $maxDelay) {
243
+                $firstDelay = $maxDelay;
244
+            }
245
+        }
246
+        return (int) \ceil($firstDelay * 1000);
247
+    }
248
+
249
+    /**
250
+     * Reset the throttling delay for an IP address, action and metadata
251
+     *
252
+     * @param string $ip
253
+     * @param string $action
254
+     * @param string $metadata
255
+     */
256
+    public function resetDelay($ip, $action, $metadata) {
257
+        $ipAddress = new IpAddress($ip);
258
+        if ($this->isIPWhitelisted((string)$ipAddress)) {
259
+            return;
260
+        }
261
+
262
+        $cutoffTime = (new \DateTime())
263
+            ->sub($this->getCutoff(43200))
264
+            ->getTimestamp();
265
+
266
+        $qb = $this->db->getQueryBuilder();
267
+        $qb->delete('bruteforce_attempts')
268
+            ->where($qb->expr()->gt('occurred', $qb->createNamedParameter($cutoffTime)))
269
+            ->andWhere($qb->expr()->eq('subnet', $qb->createNamedParameter($ipAddress->getSubnet())))
270
+            ->andWhere($qb->expr()->eq('action', $qb->createNamedParameter($action)))
271
+            ->andWhere($qb->expr()->eq('metadata', $qb->createNamedParameter(json_encode($metadata))));
272
+
273
+        $qb->execute();
274
+    }
275
+
276
+    /**
277
+     * Will sleep for the defined amount of time
278
+     *
279
+     * @param string $ip
280
+     * @param string $action optionally filter by action
281
+     * @return int the time spent sleeping
282
+     */
283
+    public function sleepDelay($ip, $action = '') {
284
+        $delay = $this->getDelay($ip, $action);
285
+        usleep($delay * 1000);
286
+        return $delay;
287
+    }
288 288
 }
Please login to merge, or discard this patch.
Spacing   +13 added lines, -13 removed lines patch added patch discarded remove patch
@@ -84,7 +84,7 @@  discard block
 block discarded – undo
84 84
 	private function getCutoff($expire) {
85 85
 		$d1 = new \DateTime();
86 86
 		$d2 = clone $d1;
87
-		$d2->sub(new \DateInterval('PT' . $expire . 'S'));
87
+		$d2->sub(new \DateInterval('PT'.$expire.'S'));
88 88
 		return $d2->diff($d1);
89 89
 	}
90 90
 
@@ -100,7 +100,7 @@  discard block
 block discarded – undo
100 100
 									$ip,
101 101
 									array $metadata = []) {
102 102
 		// No need to log if the bruteforce protection is disabled
103
-		if($this->config->getSystemValue('auth.bruteforce.protection.enabled', true) === false) {
103
+		if ($this->config->getSystemValue('auth.bruteforce.protection.enabled', true) === false) {
104 104
 			return;
105 105
 		}
106 106
 
@@ -108,7 +108,7 @@  discard block
 block discarded – undo
108 108
 		$values = [
109 109
 			'action' => $action,
110 110
 			'occurred' => $this->timeFactory->getTime(),
111
-			'ip' => (string)$ipAddress,
111
+			'ip' => (string) $ipAddress,
112 112
 			'subnet' => $ipAddress->getSubnet(),
113 113
 			'metadata' => json_encode($metadata),
114 114
 		];
@@ -126,7 +126,7 @@  discard block
 block discarded – undo
126 126
 
127 127
 		$qb = $this->db->getQueryBuilder();
128 128
 		$qb->insert('bruteforce_attempts');
129
-		foreach($values as $column => $value) {
129
+		foreach ($values as $column => $value) {
130 130
 			$qb->setValue($column, $qb->createNamedParameter($value));
131 131
 		}
132 132
 		$qb->execute();
@@ -139,12 +139,12 @@  discard block
 block discarded – undo
139 139
 	 * @return bool
140 140
 	 */
141 141
 	private function isIPWhitelisted($ip) {
142
-		if($this->config->getSystemValue('auth.bruteforce.protection.enabled', true) === false) {
142
+		if ($this->config->getSystemValue('auth.bruteforce.protection.enabled', true) === false) {
143 143
 			return true;
144 144
 		}
145 145
 
146 146
 		$keys = $this->config->getAppKeys('bruteForce');
147
-		$keys = array_filter($keys, function ($key) {
147
+		$keys = array_filter($keys, function($key) {
148 148
 			$regex = '/^whitelist_/S';
149 149
 			return preg_match($regex, $key) === 1;
150 150
 		});
@@ -164,7 +164,7 @@  discard block
 block discarded – undo
164 164
 
165 165
 			$cx = explode('/', $cidr);
166 166
 			$addr = $cx[0];
167
-			$mask = (int)$cx[1];
167
+			$mask = (int) $cx[1];
168 168
 
169 169
 			// Do not compare ipv4 to ipv6
170 170
 			if (($type === 4 && !filter_var($addr, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) ||
@@ -175,9 +175,9 @@  discard block
 block discarded – undo
175 175
 			$addr = inet_pton($addr);
176 176
 
177 177
 			$valid = true;
178
-			for($i = 0; $i < $mask; $i++) {
179
-				$part = ord($addr[(int)($i/8)]);
180
-				$orig = ord($ip[(int)($i/8)]);
178
+			for ($i = 0; $i < $mask; $i++) {
179
+				$part = ord($addr[(int) ($i / 8)]);
180
+				$orig = ord($ip[(int) ($i / 8)]);
181 181
 
182 182
 				$bitmask = 1 << (7 - ($i % 8));
183 183
 
@@ -208,7 +208,7 @@  discard block
 block discarded – undo
208 208
 	 */
209 209
 	public function getDelay($ip, $action = '') {
210 210
 		$ipAddress = new IpAddress($ip);
211
-		if ($this->isIPWhitelisted((string)$ipAddress)) {
211
+		if ($this->isIPWhitelisted((string) $ipAddress)) {
212 212
 			return 0;
213 213
 		}
214 214
 
@@ -234,7 +234,7 @@  discard block
 block discarded – undo
234 234
 
235 235
 		$maxDelay = 25;
236 236
 		$firstDelay = 0.1;
237
-		if ($attempts > (8 * PHP_INT_SIZE - 1))  {
237
+		if ($attempts > (8 * PHP_INT_SIZE - 1)) {
238 238
 			// Don't ever overflow. Just assume the maxDelay time:s
239 239
 			$firstDelay = $maxDelay;
240 240
 		} else {
@@ -255,7 +255,7 @@  discard block
 block discarded – undo
255 255
 	 */
256 256
 	public function resetDelay($ip, $action, $metadata) {
257 257
 		$ipAddress = new IpAddress($ip);
258
-		if ($this->isIPWhitelisted((string)$ipAddress)) {
258
+		if ($this->isIPWhitelisted((string) $ipAddress)) {
259 259
 			return;
260 260
 		}
261 261
 
Please login to merge, or discard this patch.
lib/private/Authentication/TwoFactorAuth/ProviderSet.php 2 patches
Indentation   +39 added lines, -39 removed lines patch added patch discarded remove patch
@@ -35,50 +35,50 @@
 block discarded – undo
35 35
  */
36 36
 class ProviderSet {
37 37
 
38
-	/** @var IProvider */
39
-	private $providers;
38
+    /** @var IProvider */
39
+    private $providers;
40 40
 
41
-	/** @var bool */
42
-	private $providerMissing;
41
+    /** @var bool */
42
+    private $providerMissing;
43 43
 
44
-	/**
45
-	 * @param IProvider[] $providers
46
-	 * @param bool $providerMissing
47
-	 */
48
-	public function __construct(array $providers, bool $providerMissing) {
49
-		$this->providers = [];
50
-		foreach ($providers as $provider) {
51
-			$this->providers[$provider->getId()] = $provider;
52
-		}
53
-		$this->providerMissing = $providerMissing;
54
-	}
44
+    /**
45
+     * @param IProvider[] $providers
46
+     * @param bool $providerMissing
47
+     */
48
+    public function __construct(array $providers, bool $providerMissing) {
49
+        $this->providers = [];
50
+        foreach ($providers as $provider) {
51
+            $this->providers[$provider->getId()] = $provider;
52
+        }
53
+        $this->providerMissing = $providerMissing;
54
+    }
55 55
 
56
-	/**
57
-	 * @param string $providerId
58
-	 * @return IProvider|null
59
-	 */
60
-	public function getProvider(string $providerId) {
61
-		return $this->providers[$providerId] ?? null;
62
-	}
56
+    /**
57
+     * @param string $providerId
58
+     * @return IProvider|null
59
+     */
60
+    public function getProvider(string $providerId) {
61
+        return $this->providers[$providerId] ?? null;
62
+    }
63 63
 
64
-	/**
65
-	 * @return IProvider[]
66
-	 */
67
-	public function getProviders(): array {
68
-		return $this->providers;
69
-	}
64
+    /**
65
+     * @return IProvider[]
66
+     */
67
+    public function getProviders(): array {
68
+        return $this->providers;
69
+    }
70 70
 
71
-	/**
72
-	 * @return IProvider[]
73
-	 */
74
-	public function getPrimaryProviders(): array {
75
-		return array_filter($this->providers, function (IProvider $provider) {
76
-			return !($provider instanceof BackupCodesProvider);
77
-		});
78
-	}
71
+    /**
72
+     * @return IProvider[]
73
+     */
74
+    public function getPrimaryProviders(): array {
75
+        return array_filter($this->providers, function (IProvider $provider) {
76
+            return !($provider instanceof BackupCodesProvider);
77
+        });
78
+    }
79 79
 
80
-	public function isProviderMissing(): bool {
81
-		return $this->providerMissing;
82
-	}
80
+    public function isProviderMissing(): bool {
81
+        return $this->providerMissing;
82
+    }
83 83
 
84 84
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -72,7 +72,7 @@
 block discarded – undo
72 72
 	 * @return IProvider[]
73 73
 	 */
74 74
 	public function getPrimaryProviders(): array {
75
-		return array_filter($this->providers, function (IProvider $provider) {
75
+		return array_filter($this->providers, function(IProvider $provider) {
76 76
 			return !($provider instanceof BackupCodesProvider);
77 77
 		});
78 78
 	}
Please login to merge, or discard this patch.
lib/private/Authentication/TwoFactorAuth/Manager.php 2 patches
Indentation   +334 added lines, -334 removed lines patch added patch discarded remove patch
@@ -47,342 +47,342 @@
 block discarded – undo
47 47
 
48 48
 class Manager {
49 49
 
50
-	const SESSION_UID_KEY = 'two_factor_auth_uid';
51
-	const SESSION_UID_DONE = 'two_factor_auth_passed';
52
-	const REMEMBER_LOGIN = 'two_factor_remember_login';
53
-	const BACKUP_CODES_PROVIDER_ID = 'backup_codes';
54
-
55
-	/** @var ProviderLoader */
56
-	private $providerLoader;
57
-
58
-	/** @var IRegistry */
59
-	private $providerRegistry;
60
-
61
-	/** @var MandatoryTwoFactor */
62
-	private $mandatoryTwoFactor;
63
-
64
-	/** @var ISession */
65
-	private $session;
66
-
67
-	/** @var IConfig */
68
-	private $config;
69
-
70
-	/** @var IManager */
71
-	private $activityManager;
72
-
73
-	/** @var ILogger */
74
-	private $logger;
75
-
76
-	/** @var TokenProvider */
77
-	private $tokenProvider;
78
-
79
-	/** @var ITimeFactory */
80
-	private $timeFactory;
81
-
82
-	/** @var EventDispatcherInterface */
83
-	private $dispatcher;
84
-
85
-	public function __construct(ProviderLoader $providerLoader,
86
-								IRegistry $providerRegistry,
87
-								MandatoryTwoFactor $mandatoryTwoFactor,
88
-								ISession $session, IConfig $config,
89
-								IManager $activityManager, ILogger $logger, TokenProvider $tokenProvider,
90
-								ITimeFactory $timeFactory, EventDispatcherInterface $eventDispatcher) {
91
-		$this->providerLoader = $providerLoader;
92
-		$this->providerRegistry = $providerRegistry;
93
-		$this->mandatoryTwoFactor = $mandatoryTwoFactor;
94
-		$this->session = $session;
95
-		$this->config = $config;
96
-		$this->activityManager = $activityManager;
97
-		$this->logger = $logger;
98
-		$this->tokenProvider = $tokenProvider;
99
-		$this->timeFactory = $timeFactory;
100
-		$this->dispatcher = $eventDispatcher;
101
-	}
102
-
103
-	/**
104
-	 * Determine whether the user must provide a second factor challenge
105
-	 *
106
-	 * @param IUser $user
107
-	 * @return boolean
108
-	 */
109
-	public function isTwoFactorAuthenticated(IUser $user): bool {
110
-		if ($this->mandatoryTwoFactor->isEnforcedFor($user)) {
111
-			return true;
112
-		}
113
-
114
-		$providerStates = $this->providerRegistry->getProviderStates($user);
115
-		$providers = $this->providerLoader->getProviders($user);
116
-		$fixedStates = $this->fixMissingProviderStates($providerStates, $providers, $user);
117
-		$enabled = array_filter($fixedStates);
118
-		$providerIds = array_keys($enabled);
119
-		$providerIdsWithoutBackupCodes = array_diff($providerIds, [self::BACKUP_CODES_PROVIDER_ID]);
120
-
121
-		return !empty($providerIdsWithoutBackupCodes);
122
-	}
123
-
124
-	/**
125
-	 * Get a 2FA provider by its ID
126
-	 *
127
-	 * @param IUser $user
128
-	 * @param string $challengeProviderId
129
-	 * @return IProvider|null
130
-	 */
131
-	public function getProvider(IUser $user, string $challengeProviderId) {
132
-		$providers = $this->getProviderSet($user)->getProviders();
133
-		return $providers[$challengeProviderId] ?? null;
134
-	}
135
-
136
-	/**
137
-	 * @param IUser $user
138
-	 * @return IActivatableAtLogin[]
139
-	 * @throws Exception
140
-	 */
141
-	public function getLoginSetupProviders(IUser $user): array {
142
-		$providers = $this->providerLoader->getProviders($user);
143
-		return array_filter($providers, function (IProvider $provider) {
144
-			return ($provider instanceof IActivatableAtLogin);
145
-		});
146
-	}
147
-
148
-	/**
149
-	 * Check if the persistant mapping of enabled/disabled state of each available
150
-	 * provider is missing an entry and add it to the registry in that case.
151
-	 *
152
-	 * @todo remove in Nextcloud 17 as by then all providers should have been updated
153
-	 *
154
-	 * @param string[] $providerStates
155
-	 * @param IProvider[] $providers
156
-	 * @param IUser $user
157
-	 * @return string[] the updated $providerStates variable
158
-	 */
159
-	private function fixMissingProviderStates(array $providerStates,
160
-		array $providers, IUser $user): array {
161
-
162
-		foreach ($providers as $provider) {
163
-			if (isset($providerStates[$provider->getId()])) {
164
-				// All good
165
-				continue;
166
-			}
167
-
168
-			$enabled = $provider->isTwoFactorAuthEnabledForUser($user);
169
-			if ($enabled) {
170
-				$this->providerRegistry->enableProviderFor($provider, $user);
171
-			} else {
172
-				$this->providerRegistry->disableProviderFor($provider, $user);
173
-			}
174
-			$providerStates[$provider->getId()] = $enabled;
175
-		}
176
-
177
-		return $providerStates;
178
-	}
179
-
180
-	/**
181
-	 * @param array $states
182
-	 * @param IProvider[] $providers
183
-	 */
184
-	private function isProviderMissing(array $states, array $providers): bool {
185
-		$indexed = [];
186
-		foreach ($providers as $provider) {
187
-			$indexed[$provider->getId()] = $provider;
188
-		}
189
-
190
-		$missing = [];
191
-		foreach ($states as $providerId => $enabled) {
192
-			if (!$enabled) {
193
-				// Don't care
194
-				continue;
195
-			}
196
-
197
-			if (!isset($indexed[$providerId])) {
198
-				$missing[] = $providerId;
199
-				$this->logger->alert("two-factor auth provider '$providerId' failed to load",
200
-					[
201
-						'app' => 'core',
202
-					]);
203
-			}
204
-		}
205
-
206
-		if (!empty($missing)) {
207
-			// There was at least one provider missing
208
-			$this->logger->alert(count($missing) . " two-factor auth providers failed to load", ['app' => 'core']);
209
-
210
-			return true;
211
-		}
212
-
213
-		// If we reach this, there was not a single provider missing
214
-		return false;
215
-	}
216
-
217
-	/**
218
-	 * Get the list of 2FA providers for the given user
219
-	 *
220
-	 * @param IUser $user
221
-	 * @throws Exception
222
-	 */
223
-	public function getProviderSet(IUser $user): ProviderSet {
224
-		$providerStates = $this->providerRegistry->getProviderStates($user);
225
-		$providers = $this->providerLoader->getProviders($user);
226
-
227
-		$fixedStates = $this->fixMissingProviderStates($providerStates, $providers, $user);
228
-		$isProviderMissing = $this->isProviderMissing($fixedStates, $providers);
229
-
230
-		$enabled = array_filter($providers, function (IProvider $provider) use ($fixedStates) {
231
-			return $fixedStates[$provider->getId()];
232
-		});
233
-		return new ProviderSet($enabled, $isProviderMissing);
234
-	}
235
-
236
-	/**
237
-	 * Verify the given challenge
238
-	 *
239
-	 * @param string $providerId
240
-	 * @param IUser $user
241
-	 * @param string $challenge
242
-	 * @return boolean
243
-	 */
244
-	public function verifyChallenge(string $providerId, IUser $user, string $challenge): bool {
245
-		$provider = $this->getProvider($user, $providerId);
246
-		if ($provider === null) {
247
-			return false;
248
-		}
249
-
250
-		$passed = $provider->verifyChallenge($user, $challenge);
251
-		if ($passed) {
252
-			if ($this->session->get(self::REMEMBER_LOGIN) === true) {
253
-				// TODO: resolve cyclic dependency and use DI
254
-				\OC::$server->getUserSession()->createRememberMeToken($user);
255
-			}
256
-			$this->session->remove(self::SESSION_UID_KEY);
257
-			$this->session->remove(self::REMEMBER_LOGIN);
258
-			$this->session->set(self::SESSION_UID_DONE, $user->getUID());
259
-
260
-			// Clear token from db
261
-			$sessionId = $this->session->getId();
262
-			$token = $this->tokenProvider->getToken($sessionId);
263
-			$tokenId = $token->getId();
264
-			$this->config->deleteUserValue($user->getUID(), 'login_token_2fa', $tokenId);
265
-
266
-			$dispatchEvent = new GenericEvent($user, ['provider' => $provider->getDisplayName()]);
267
-			$this->dispatcher->dispatch(IProvider::EVENT_SUCCESS, $dispatchEvent);
268
-
269
-			$this->publishEvent($user, 'twofactor_success', [
270
-				'provider' => $provider->getDisplayName(),
271
-			]);
272
-		} else {
273
-			$dispatchEvent = new GenericEvent($user, ['provider' => $provider->getDisplayName()]);
274
-			$this->dispatcher->dispatch(IProvider::EVENT_FAILED, $dispatchEvent);
275
-
276
-			$this->publishEvent($user, 'twofactor_failed', [
277
-				'provider' => $provider->getDisplayName(),
278
-			]);
279
-		}
280
-		return $passed;
281
-	}
282
-
283
-	/**
284
-	 * Push a 2fa event the user's activity stream
285
-	 *
286
-	 * @param IUser $user
287
-	 * @param string $event
288
-	 * @param array $params
289
-	 */
290
-	private function publishEvent(IUser $user, string $event, array $params) {
291
-		$activity = $this->activityManager->generateEvent();
292
-		$activity->setApp('core')
293
-			->setType('security')
294
-			->setAuthor($user->getUID())
295
-			->setAffectedUser($user->getUID())
296
-			->setSubject($event, $params);
297
-		try {
298
-			$this->activityManager->publish($activity);
299
-		} catch (BadMethodCallException $e) {
300
-			$this->logger->warning('could not publish activity', ['app' => 'core']);
301
-			$this->logger->logException($e, ['app' => 'core']);
302
-		}
303
-	}
304
-
305
-	/**
306
-	 * Check if the currently logged in user needs to pass 2FA
307
-	 *
308
-	 * @param IUser $user the currently logged in user
309
-	 * @return boolean
310
-	 */
311
-	public function needsSecondFactor(IUser $user = null): bool {
312
-		if ($user === null) {
313
-			return false;
314
-		}
315
-
316
-		// If we are authenticated using an app password skip all this
317
-		if ($this->session->exists('app_password')) {
318
-			return false;
319
-		}
320
-
321
-		// First check if the session tells us we should do 2FA (99% case)
322
-		if (!$this->session->exists(self::SESSION_UID_KEY)) {
323
-
324
-			// Check if the session tells us it is 2FA authenticated already
325
-			if ($this->session->exists(self::SESSION_UID_DONE) &&
326
-				$this->session->get(self::SESSION_UID_DONE) === $user->getUID()) {
327
-				return false;
328
-			}
329
-
330
-			/*
50
+    const SESSION_UID_KEY = 'two_factor_auth_uid';
51
+    const SESSION_UID_DONE = 'two_factor_auth_passed';
52
+    const REMEMBER_LOGIN = 'two_factor_remember_login';
53
+    const BACKUP_CODES_PROVIDER_ID = 'backup_codes';
54
+
55
+    /** @var ProviderLoader */
56
+    private $providerLoader;
57
+
58
+    /** @var IRegistry */
59
+    private $providerRegistry;
60
+
61
+    /** @var MandatoryTwoFactor */
62
+    private $mandatoryTwoFactor;
63
+
64
+    /** @var ISession */
65
+    private $session;
66
+
67
+    /** @var IConfig */
68
+    private $config;
69
+
70
+    /** @var IManager */
71
+    private $activityManager;
72
+
73
+    /** @var ILogger */
74
+    private $logger;
75
+
76
+    /** @var TokenProvider */
77
+    private $tokenProvider;
78
+
79
+    /** @var ITimeFactory */
80
+    private $timeFactory;
81
+
82
+    /** @var EventDispatcherInterface */
83
+    private $dispatcher;
84
+
85
+    public function __construct(ProviderLoader $providerLoader,
86
+                                IRegistry $providerRegistry,
87
+                                MandatoryTwoFactor $mandatoryTwoFactor,
88
+                                ISession $session, IConfig $config,
89
+                                IManager $activityManager, ILogger $logger, TokenProvider $tokenProvider,
90
+                                ITimeFactory $timeFactory, EventDispatcherInterface $eventDispatcher) {
91
+        $this->providerLoader = $providerLoader;
92
+        $this->providerRegistry = $providerRegistry;
93
+        $this->mandatoryTwoFactor = $mandatoryTwoFactor;
94
+        $this->session = $session;
95
+        $this->config = $config;
96
+        $this->activityManager = $activityManager;
97
+        $this->logger = $logger;
98
+        $this->tokenProvider = $tokenProvider;
99
+        $this->timeFactory = $timeFactory;
100
+        $this->dispatcher = $eventDispatcher;
101
+    }
102
+
103
+    /**
104
+     * Determine whether the user must provide a second factor challenge
105
+     *
106
+     * @param IUser $user
107
+     * @return boolean
108
+     */
109
+    public function isTwoFactorAuthenticated(IUser $user): bool {
110
+        if ($this->mandatoryTwoFactor->isEnforcedFor($user)) {
111
+            return true;
112
+        }
113
+
114
+        $providerStates = $this->providerRegistry->getProviderStates($user);
115
+        $providers = $this->providerLoader->getProviders($user);
116
+        $fixedStates = $this->fixMissingProviderStates($providerStates, $providers, $user);
117
+        $enabled = array_filter($fixedStates);
118
+        $providerIds = array_keys($enabled);
119
+        $providerIdsWithoutBackupCodes = array_diff($providerIds, [self::BACKUP_CODES_PROVIDER_ID]);
120
+
121
+        return !empty($providerIdsWithoutBackupCodes);
122
+    }
123
+
124
+    /**
125
+     * Get a 2FA provider by its ID
126
+     *
127
+     * @param IUser $user
128
+     * @param string $challengeProviderId
129
+     * @return IProvider|null
130
+     */
131
+    public function getProvider(IUser $user, string $challengeProviderId) {
132
+        $providers = $this->getProviderSet($user)->getProviders();
133
+        return $providers[$challengeProviderId] ?? null;
134
+    }
135
+
136
+    /**
137
+     * @param IUser $user
138
+     * @return IActivatableAtLogin[]
139
+     * @throws Exception
140
+     */
141
+    public function getLoginSetupProviders(IUser $user): array {
142
+        $providers = $this->providerLoader->getProviders($user);
143
+        return array_filter($providers, function (IProvider $provider) {
144
+            return ($provider instanceof IActivatableAtLogin);
145
+        });
146
+    }
147
+
148
+    /**
149
+     * Check if the persistant mapping of enabled/disabled state of each available
150
+     * provider is missing an entry and add it to the registry in that case.
151
+     *
152
+     * @todo remove in Nextcloud 17 as by then all providers should have been updated
153
+     *
154
+     * @param string[] $providerStates
155
+     * @param IProvider[] $providers
156
+     * @param IUser $user
157
+     * @return string[] the updated $providerStates variable
158
+     */
159
+    private function fixMissingProviderStates(array $providerStates,
160
+        array $providers, IUser $user): array {
161
+
162
+        foreach ($providers as $provider) {
163
+            if (isset($providerStates[$provider->getId()])) {
164
+                // All good
165
+                continue;
166
+            }
167
+
168
+            $enabled = $provider->isTwoFactorAuthEnabledForUser($user);
169
+            if ($enabled) {
170
+                $this->providerRegistry->enableProviderFor($provider, $user);
171
+            } else {
172
+                $this->providerRegistry->disableProviderFor($provider, $user);
173
+            }
174
+            $providerStates[$provider->getId()] = $enabled;
175
+        }
176
+
177
+        return $providerStates;
178
+    }
179
+
180
+    /**
181
+     * @param array $states
182
+     * @param IProvider[] $providers
183
+     */
184
+    private function isProviderMissing(array $states, array $providers): bool {
185
+        $indexed = [];
186
+        foreach ($providers as $provider) {
187
+            $indexed[$provider->getId()] = $provider;
188
+        }
189
+
190
+        $missing = [];
191
+        foreach ($states as $providerId => $enabled) {
192
+            if (!$enabled) {
193
+                // Don't care
194
+                continue;
195
+            }
196
+
197
+            if (!isset($indexed[$providerId])) {
198
+                $missing[] = $providerId;
199
+                $this->logger->alert("two-factor auth provider '$providerId' failed to load",
200
+                    [
201
+                        'app' => 'core',
202
+                    ]);
203
+            }
204
+        }
205
+
206
+        if (!empty($missing)) {
207
+            // There was at least one provider missing
208
+            $this->logger->alert(count($missing) . " two-factor auth providers failed to load", ['app' => 'core']);
209
+
210
+            return true;
211
+        }
212
+
213
+        // If we reach this, there was not a single provider missing
214
+        return false;
215
+    }
216
+
217
+    /**
218
+     * Get the list of 2FA providers for the given user
219
+     *
220
+     * @param IUser $user
221
+     * @throws Exception
222
+     */
223
+    public function getProviderSet(IUser $user): ProviderSet {
224
+        $providerStates = $this->providerRegistry->getProviderStates($user);
225
+        $providers = $this->providerLoader->getProviders($user);
226
+
227
+        $fixedStates = $this->fixMissingProviderStates($providerStates, $providers, $user);
228
+        $isProviderMissing = $this->isProviderMissing($fixedStates, $providers);
229
+
230
+        $enabled = array_filter($providers, function (IProvider $provider) use ($fixedStates) {
231
+            return $fixedStates[$provider->getId()];
232
+        });
233
+        return new ProviderSet($enabled, $isProviderMissing);
234
+    }
235
+
236
+    /**
237
+     * Verify the given challenge
238
+     *
239
+     * @param string $providerId
240
+     * @param IUser $user
241
+     * @param string $challenge
242
+     * @return boolean
243
+     */
244
+    public function verifyChallenge(string $providerId, IUser $user, string $challenge): bool {
245
+        $provider = $this->getProvider($user, $providerId);
246
+        if ($provider === null) {
247
+            return false;
248
+        }
249
+
250
+        $passed = $provider->verifyChallenge($user, $challenge);
251
+        if ($passed) {
252
+            if ($this->session->get(self::REMEMBER_LOGIN) === true) {
253
+                // TODO: resolve cyclic dependency and use DI
254
+                \OC::$server->getUserSession()->createRememberMeToken($user);
255
+            }
256
+            $this->session->remove(self::SESSION_UID_KEY);
257
+            $this->session->remove(self::REMEMBER_LOGIN);
258
+            $this->session->set(self::SESSION_UID_DONE, $user->getUID());
259
+
260
+            // Clear token from db
261
+            $sessionId = $this->session->getId();
262
+            $token = $this->tokenProvider->getToken($sessionId);
263
+            $tokenId = $token->getId();
264
+            $this->config->deleteUserValue($user->getUID(), 'login_token_2fa', $tokenId);
265
+
266
+            $dispatchEvent = new GenericEvent($user, ['provider' => $provider->getDisplayName()]);
267
+            $this->dispatcher->dispatch(IProvider::EVENT_SUCCESS, $dispatchEvent);
268
+
269
+            $this->publishEvent($user, 'twofactor_success', [
270
+                'provider' => $provider->getDisplayName(),
271
+            ]);
272
+        } else {
273
+            $dispatchEvent = new GenericEvent($user, ['provider' => $provider->getDisplayName()]);
274
+            $this->dispatcher->dispatch(IProvider::EVENT_FAILED, $dispatchEvent);
275
+
276
+            $this->publishEvent($user, 'twofactor_failed', [
277
+                'provider' => $provider->getDisplayName(),
278
+            ]);
279
+        }
280
+        return $passed;
281
+    }
282
+
283
+    /**
284
+     * Push a 2fa event the user's activity stream
285
+     *
286
+     * @param IUser $user
287
+     * @param string $event
288
+     * @param array $params
289
+     */
290
+    private function publishEvent(IUser $user, string $event, array $params) {
291
+        $activity = $this->activityManager->generateEvent();
292
+        $activity->setApp('core')
293
+            ->setType('security')
294
+            ->setAuthor($user->getUID())
295
+            ->setAffectedUser($user->getUID())
296
+            ->setSubject($event, $params);
297
+        try {
298
+            $this->activityManager->publish($activity);
299
+        } catch (BadMethodCallException $e) {
300
+            $this->logger->warning('could not publish activity', ['app' => 'core']);
301
+            $this->logger->logException($e, ['app' => 'core']);
302
+        }
303
+    }
304
+
305
+    /**
306
+     * Check if the currently logged in user needs to pass 2FA
307
+     *
308
+     * @param IUser $user the currently logged in user
309
+     * @return boolean
310
+     */
311
+    public function needsSecondFactor(IUser $user = null): bool {
312
+        if ($user === null) {
313
+            return false;
314
+        }
315
+
316
+        // If we are authenticated using an app password skip all this
317
+        if ($this->session->exists('app_password')) {
318
+            return false;
319
+        }
320
+
321
+        // First check if the session tells us we should do 2FA (99% case)
322
+        if (!$this->session->exists(self::SESSION_UID_KEY)) {
323
+
324
+            // Check if the session tells us it is 2FA authenticated already
325
+            if ($this->session->exists(self::SESSION_UID_DONE) &&
326
+                $this->session->get(self::SESSION_UID_DONE) === $user->getUID()) {
327
+                return false;
328
+            }
329
+
330
+            /*
331 331
 			 * If the session is expired check if we are not logged in by a token
332 332
 			 * that still needs 2FA auth
333 333
 			 */
334
-			try {
335
-				$sessionId = $this->session->getId();
336
-				$token = $this->tokenProvider->getToken($sessionId);
337
-				$tokenId = $token->getId();
338
-				$tokensNeeding2FA = $this->config->getUserKeys($user->getUID(), 'login_token_2fa');
339
-
340
-				if (!\in_array($tokenId, $tokensNeeding2FA, true)) {
341
-					$this->session->set(self::SESSION_UID_DONE, $user->getUID());
342
-					return false;
343
-				}
344
-			} catch (InvalidTokenException $e) {
345
-			}
346
-		}
347
-
348
-		if (!$this->isTwoFactorAuthenticated($user)) {
349
-			// There is no second factor any more -> let the user pass
350
-			//   This prevents infinite redirect loops when a user is about
351
-			//   to solve the 2FA challenge, and the provider app is
352
-			//   disabled the same time
353
-			$this->session->remove(self::SESSION_UID_KEY);
354
-
355
-			$keys = $this->config->getUserKeys($user->getUID(), 'login_token_2fa');
356
-			foreach ($keys as $key) {
357
-				$this->config->deleteUserValue($user->getUID(), 'login_token_2fa', $key);
358
-			}
359
-			return false;
360
-		}
361
-
362
-		return true;
363
-	}
364
-
365
-	/**
366
-	 * Prepare the 2FA login
367
-	 *
368
-	 * @param IUser $user
369
-	 * @param boolean $rememberMe
370
-	 */
371
-	public function prepareTwoFactorLogin(IUser $user, bool $rememberMe) {
372
-		$this->session->set(self::SESSION_UID_KEY, $user->getUID());
373
-		$this->session->set(self::REMEMBER_LOGIN, $rememberMe);
374
-
375
-		$id = $this->session->getId();
376
-		$token = $this->tokenProvider->getToken($id);
377
-		$this->config->setUserValue($user->getUID(), 'login_token_2fa', $token->getId(), $this->timeFactory->getTime());
378
-	}
379
-
380
-	public function clearTwoFactorPending(string $userId) {
381
-		$tokensNeeding2FA = $this->config->getUserKeys($userId, 'login_token_2fa');
382
-
383
-		foreach ($tokensNeeding2FA as $tokenId) {
384
-			$this->tokenProvider->invalidateTokenById($userId, $tokenId);
385
-		}
386
-	}
334
+            try {
335
+                $sessionId = $this->session->getId();
336
+                $token = $this->tokenProvider->getToken($sessionId);
337
+                $tokenId = $token->getId();
338
+                $tokensNeeding2FA = $this->config->getUserKeys($user->getUID(), 'login_token_2fa');
339
+
340
+                if (!\in_array($tokenId, $tokensNeeding2FA, true)) {
341
+                    $this->session->set(self::SESSION_UID_DONE, $user->getUID());
342
+                    return false;
343
+                }
344
+            } catch (InvalidTokenException $e) {
345
+            }
346
+        }
347
+
348
+        if (!$this->isTwoFactorAuthenticated($user)) {
349
+            // There is no second factor any more -> let the user pass
350
+            //   This prevents infinite redirect loops when a user is about
351
+            //   to solve the 2FA challenge, and the provider app is
352
+            //   disabled the same time
353
+            $this->session->remove(self::SESSION_UID_KEY);
354
+
355
+            $keys = $this->config->getUserKeys($user->getUID(), 'login_token_2fa');
356
+            foreach ($keys as $key) {
357
+                $this->config->deleteUserValue($user->getUID(), 'login_token_2fa', $key);
358
+            }
359
+            return false;
360
+        }
361
+
362
+        return true;
363
+    }
364
+
365
+    /**
366
+     * Prepare the 2FA login
367
+     *
368
+     * @param IUser $user
369
+     * @param boolean $rememberMe
370
+     */
371
+    public function prepareTwoFactorLogin(IUser $user, bool $rememberMe) {
372
+        $this->session->set(self::SESSION_UID_KEY, $user->getUID());
373
+        $this->session->set(self::REMEMBER_LOGIN, $rememberMe);
374
+
375
+        $id = $this->session->getId();
376
+        $token = $this->tokenProvider->getToken($id);
377
+        $this->config->setUserValue($user->getUID(), 'login_token_2fa', $token->getId(), $this->timeFactory->getTime());
378
+    }
379
+
380
+    public function clearTwoFactorPending(string $userId) {
381
+        $tokensNeeding2FA = $this->config->getUserKeys($userId, 'login_token_2fa');
382
+
383
+        foreach ($tokensNeeding2FA as $tokenId) {
384
+            $this->tokenProvider->invalidateTokenById($userId, $tokenId);
385
+        }
386
+    }
387 387
 
388 388
 }
Please login to merge, or discard this patch.
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -140,7 +140,7 @@  discard block
 block discarded – undo
140 140
 	 */
141 141
 	public function getLoginSetupProviders(IUser $user): array {
142 142
 		$providers = $this->providerLoader->getProviders($user);
143
-		return array_filter($providers, function (IProvider $provider) {
143
+		return array_filter($providers, function(IProvider $provider) {
144 144
 			return ($provider instanceof IActivatableAtLogin);
145 145
 		});
146 146
 	}
@@ -205,7 +205,7 @@  discard block
 block discarded – undo
205 205
 
206 206
 		if (!empty($missing)) {
207 207
 			// There was at least one provider missing
208
-			$this->logger->alert(count($missing) . " two-factor auth providers failed to load", ['app' => 'core']);
208
+			$this->logger->alert(count($missing)." two-factor auth providers failed to load", ['app' => 'core']);
209 209
 
210 210
 			return true;
211 211
 		}
@@ -227,7 +227,7 @@  discard block
 block discarded – undo
227 227
 		$fixedStates = $this->fixMissingProviderStates($providerStates, $providers, $user);
228 228
 		$isProviderMissing = $this->isProviderMissing($fixedStates, $providers);
229 229
 
230
-		$enabled = array_filter($providers, function (IProvider $provider) use ($fixedStates) {
230
+		$enabled = array_filter($providers, function(IProvider $provider) use ($fixedStates) {
231 231
 			return $fixedStates[$provider->getId()];
232 232
 		});
233 233
 		return new ProviderSet($enabled, $isProviderMissing);
Please login to merge, or discard this patch.