Completed
Push — stable13 ( 2d5d8b...1a016f )
by Roeland
17:00
created
lib/autoloader.php 2 patches
Indentation   +145 added lines, -145 removed lines patch added patch discarded remove patch
@@ -35,149 +35,149 @@
 block discarded – undo
35 35
 use \OCP\AutoloadNotAllowedException;
36 36
 
37 37
 class Autoloader {
38
-	/** @var bool */
39
-	private $useGlobalClassPath = true;
40
-	/** @var array */
41
-	private $validRoots = [];
42
-
43
-	/**
44
-	 * Optional low-latency memory cache for class to path mapping.
45
-	 *
46
-	 * @var \OC\Memcache\Cache
47
-	 */
48
-	protected $memoryCache;
49
-
50
-	/**
51
-	 * Autoloader constructor.
52
-	 *
53
-	 * @param string[] $validRoots
54
-	 */
55
-	public function __construct(array $validRoots) {
56
-		foreach ($validRoots as $root) {
57
-			$this->validRoots[$root] = true;
58
-		}
59
-	}
60
-
61
-	/**
62
-	 * Add a path to the list of valid php roots for auto loading
63
-	 *
64
-	 * @param string $root
65
-	 */
66
-	public function addValidRoot($root) {
67
-		$root = stream_resolve_include_path($root);
68
-		$this->validRoots[$root] = true;
69
-	}
70
-
71
-	/**
72
-	 * disable the usage of the global classpath \OC::$CLASSPATH
73
-	 */
74
-	public function disableGlobalClassPath() {
75
-		$this->useGlobalClassPath = false;
76
-	}
77
-
78
-	/**
79
-	 * enable the usage of the global classpath \OC::$CLASSPATH
80
-	 */
81
-	public function enableGlobalClassPath() {
82
-		$this->useGlobalClassPath = true;
83
-	}
84
-
85
-	/**
86
-	 * get the possible paths for a class
87
-	 *
88
-	 * @param string $class
89
-	 * @return array|bool an array of possible paths or false if the class is not part of ownCloud
90
-	 */
91
-	public function findClass($class) {
92
-		$class = trim($class, '\\');
93
-
94
-		$paths = array();
95
-		if ($this->useGlobalClassPath && array_key_exists($class, \OC::$CLASSPATH)) {
96
-			$paths[] = \OC::$CLASSPATH[$class];
97
-			/**
98
-			 * @TODO: Remove this when necessary
99
-			 * Remove "apps/" from inclusion path for smooth migration to multi app dir
100
-			 */
101
-			if (strpos(\OC::$CLASSPATH[$class], 'apps/') === 0) {
102
-				\OCP\Util::writeLog('core', 'include path for class "' . $class . '" starts with "apps/"', \OCP\Util::DEBUG);
103
-				$paths[] = str_replace('apps/', '', \OC::$CLASSPATH[$class]);
104
-			}
105
-		} elseif (strpos($class, 'OC_') === 0) {
106
-			$paths[] = \OC::$SERVERROOT . '/lib/private/legacy/' . strtolower(str_replace('_', '/', substr($class, 3)) . '.php');
107
-		} elseif (strpos($class, 'OCA\\') === 0) {
108
-			list(, $app, $rest) = explode('\\', $class, 3);
109
-			$app = strtolower($app);
110
-			$appPath = \OC_App::getAppPath($app);
111
-			if ($appPath && stream_resolve_include_path($appPath)) {
112
-				$paths[] = $appPath . '/' . strtolower(str_replace('\\', '/', $rest) . '.php');
113
-				// If not found in the root of the app directory, insert '/lib' after app id and try again.
114
-				$paths[] = $appPath . '/lib/' . strtolower(str_replace('\\', '/', $rest) . '.php');
115
-			}
116
-		} elseif ($class === 'Test\\TestCase') {
117
-			// This File is considered public API, so we make sure that the class
118
-			// can still be loaded, although the PSR-4 paths have not been loaded.
119
-			$paths[] = \OC::$SERVERROOT . '/tests/lib/TestCase.php';
120
-		}
121
-		return $paths;
122
-	}
123
-
124
-	/**
125
-	 * @param string $fullPath
126
-	 * @return bool
127
-	 */
128
-	protected function isValidPath($fullPath) {
129
-		foreach ($this->validRoots as $root => $true) {
130
-			if (substr($fullPath, 0, strlen($root) + 1) === $root . '/') {
131
-				return true;
132
-			}
133
-		}
134
-		throw new AutoloadNotAllowedException($fullPath);
135
-	}
136
-
137
-	/**
138
-	 * Load the specified class
139
-	 *
140
-	 * @param string $class
141
-	 * @return bool
142
-	 */
143
-	public function load($class) {
144
-		$pathsToRequire = null;
145
-		if ($this->memoryCache) {
146
-			$pathsToRequire = $this->memoryCache->get($class);
147
-		}
148
-
149
-		if(class_exists($class, false)) {
150
-			return false;
151
-		}
152
-
153
-		if (!is_array($pathsToRequire)) {
154
-			// No cache or cache miss
155
-			$pathsToRequire = array();
156
-			foreach ($this->findClass($class) as $path) {
157
-				$fullPath = stream_resolve_include_path($path);
158
-				if ($fullPath && $this->isValidPath($fullPath)) {
159
-					$pathsToRequire[] = $fullPath;
160
-				}
161
-			}
162
-
163
-			if ($this->memoryCache) {
164
-				$this->memoryCache->set($class, $pathsToRequire, 60); // cache 60 sec
165
-			}
166
-		}
167
-
168
-		foreach ($pathsToRequire as $fullPath) {
169
-			require_once $fullPath;
170
-		}
171
-
172
-		return false;
173
-	}
174
-
175
-	/**
176
-	 * Sets the optional low-latency cache for class to path mapping.
177
-	 *
178
-	 * @param \OC\Memcache\Cache $memoryCache Instance of memory cache.
179
-	 */
180
-	public function setMemoryCache(\OC\Memcache\Cache $memoryCache = null) {
181
-		$this->memoryCache = $memoryCache;
182
-	}
38
+    /** @var bool */
39
+    private $useGlobalClassPath = true;
40
+    /** @var array */
41
+    private $validRoots = [];
42
+
43
+    /**
44
+     * Optional low-latency memory cache for class to path mapping.
45
+     *
46
+     * @var \OC\Memcache\Cache
47
+     */
48
+    protected $memoryCache;
49
+
50
+    /**
51
+     * Autoloader constructor.
52
+     *
53
+     * @param string[] $validRoots
54
+     */
55
+    public function __construct(array $validRoots) {
56
+        foreach ($validRoots as $root) {
57
+            $this->validRoots[$root] = true;
58
+        }
59
+    }
60
+
61
+    /**
62
+     * Add a path to the list of valid php roots for auto loading
63
+     *
64
+     * @param string $root
65
+     */
66
+    public function addValidRoot($root) {
67
+        $root = stream_resolve_include_path($root);
68
+        $this->validRoots[$root] = true;
69
+    }
70
+
71
+    /**
72
+     * disable the usage of the global classpath \OC::$CLASSPATH
73
+     */
74
+    public function disableGlobalClassPath() {
75
+        $this->useGlobalClassPath = false;
76
+    }
77
+
78
+    /**
79
+     * enable the usage of the global classpath \OC::$CLASSPATH
80
+     */
81
+    public function enableGlobalClassPath() {
82
+        $this->useGlobalClassPath = true;
83
+    }
84
+
85
+    /**
86
+     * get the possible paths for a class
87
+     *
88
+     * @param string $class
89
+     * @return array|bool an array of possible paths or false if the class is not part of ownCloud
90
+     */
91
+    public function findClass($class) {
92
+        $class = trim($class, '\\');
93
+
94
+        $paths = array();
95
+        if ($this->useGlobalClassPath && array_key_exists($class, \OC::$CLASSPATH)) {
96
+            $paths[] = \OC::$CLASSPATH[$class];
97
+            /**
98
+             * @TODO: Remove this when necessary
99
+             * Remove "apps/" from inclusion path for smooth migration to multi app dir
100
+             */
101
+            if (strpos(\OC::$CLASSPATH[$class], 'apps/') === 0) {
102
+                \OCP\Util::writeLog('core', 'include path for class "' . $class . '" starts with "apps/"', \OCP\Util::DEBUG);
103
+                $paths[] = str_replace('apps/', '', \OC::$CLASSPATH[$class]);
104
+            }
105
+        } elseif (strpos($class, 'OC_') === 0) {
106
+            $paths[] = \OC::$SERVERROOT . '/lib/private/legacy/' . strtolower(str_replace('_', '/', substr($class, 3)) . '.php');
107
+        } elseif (strpos($class, 'OCA\\') === 0) {
108
+            list(, $app, $rest) = explode('\\', $class, 3);
109
+            $app = strtolower($app);
110
+            $appPath = \OC_App::getAppPath($app);
111
+            if ($appPath && stream_resolve_include_path($appPath)) {
112
+                $paths[] = $appPath . '/' . strtolower(str_replace('\\', '/', $rest) . '.php');
113
+                // If not found in the root of the app directory, insert '/lib' after app id and try again.
114
+                $paths[] = $appPath . '/lib/' . strtolower(str_replace('\\', '/', $rest) . '.php');
115
+            }
116
+        } elseif ($class === 'Test\\TestCase') {
117
+            // This File is considered public API, so we make sure that the class
118
+            // can still be loaded, although the PSR-4 paths have not been loaded.
119
+            $paths[] = \OC::$SERVERROOT . '/tests/lib/TestCase.php';
120
+        }
121
+        return $paths;
122
+    }
123
+
124
+    /**
125
+     * @param string $fullPath
126
+     * @return bool
127
+     */
128
+    protected function isValidPath($fullPath) {
129
+        foreach ($this->validRoots as $root => $true) {
130
+            if (substr($fullPath, 0, strlen($root) + 1) === $root . '/') {
131
+                return true;
132
+            }
133
+        }
134
+        throw new AutoloadNotAllowedException($fullPath);
135
+    }
136
+
137
+    /**
138
+     * Load the specified class
139
+     *
140
+     * @param string $class
141
+     * @return bool
142
+     */
143
+    public function load($class) {
144
+        $pathsToRequire = null;
145
+        if ($this->memoryCache) {
146
+            $pathsToRequire = $this->memoryCache->get($class);
147
+        }
148
+
149
+        if(class_exists($class, false)) {
150
+            return false;
151
+        }
152
+
153
+        if (!is_array($pathsToRequire)) {
154
+            // No cache or cache miss
155
+            $pathsToRequire = array();
156
+            foreach ($this->findClass($class) as $path) {
157
+                $fullPath = stream_resolve_include_path($path);
158
+                if ($fullPath && $this->isValidPath($fullPath)) {
159
+                    $pathsToRequire[] = $fullPath;
160
+                }
161
+            }
162
+
163
+            if ($this->memoryCache) {
164
+                $this->memoryCache->set($class, $pathsToRequire, 60); // cache 60 sec
165
+            }
166
+        }
167
+
168
+        foreach ($pathsToRequire as $fullPath) {
169
+            require_once $fullPath;
170
+        }
171
+
172
+        return false;
173
+    }
174
+
175
+    /**
176
+     * Sets the optional low-latency cache for class to path mapping.
177
+     *
178
+     * @param \OC\Memcache\Cache $memoryCache Instance of memory cache.
179
+     */
180
+    public function setMemoryCache(\OC\Memcache\Cache $memoryCache = null) {
181
+        $this->memoryCache = $memoryCache;
182
+    }
183 183
 }
Please login to merge, or discard this patch.
Spacing   +7 added lines, -7 removed lines patch added patch discarded remove patch
@@ -99,24 +99,24 @@  discard block
 block discarded – undo
99 99
 			 * Remove "apps/" from inclusion path for smooth migration to multi app dir
100 100
 			 */
101 101
 			if (strpos(\OC::$CLASSPATH[$class], 'apps/') === 0) {
102
-				\OCP\Util::writeLog('core', 'include path for class "' . $class . '" starts with "apps/"', \OCP\Util::DEBUG);
102
+				\OCP\Util::writeLog('core', 'include path for class "'.$class.'" starts with "apps/"', \OCP\Util::DEBUG);
103 103
 				$paths[] = str_replace('apps/', '', \OC::$CLASSPATH[$class]);
104 104
 			}
105 105
 		} elseif (strpos($class, 'OC_') === 0) {
106
-			$paths[] = \OC::$SERVERROOT . '/lib/private/legacy/' . strtolower(str_replace('_', '/', substr($class, 3)) . '.php');
106
+			$paths[] = \OC::$SERVERROOT.'/lib/private/legacy/'.strtolower(str_replace('_', '/', substr($class, 3)).'.php');
107 107
 		} elseif (strpos($class, 'OCA\\') === 0) {
108 108
 			list(, $app, $rest) = explode('\\', $class, 3);
109 109
 			$app = strtolower($app);
110 110
 			$appPath = \OC_App::getAppPath($app);
111 111
 			if ($appPath && stream_resolve_include_path($appPath)) {
112
-				$paths[] = $appPath . '/' . strtolower(str_replace('\\', '/', $rest) . '.php');
112
+				$paths[] = $appPath.'/'.strtolower(str_replace('\\', '/', $rest).'.php');
113 113
 				// If not found in the root of the app directory, insert '/lib' after app id and try again.
114
-				$paths[] = $appPath . '/lib/' . strtolower(str_replace('\\', '/', $rest) . '.php');
114
+				$paths[] = $appPath.'/lib/'.strtolower(str_replace('\\', '/', $rest).'.php');
115 115
 			}
116 116
 		} elseif ($class === 'Test\\TestCase') {
117 117
 			// This File is considered public API, so we make sure that the class
118 118
 			// can still be loaded, although the PSR-4 paths have not been loaded.
119
-			$paths[] = \OC::$SERVERROOT . '/tests/lib/TestCase.php';
119
+			$paths[] = \OC::$SERVERROOT.'/tests/lib/TestCase.php';
120 120
 		}
121 121
 		return $paths;
122 122
 	}
@@ -127,7 +127,7 @@  discard block
 block discarded – undo
127 127
 	 */
128 128
 	protected function isValidPath($fullPath) {
129 129
 		foreach ($this->validRoots as $root => $true) {
130
-			if (substr($fullPath, 0, strlen($root) + 1) === $root . '/') {
130
+			if (substr($fullPath, 0, strlen($root) + 1) === $root.'/') {
131 131
 				return true;
132 132
 			}
133 133
 		}
@@ -146,7 +146,7 @@  discard block
 block discarded – undo
146 146
 			$pathsToRequire = $this->memoryCache->get($class);
147 147
 		}
148 148
 
149
-		if(class_exists($class, false)) {
149
+		if (class_exists($class, false)) {
150 150
 			return false;
151 151
 		}
152 152
 
Please login to merge, or discard this patch.
lib/private/Contacts/ContactsMenu/Entry.php 1 patch
Indentation   +136 added lines, -136 removed lines patch added patch discarded remove patch
@@ -29,141 +29,141 @@
 block discarded – undo
29 29
 
30 30
 class Entry implements IEntry {
31 31
 
32
-	/** @var string|int|null */
33
-	private $id = null;
34
-
35
-	/** @var string */
36
-	private $fullName = '';
37
-
38
-	/** @var string[] */
39
-	private $emailAddresses = [];
40
-
41
-	/** @var string|null */
42
-	private $avatar;
43
-
44
-	/** @var IAction[] */
45
-	private $actions = [];
46
-
47
-	/** @var array */
48
-	private $properties = [];
49
-
50
-	/**
51
-	 * @param string $id
52
-	 */
53
-	public function setId($id) {
54
-		$this->id = $id;
55
-	}
56
-
57
-	/**
58
-	 * @param string $displayName
59
-	 */
60
-	public function setFullName($displayName) {
61
-		$this->fullName = $displayName;
62
-	}
63
-
64
-	/**
65
-	 * @return string
66
-	 */
67
-	public function getFullName() {
68
-		return $this->fullName;
69
-	}
70
-
71
-	/**
72
-	 * @param string $address
73
-	 */
74
-	public function addEMailAddress($address) {
75
-		$this->emailAddresses[] = $address;
76
-	}
77
-
78
-	/**
79
-	 * @return string
80
-	 */
81
-	public function getEMailAddresses() {
82
-		return $this->emailAddresses;
83
-	}
84
-
85
-	/**
86
-	 * @param string $avatar
87
-	 */
88
-	public function setAvatar($avatar) {
89
-		$this->avatar = $avatar;
90
-	}
91
-
92
-	/**
93
-	 * @return string
94
-	 */
95
-	public function getAvatar() {
96
-		return $this->avatar;
97
-	}
98
-
99
-	/**
100
-	 * @param IAction $action
101
-	 */
102
-	public function addAction(IAction $action) {
103
-		$this->actions[] = $action;
104
-		$this->sortActions();
105
-	}
106
-
107
-	/**
108
-	 * @return IAction[]
109
-	 */
110
-	public function getActions() {
111
-		return $this->actions;
112
-	}
113
-
114
-	/**
115
-	 * sort the actions by priority and name
116
-	 */
117
-	private function sortActions() {
118
-		usort($this->actions, function(IAction $action1, IAction $action2) {
119
-			$prio1 = $action1->getPriority();
120
-			$prio2 = $action2->getPriority();
121
-
122
-			if ($prio1 === $prio2) {
123
-				// Ascending order for same priority
124
-				return strcasecmp($action1->getName(), $action2->getName());
125
-			}
126
-
127
-			// Descending order when priority differs
128
-			return $prio2 - $prio1;
129
-		});
130
-	}
131
-
132
-	/**
133
-	 * @param array $contact key-value array containing additional properties
134
-	 */
135
-	public function setProperties(array $contact) {
136
-		$this->properties = $contact;
137
-	}
138
-
139
-	/**
140
-	 * @param string $key
141
-	 * @return mixed
142
-	 */
143
-	public function getProperty($key) {
144
-		if (!isset($this->properties[$key])) {
145
-			return null;
146
-		}
147
-		return $this->properties[$key];
148
-	}
149
-
150
-	/**
151
-	 * @return array
152
-	 */
153
-	public function jsonSerialize() {
154
-		$topAction = !empty($this->actions) ? $this->actions[0]->jsonSerialize() : null;
155
-		$otherActions = array_map(function(IAction $action) {
156
-			return $action->jsonSerialize();
157
-		}, array_slice($this->actions, 1));
158
-
159
-		return [
160
-			'id' => $this->id,
161
-			'fullName' => $this->fullName,
162
-			'avatar' => $this->getAvatar(),
163
-			'topAction' => $topAction,
164
-			'actions' => $otherActions,
165
-			'lastMessage' => '',
166
-		];
167
-	}
32
+    /** @var string|int|null */
33
+    private $id = null;
34
+
35
+    /** @var string */
36
+    private $fullName = '';
37
+
38
+    /** @var string[] */
39
+    private $emailAddresses = [];
40
+
41
+    /** @var string|null */
42
+    private $avatar;
43
+
44
+    /** @var IAction[] */
45
+    private $actions = [];
46
+
47
+    /** @var array */
48
+    private $properties = [];
49
+
50
+    /**
51
+     * @param string $id
52
+     */
53
+    public function setId($id) {
54
+        $this->id = $id;
55
+    }
56
+
57
+    /**
58
+     * @param string $displayName
59
+     */
60
+    public function setFullName($displayName) {
61
+        $this->fullName = $displayName;
62
+    }
63
+
64
+    /**
65
+     * @return string
66
+     */
67
+    public function getFullName() {
68
+        return $this->fullName;
69
+    }
70
+
71
+    /**
72
+     * @param string $address
73
+     */
74
+    public function addEMailAddress($address) {
75
+        $this->emailAddresses[] = $address;
76
+    }
77
+
78
+    /**
79
+     * @return string
80
+     */
81
+    public function getEMailAddresses() {
82
+        return $this->emailAddresses;
83
+    }
84
+
85
+    /**
86
+     * @param string $avatar
87
+     */
88
+    public function setAvatar($avatar) {
89
+        $this->avatar = $avatar;
90
+    }
91
+
92
+    /**
93
+     * @return string
94
+     */
95
+    public function getAvatar() {
96
+        return $this->avatar;
97
+    }
98
+
99
+    /**
100
+     * @param IAction $action
101
+     */
102
+    public function addAction(IAction $action) {
103
+        $this->actions[] = $action;
104
+        $this->sortActions();
105
+    }
106
+
107
+    /**
108
+     * @return IAction[]
109
+     */
110
+    public function getActions() {
111
+        return $this->actions;
112
+    }
113
+
114
+    /**
115
+     * sort the actions by priority and name
116
+     */
117
+    private function sortActions() {
118
+        usort($this->actions, function(IAction $action1, IAction $action2) {
119
+            $prio1 = $action1->getPriority();
120
+            $prio2 = $action2->getPriority();
121
+
122
+            if ($prio1 === $prio2) {
123
+                // Ascending order for same priority
124
+                return strcasecmp($action1->getName(), $action2->getName());
125
+            }
126
+
127
+            // Descending order when priority differs
128
+            return $prio2 - $prio1;
129
+        });
130
+    }
131
+
132
+    /**
133
+     * @param array $contact key-value array containing additional properties
134
+     */
135
+    public function setProperties(array $contact) {
136
+        $this->properties = $contact;
137
+    }
138
+
139
+    /**
140
+     * @param string $key
141
+     * @return mixed
142
+     */
143
+    public function getProperty($key) {
144
+        if (!isset($this->properties[$key])) {
145
+            return null;
146
+        }
147
+        return $this->properties[$key];
148
+    }
149
+
150
+    /**
151
+     * @return array
152
+     */
153
+    public function jsonSerialize() {
154
+        $topAction = !empty($this->actions) ? $this->actions[0]->jsonSerialize() : null;
155
+        $otherActions = array_map(function(IAction $action) {
156
+            return $action->jsonSerialize();
157
+        }, array_slice($this->actions, 1));
158
+
159
+        return [
160
+            'id' => $this->id,
161
+            'fullName' => $this->fullName,
162
+            'avatar' => $this->getAvatar(),
163
+            'topAction' => $topAction,
164
+            'actions' => $otherActions,
165
+            'lastMessage' => '',
166
+        ];
167
+    }
168 168
 
169 169
 }
Please login to merge, or discard this patch.
lib/public/Contacts/ContactsMenu/IEntry.php 1 patch
Indentation   +28 added lines, -28 removed lines patch added patch discarded remove patch
@@ -31,36 +31,36 @@
 block discarded – undo
31 31
  */
32 32
 interface IEntry extends JsonSerializable {
33 33
 
34
-	/**
35
-	 * @since 12.0
36
-	 * @return string
37
-	 */
38
-	public function getFullName();
34
+    /**
35
+     * @since 12.0
36
+     * @return string
37
+     */
38
+    public function getFullName();
39 39
 
40
-	/**
41
-	 * @since 12.0
42
-	 * @return string[]
43
-	 */
44
-	public function getEMailAddresses();
40
+    /**
41
+     * @since 12.0
42
+     * @return string[]
43
+     */
44
+    public function getEMailAddresses();
45 45
 
46
-	/**
47
-	 * @since 12.0
48
-	 * @return string|null image URI
49
-	 */
50
-	public function getAvatar();
46
+    /**
47
+     * @since 12.0
48
+     * @return string|null image URI
49
+     */
50
+    public function getAvatar();
51 51
 
52
-	/**
53
-	 * @since 12.0
54
-	 * @param IAction $action an action to show in the contacts menu
55
-	 */
56
-	public function addAction(IAction $action);
52
+    /**
53
+     * @since 12.0
54
+     * @param IAction $action an action to show in the contacts menu
55
+     */
56
+    public function addAction(IAction $action);
57 57
 
58
-	/**
59
-	 * Get an arbitrary property from the contact
60
-	 *
61
-	 * @since 12.0
62
-	 * @param string $key
63
-	 * @return mixed the value of the property or null
64
-	 */
65
-	public function getProperty($key);
58
+    /**
59
+     * Get an arbitrary property from the contact
60
+     *
61
+     * @since 12.0
62
+     * @param string $key
63
+     * @return mixed the value of the property or null
64
+     */
65
+    public function getProperty($key);
66 66
 }
Please login to merge, or discard this patch.
lib/private/IntegrityCheck/Checker.php 2 patches
Spacing   +47 added lines, -47 removed lines patch added patch discarded remove patch
@@ -96,7 +96,7 @@  discard block
 block discarded – undo
96 96
 	 * @return bool
97 97
 	 */
98 98
 	public function isCodeCheckEnforced() {
99
-		$notSignedChannels = [ '', 'git'];
99
+		$notSignedChannels = ['', 'git'];
100 100
 		if (in_array($this->environmentHelper->getChannel(), $notSignedChannels, true)) {
101 101
 			return false;
102 102
 		}
@@ -131,7 +131,7 @@  discard block
 block discarded – undo
131 131
 			$folderToIterate,
132 132
 			\RecursiveDirectoryIterator::SKIP_DOTS
133 133
 		);
134
-		if($root === '') {
134
+		if ($root === '') {
135 135
 			$root = \OC::$SERVERROOT;
136 136
 		}
137 137
 		$root = rtrim($root, '/');
@@ -160,9 +160,9 @@  discard block
 block discarded – undo
160 160
 		$tmpFolder = '';
161 161
 
162 162
 		$baseDirectoryLength = strlen($path);
163
-		foreach($iterator as $filename => $data) {
163
+		foreach ($iterator as $filename => $data) {
164 164
 			/** @var \DirectoryIterator $data */
165
-			if($data->isDir()) {
165
+			if ($data->isDir()) {
166 166
 				continue;
167 167
 			}
168 168
 
@@ -170,11 +170,11 @@  discard block
 block discarded – undo
170 170
 			$relativeFileName = ltrim($relativeFileName, '/');
171 171
 
172 172
 			// Exclude signature.json files in the appinfo and root folder
173
-			if($relativeFileName === 'appinfo/signature.json') {
173
+			if ($relativeFileName === 'appinfo/signature.json') {
174 174
 				continue;
175 175
 			}
176 176
 			// Exclude signature.json files in the appinfo and core folder
177
-			if($relativeFileName === 'core/signature.json') {
177
+			if ($relativeFileName === 'core/signature.json') {
178 178
 				continue;
179 179
 			}
180 180
 
@@ -183,18 +183,18 @@  discard block
 block discarded – undo
183 183
 			// to ensure that this will not lead to false positives this will
184 184
 			// copy the file to a temporary folder and reset it to the default
185 185
 			// values.
186
-			if($filename === $this->environmentHelper->getServerRoot() . '/.htaccess'
187
-				|| $filename === $this->environmentHelper->getServerRoot() . '/.user.ini') {
186
+			if ($filename === $this->environmentHelper->getServerRoot().'/.htaccess'
187
+				|| $filename === $this->environmentHelper->getServerRoot().'/.user.ini') {
188 188
 
189
-				if(!$copiedWebserverSettingFiles) {
189
+				if (!$copiedWebserverSettingFiles) {
190 190
 					$tmpFolder = rtrim($this->tempManager->getTemporaryFolder(), '/');
191
-					copy($this->environmentHelper->getServerRoot() . '/.htaccess', $tmpFolder . '/.htaccess');
192
-					copy($this->environmentHelper->getServerRoot() . '/.user.ini', $tmpFolder . '/.user.ini');
191
+					copy($this->environmentHelper->getServerRoot().'/.htaccess', $tmpFolder.'/.htaccess');
192
+					copy($this->environmentHelper->getServerRoot().'/.user.ini', $tmpFolder.'/.user.ini');
193 193
 					\OC_Files::setUploadLimit(
194 194
 						\OCP\Util::computerFileSize('511MB'),
195 195
 						[
196
-							'.htaccess' => $tmpFolder . '/.htaccess',
197
-							'.user.ini' => $tmpFolder . '/.user.ini',
196
+							'.htaccess' => $tmpFolder.'/.htaccess',
197
+							'.user.ini' => $tmpFolder.'/.user.ini',
198 198
 						]
199 199
 					);
200 200
 				}
@@ -202,8 +202,8 @@  discard block
 block discarded – undo
202 202
 
203 203
 			// The .user.ini file can contain custom modifications to the file size
204 204
 			// as well.
205
-			if($filename === $this->environmentHelper->getServerRoot() . '/.user.ini') {
206
-				$fileContent = file_get_contents($tmpFolder . '/.user.ini');
205
+			if ($filename === $this->environmentHelper->getServerRoot().'/.user.ini') {
206
+				$fileContent = file_get_contents($tmpFolder.'/.user.ini');
207 207
 				$hashes[$relativeFileName] = hash('sha512', $fileContent);
208 208
 				continue;
209 209
 			}
@@ -215,10 +215,10 @@  discard block
 block discarded – undo
215 215
 			// Thus we ignore everything below the first occurrence of
216 216
 			// "#### DO NOT CHANGE ANYTHING ABOVE THIS LINE ####" and have the
217 217
 			// hash generated based on this.
218
-			if($filename === $this->environmentHelper->getServerRoot() . '/.htaccess') {
219
-				$fileContent = file_get_contents($tmpFolder . '/.htaccess');
218
+			if ($filename === $this->environmentHelper->getServerRoot().'/.htaccess') {
219
+				$fileContent = file_get_contents($tmpFolder.'/.htaccess');
220 220
 				$explodedArray = explode('#### DO NOT CHANGE ANYTHING ABOVE THIS LINE ####', $fileContent);
221
-				if(count($explodedArray) === 2) {
221
+				if (count($explodedArray) === 2) {
222 222
 					$hashes[$relativeFileName] = hash('sha512', $explodedArray[0]);
223 223
 					continue;
224 224
 				}
@@ -267,7 +267,7 @@  discard block
 block discarded – undo
267 267
 	public function writeAppSignature($path,
268 268
 									  X509 $certificate,
269 269
 									  RSA $privateKey) {
270
-		$appInfoDir = $path . '/appinfo';
270
+		$appInfoDir = $path.'/appinfo';
271 271
 		try {
272 272
 			$this->fileAccessHelper->assertDirectoryExists($appInfoDir);
273 273
 
@@ -275,12 +275,12 @@  discard block
 block discarded – undo
275 275
 			$hashes = $this->generateHashes($iterator, $path);
276 276
 			$signature = $this->createSignatureData($hashes, $certificate, $privateKey);
277 277
 				$this->fileAccessHelper->file_put_contents(
278
-					$appInfoDir . '/signature.json',
278
+					$appInfoDir.'/signature.json',
279 279
 				json_encode($signature, JSON_PRETTY_PRINT)
280 280
 			);
281
-		} catch (\Exception $e){
281
+		} catch (\Exception $e) {
282 282
 			if (!$this->fileAccessHelper->is_writable($appInfoDir)) {
283
-				throw new \Exception($appInfoDir . ' is not writable');
283
+				throw new \Exception($appInfoDir.' is not writable');
284 284
 			}
285 285
 			throw $e;
286 286
 		}
@@ -297,7 +297,7 @@  discard block
 block discarded – undo
297 297
 	public function writeCoreSignature(X509 $certificate,
298 298
 									   RSA $rsa,
299 299
 									   $path) {
300
-		$coreDir = $path . '/core';
300
+		$coreDir = $path.'/core';
301 301
 		try {
302 302
 
303 303
 			$this->fileAccessHelper->assertDirectoryExists($coreDir);
@@ -305,12 +305,12 @@  discard block
 block discarded – undo
305 305
 			$hashes = $this->generateHashes($iterator, $path);
306 306
 			$signatureData = $this->createSignatureData($hashes, $certificate, $rsa);
307 307
 			$this->fileAccessHelper->file_put_contents(
308
-				$coreDir . '/signature.json',
308
+				$coreDir.'/signature.json',
309 309
 				json_encode($signatureData, JSON_PRETTY_PRINT)
310 310
 			);
311
-		} catch (\Exception $e){
311
+		} catch (\Exception $e) {
312 312
 			if (!$this->fileAccessHelper->is_writable($coreDir)) {
313
-				throw new \Exception($coreDir . ' is not writable');
313
+				throw new \Exception($coreDir.' is not writable');
314 314
 			}
315 315
 			throw $e;
316 316
 		}
@@ -327,12 +327,12 @@  discard block
 block discarded – undo
327 327
 	 * @throws \Exception
328 328
 	 */
329 329
 	private function verify($signaturePath, $basePath, $certificateCN) {
330
-		if(!$this->isCodeCheckEnforced()) {
330
+		if (!$this->isCodeCheckEnforced()) {
331 331
 			return [];
332 332
 		}
333 333
 
334 334
 		$signatureData = json_decode($this->fileAccessHelper->file_get_contents($signaturePath), true);
335
-		if(!is_array($signatureData)) {
335
+		if (!is_array($signatureData)) {
336 336
 			throw new InvalidSignatureException('Signature data not found.');
337 337
 		}
338 338
 
@@ -346,11 +346,11 @@  discard block
 block discarded – undo
346 346
 		$rootCertificatePublicKey = $this->fileAccessHelper->file_get_contents($this->environmentHelper->getServerRoot().'/resources/codesigning/root.crt');
347 347
 		$x509->loadCA($rootCertificatePublicKey);
348 348
 		$x509->loadX509($certificate);
349
-		if(!$x509->validateSignature()) {
349
+		if (!$x509->validateSignature()) {
350 350
 			throw new InvalidSignatureException('Certificate is not valid.');
351 351
 		}
352 352
 		// Verify if certificate has proper CN. "core" CN is always trusted.
353
-		if($x509->getDN(X509::DN_OPENSSL)['CN'] !== $certificateCN && $x509->getDN(X509::DN_OPENSSL)['CN'] !== 'core') {
353
+		if ($x509->getDN(X509::DN_OPENSSL)['CN'] !== $certificateCN && $x509->getDN(X509::DN_OPENSSL)['CN'] !== 'core') {
354 354
 			throw new InvalidSignatureException(
355 355
 					sprintf('Certificate is not valid for required scope. (Requested: %s, current: CN=%s)', $certificateCN, $x509->getDN(true)['CN'])
356 356
 			);
@@ -363,7 +363,7 @@  discard block
 block discarded – undo
363 363
 		$rsa->setMGFHash('sha512');
364 364
 		// See https://tools.ietf.org/html/rfc3447#page-38
365 365
 		$rsa->setSaltLength(0);
366
-		if(!$rsa->verify(json_encode($expectedHashes), $signature)) {
366
+		if (!$rsa->verify(json_encode($expectedHashes), $signature)) {
367 367
 			throw new InvalidSignatureException('Signature could not get verified.');
368 368
 		}
369 369
 
@@ -372,9 +372,9 @@  discard block
 block discarded – undo
372 372
 		//
373 373
 		// Due to this reason we exclude the whole updater/ folder from the code
374 374
 		// integrity check.
375
-		if($basePath === $this->environmentHelper->getServerRoot()) {
376
-			foreach($expectedHashes as $fileName => $hash) {
377
-				if(strpos($fileName, 'updater/') === 0) {
375
+		if ($basePath === $this->environmentHelper->getServerRoot()) {
376
+			foreach ($expectedHashes as $fileName => $hash) {
377
+				if (strpos($fileName, 'updater/') === 0) {
378 378
 					unset($expectedHashes[$fileName]);
379 379
 				}
380 380
 			}
@@ -386,23 +386,23 @@  discard block
 block discarded – undo
386 386
 		$differencesB = array_diff($currentInstanceHashes, $expectedHashes);
387 387
 		$differences = array_unique(array_merge($differencesA, $differencesB));
388 388
 		$differenceArray = [];
389
-		foreach($differences as $filename => $hash) {
389
+		foreach ($differences as $filename => $hash) {
390 390
 			// Check if file should not exist in the new signature table
391
-			if(!array_key_exists($filename, $expectedHashes)) {
391
+			if (!array_key_exists($filename, $expectedHashes)) {
392 392
 				$differenceArray['EXTRA_FILE'][$filename]['expected'] = '';
393 393
 				$differenceArray['EXTRA_FILE'][$filename]['current'] = $hash;
394 394
 				continue;
395 395
 			}
396 396
 
397 397
 			// Check if file is missing
398
-			if(!array_key_exists($filename, $currentInstanceHashes)) {
398
+			if (!array_key_exists($filename, $currentInstanceHashes)) {
399 399
 				$differenceArray['FILE_MISSING'][$filename]['expected'] = $expectedHashes[$filename];
400 400
 				$differenceArray['FILE_MISSING'][$filename]['current'] = '';
401 401
 				continue;
402 402
 			}
403 403
 
404 404
 			// Check if hash does mismatch
405
-			if($expectedHashes[$filename] !== $currentInstanceHashes[$filename]) {
405
+			if ($expectedHashes[$filename] !== $currentInstanceHashes[$filename]) {
406 406
 				$differenceArray['INVALID_HASH'][$filename]['expected'] = $expectedHashes[$filename];
407 407
 				$differenceArray['INVALID_HASH'][$filename]['current'] = $currentInstanceHashes[$filename];
408 408
 				continue;
@@ -422,7 +422,7 @@  discard block
 block discarded – undo
422 422
 	 */
423 423
 	public function hasPassedCheck() {
424 424
 		$results = $this->getResults();
425
-		if(empty($results)) {
425
+		if (empty($results)) {
426 426
 			return true;
427 427
 		}
428 428
 
@@ -434,7 +434,7 @@  discard block
 block discarded – undo
434 434
 	 */
435 435
 	public function getResults() {
436 436
 		$cachedResults = $this->cache->get(self::CACHE_KEY);
437
-		if(!is_null($cachedResults)) {
437
+		if (!is_null($cachedResults)) {
438 438
 			return json_decode($cachedResults, true);
439 439
 		}
440 440
 
@@ -453,7 +453,7 @@  discard block
 block discarded – undo
453 453
 	private function storeResults($scope, array $result) {
454 454
 		$resultArray = $this->getResults();
455 455
 		unset($resultArray[$scope]);
456
-		if(!empty($result)) {
456
+		if (!empty($result)) {
457 457
 			$resultArray[$scope] = $result;
458 458
 		}
459 459
 		if ($this->config !== null) {
@@ -505,11 +505,11 @@  discard block
 block discarded – undo
505 505
 	 */
506 506
 	public function verifyAppSignature($appId, $path = '') {
507 507
 		try {
508
-			if($path === '') {
508
+			if ($path === '') {
509 509
 				$path = $this->appLocator->getAppPath($appId);
510 510
 			}
511 511
 			$result = $this->verify(
512
-					$path . '/appinfo/signature.json',
512
+					$path.'/appinfo/signature.json',
513 513
 					$path,
514 514
 					$appId
515 515
 			);
@@ -559,7 +559,7 @@  discard block
 block discarded – undo
559 559
 	public function verifyCoreSignature() {
560 560
 		try {
561 561
 			$result = $this->verify(
562
-					$this->environmentHelper->getServerRoot() . '/core/signature.json',
562
+					$this->environmentHelper->getServerRoot().'/core/signature.json',
563 563
 					$this->environmentHelper->getServerRoot(),
564 564
 					'core'
565 565
 			);
@@ -584,18 +584,18 @@  discard block
 block discarded – undo
584 584
 		$this->cleanResults();
585 585
 		$this->verifyCoreSignature();
586 586
 		$appIds = $this->appLocator->getAllApps();
587
-		foreach($appIds as $appId) {
587
+		foreach ($appIds as $appId) {
588 588
 			// If an application is shipped a valid signature is required
589 589
 			$isShipped = $this->appManager->isShipped($appId);
590 590
 			$appNeedsToBeChecked = false;
591 591
 			if ($isShipped) {
592 592
 				$appNeedsToBeChecked = true;
593
-			} elseif ($this->fileAccessHelper->file_exists($this->appLocator->getAppPath($appId) . '/appinfo/signature.json')) {
593
+			} elseif ($this->fileAccessHelper->file_exists($this->appLocator->getAppPath($appId).'/appinfo/signature.json')) {
594 594
 				// Otherwise only if the application explicitly ships a signature.json file
595 595
 				$appNeedsToBeChecked = true;
596 596
 			}
597 597
 
598
-			if($appNeedsToBeChecked) {
598
+			if ($appNeedsToBeChecked) {
599 599
 				$this->verifyAppSignature($appId);
600 600
 			}
601 601
 		}
Please login to merge, or discard this patch.
Indentation   +551 added lines, -551 removed lines patch added patch discarded remove patch
@@ -51,555 +51,555 @@
 block discarded – undo
51 51
  * @package OC\IntegrityCheck
52 52
  */
53 53
 class Checker {
54
-	const CACHE_KEY = 'oc.integritycheck.checker';
55
-	/** @var EnvironmentHelper */
56
-	private $environmentHelper;
57
-	/** @var AppLocator */
58
-	private $appLocator;
59
-	/** @var FileAccessHelper */
60
-	private $fileAccessHelper;
61
-	/** @var IConfig */
62
-	private $config;
63
-	/** @var ICache */
64
-	private $cache;
65
-	/** @var IAppManager */
66
-	private $appManager;
67
-	/** @var ITempManager */
68
-	private $tempManager;
69
-
70
-	/**
71
-	 * @param EnvironmentHelper $environmentHelper
72
-	 * @param FileAccessHelper $fileAccessHelper
73
-	 * @param AppLocator $appLocator
74
-	 * @param IConfig $config
75
-	 * @param ICacheFactory $cacheFactory
76
-	 * @param IAppManager $appManager
77
-	 * @param ITempManager $tempManager
78
-	 */
79
-	public function __construct(EnvironmentHelper $environmentHelper,
80
-								FileAccessHelper $fileAccessHelper,
81
-								AppLocator $appLocator,
82
-								IConfig $config = null,
83
-								ICacheFactory $cacheFactory,
84
-								IAppManager $appManager = null,
85
-								ITempManager $tempManager) {
86
-		$this->environmentHelper = $environmentHelper;
87
-		$this->fileAccessHelper = $fileAccessHelper;
88
-		$this->appLocator = $appLocator;
89
-		$this->config = $config;
90
-		$this->cache = $cacheFactory->createDistributed(self::CACHE_KEY);
91
-		$this->appManager = $appManager;
92
-		$this->tempManager = $tempManager;
93
-	}
94
-
95
-	/**
96
-	 * Whether code signing is enforced or not.
97
-	 *
98
-	 * @return bool
99
-	 */
100
-	public function isCodeCheckEnforced() {
101
-		$notSignedChannels = [ '', 'git'];
102
-		if (in_array($this->environmentHelper->getChannel(), $notSignedChannels, true)) {
103
-			return false;
104
-		}
105
-
106
-		/**
107
-		 * This config option is undocumented and supposed to be so, it's only
108
-		 * applicable for very specific scenarios and we should not advertise it
109
-		 * too prominent. So please do not add it to config.sample.php.
110
-		 */
111
-		if ($this->config !== null) {
112
-			$isIntegrityCheckDisabled = $this->config->getSystemValue('integrity.check.disabled', false);
113
-		} else {
114
-			$isIntegrityCheckDisabled = false;
115
-		}
116
-		if ($isIntegrityCheckDisabled === true) {
117
-			return false;
118
-		}
119
-
120
-		return true;
121
-	}
122
-
123
-	/**
124
-	 * Enumerates all files belonging to the folder. Sensible defaults are excluded.
125
-	 *
126
-	 * @param string $folderToIterate
127
-	 * @param string $root
128
-	 * @return \RecursiveIteratorIterator
129
-	 * @throws \Exception
130
-	 */
131
-	private function getFolderIterator($folderToIterate, $root = '') {
132
-		$dirItr = new \RecursiveDirectoryIterator(
133
-			$folderToIterate,
134
-			\RecursiveDirectoryIterator::SKIP_DOTS
135
-		);
136
-		if($root === '') {
137
-			$root = \OC::$SERVERROOT;
138
-		}
139
-		$root = rtrim($root, '/');
140
-
141
-		$excludeGenericFilesIterator = new ExcludeFileByNameFilterIterator($dirItr);
142
-		$excludeFoldersIterator = new ExcludeFoldersByPathFilterIterator($excludeGenericFilesIterator, $root);
143
-
144
-		return new \RecursiveIteratorIterator(
145
-			$excludeFoldersIterator,
146
-			\RecursiveIteratorIterator::SELF_FIRST
147
-		);
148
-	}
149
-
150
-	/**
151
-	 * Returns an array of ['filename' => 'SHA512-hash-of-file'] for all files found
152
-	 * in the iterator.
153
-	 *
154
-	 * @param \RecursiveIteratorIterator $iterator
155
-	 * @param string $path
156
-	 * @return array Array of hashes.
157
-	 */
158
-	private function generateHashes(\RecursiveIteratorIterator $iterator,
159
-									$path) {
160
-		$hashes = [];
161
-		$copiedWebserverSettingFiles = false;
162
-		$tmpFolder = '';
163
-
164
-		$baseDirectoryLength = strlen($path);
165
-		foreach($iterator as $filename => $data) {
166
-			/** @var \DirectoryIterator $data */
167
-			if($data->isDir()) {
168
-				continue;
169
-			}
170
-
171
-			$relativeFileName = substr($filename, $baseDirectoryLength);
172
-			$relativeFileName = ltrim($relativeFileName, '/');
173
-
174
-			// Exclude signature.json files in the appinfo and root folder
175
-			if($relativeFileName === 'appinfo/signature.json') {
176
-				continue;
177
-			}
178
-			// Exclude signature.json files in the appinfo and core folder
179
-			if($relativeFileName === 'core/signature.json') {
180
-				continue;
181
-			}
182
-
183
-			// The .user.ini and the .htaccess file of ownCloud can contain some
184
-			// custom modifications such as for example the maximum upload size
185
-			// to ensure that this will not lead to false positives this will
186
-			// copy the file to a temporary folder and reset it to the default
187
-			// values.
188
-			if($filename === $this->environmentHelper->getServerRoot() . '/.htaccess'
189
-				|| $filename === $this->environmentHelper->getServerRoot() . '/.user.ini') {
190
-
191
-				if(!$copiedWebserverSettingFiles) {
192
-					$tmpFolder = rtrim($this->tempManager->getTemporaryFolder(), '/');
193
-					copy($this->environmentHelper->getServerRoot() . '/.htaccess', $tmpFolder . '/.htaccess');
194
-					copy($this->environmentHelper->getServerRoot() . '/.user.ini', $tmpFolder . '/.user.ini');
195
-					\OC_Files::setUploadLimit(
196
-						\OCP\Util::computerFileSize('511MB'),
197
-						[
198
-							'.htaccess' => $tmpFolder . '/.htaccess',
199
-							'.user.ini' => $tmpFolder . '/.user.ini',
200
-						]
201
-					);
202
-				}
203
-			}
204
-
205
-			// The .user.ini file can contain custom modifications to the file size
206
-			// as well.
207
-			if($filename === $this->environmentHelper->getServerRoot() . '/.user.ini') {
208
-				$fileContent = file_get_contents($tmpFolder . '/.user.ini');
209
-				$hashes[$relativeFileName] = hash('sha512', $fileContent);
210
-				continue;
211
-			}
212
-
213
-			// The .htaccess file in the root folder of ownCloud can contain
214
-			// custom content after the installation due to the fact that dynamic
215
-			// content is written into it at installation time as well. This
216
-			// includes for example the 404 and 403 instructions.
217
-			// Thus we ignore everything below the first occurrence of
218
-			// "#### DO NOT CHANGE ANYTHING ABOVE THIS LINE ####" and have the
219
-			// hash generated based on this.
220
-			if($filename === $this->environmentHelper->getServerRoot() . '/.htaccess') {
221
-				$fileContent = file_get_contents($tmpFolder . '/.htaccess');
222
-				$explodedArray = explode('#### DO NOT CHANGE ANYTHING ABOVE THIS LINE ####', $fileContent);
223
-				if(count($explodedArray) === 2) {
224
-					$hashes[$relativeFileName] = hash('sha512', $explodedArray[0]);
225
-					continue;
226
-				}
227
-			}
228
-
229
-			$hashes[$relativeFileName] = hash_file('sha512', $filename);
230
-		}
231
-
232
-		return $hashes;
233
-	}
234
-
235
-	/**
236
-	 * Creates the signature data
237
-	 *
238
-	 * @param array $hashes
239
-	 * @param X509 $certificate
240
-	 * @param RSA $privateKey
241
-	 * @return string
242
-	 */
243
-	private function createSignatureData(array $hashes,
244
-										 X509 $certificate,
245
-										 RSA $privateKey) {
246
-		ksort($hashes);
247
-
248
-		$privateKey->setSignatureMode(RSA::SIGNATURE_PSS);
249
-		$privateKey->setMGFHash('sha512');
250
-		// See https://tools.ietf.org/html/rfc3447#page-38
251
-		$privateKey->setSaltLength(0);
252
-		$signature = $privateKey->sign(json_encode($hashes));
253
-
254
-		return [
255
-				'hashes' => $hashes,
256
-				'signature' => base64_encode($signature),
257
-				'certificate' => $certificate->saveX509($certificate->currentCert),
258
-			];
259
-	}
260
-
261
-	/**
262
-	 * Write the signature of the app in the specified folder
263
-	 *
264
-	 * @param string $path
265
-	 * @param X509 $certificate
266
-	 * @param RSA $privateKey
267
-	 * @throws \Exception
268
-	 */
269
-	public function writeAppSignature($path,
270
-									  X509 $certificate,
271
-									  RSA $privateKey) {
272
-		$appInfoDir = $path . '/appinfo';
273
-		try {
274
-			$this->fileAccessHelper->assertDirectoryExists($appInfoDir);
275
-
276
-			$iterator = $this->getFolderIterator($path);
277
-			$hashes = $this->generateHashes($iterator, $path);
278
-			$signature = $this->createSignatureData($hashes, $certificate, $privateKey);
279
-				$this->fileAccessHelper->file_put_contents(
280
-					$appInfoDir . '/signature.json',
281
-				json_encode($signature, JSON_PRETTY_PRINT)
282
-			);
283
-		} catch (\Exception $e){
284
-			if (!$this->fileAccessHelper->is_writable($appInfoDir)) {
285
-				throw new \Exception($appInfoDir . ' is not writable');
286
-			}
287
-			throw $e;
288
-		}
289
-	}
290
-
291
-	/**
292
-	 * Write the signature of core
293
-	 *
294
-	 * @param X509 $certificate
295
-	 * @param RSA $rsa
296
-	 * @param string $path
297
-	 * @throws \Exception
298
-	 */
299
-	public function writeCoreSignature(X509 $certificate,
300
-									   RSA $rsa,
301
-									   $path) {
302
-		$coreDir = $path . '/core';
303
-		try {
304
-
305
-			$this->fileAccessHelper->assertDirectoryExists($coreDir);
306
-			$iterator = $this->getFolderIterator($path, $path);
307
-			$hashes = $this->generateHashes($iterator, $path);
308
-			$signatureData = $this->createSignatureData($hashes, $certificate, $rsa);
309
-			$this->fileAccessHelper->file_put_contents(
310
-				$coreDir . '/signature.json',
311
-				json_encode($signatureData, JSON_PRETTY_PRINT)
312
-			);
313
-		} catch (\Exception $e){
314
-			if (!$this->fileAccessHelper->is_writable($coreDir)) {
315
-				throw new \Exception($coreDir . ' is not writable');
316
-			}
317
-			throw $e;
318
-		}
319
-	}
320
-
321
-	/**
322
-	 * Verifies the signature for the specified path.
323
-	 *
324
-	 * @param string $signaturePath
325
-	 * @param string $basePath
326
-	 * @param string $certificateCN
327
-	 * @return array
328
-	 * @throws InvalidSignatureException
329
-	 * @throws \Exception
330
-	 */
331
-	private function verify($signaturePath, $basePath, $certificateCN) {
332
-		if(!$this->isCodeCheckEnforced()) {
333
-			return [];
334
-		}
335
-
336
-		$signatureData = json_decode($this->fileAccessHelper->file_get_contents($signaturePath), true);
337
-		if(!is_array($signatureData)) {
338
-			throw new InvalidSignatureException('Signature data not found.');
339
-		}
340
-
341
-		$expectedHashes = $signatureData['hashes'];
342
-		ksort($expectedHashes);
343
-		$signature = base64_decode($signatureData['signature']);
344
-		$certificate = $signatureData['certificate'];
345
-
346
-		// Check if certificate is signed by Nextcloud Root Authority
347
-		$x509 = new \phpseclib\File\X509();
348
-		$rootCertificatePublicKey = $this->fileAccessHelper->file_get_contents($this->environmentHelper->getServerRoot().'/resources/codesigning/root.crt');
349
-		$x509->loadCA($rootCertificatePublicKey);
350
-		$x509->loadX509($certificate);
351
-		if(!$x509->validateSignature()) {
352
-			throw new InvalidSignatureException('Certificate is not valid.');
353
-		}
354
-		// Verify if certificate has proper CN. "core" CN is always trusted.
355
-		if($x509->getDN(X509::DN_OPENSSL)['CN'] !== $certificateCN && $x509->getDN(X509::DN_OPENSSL)['CN'] !== 'core') {
356
-			throw new InvalidSignatureException(
357
-					sprintf('Certificate is not valid for required scope. (Requested: %s, current: CN=%s)', $certificateCN, $x509->getDN(true)['CN'])
358
-			);
359
-		}
360
-
361
-		// Check if the signature of the files is valid
362
-		$rsa = new \phpseclib\Crypt\RSA();
363
-		$rsa->loadKey($x509->currentCert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']);
364
-		$rsa->setSignatureMode(RSA::SIGNATURE_PSS);
365
-		$rsa->setMGFHash('sha512');
366
-		// See https://tools.ietf.org/html/rfc3447#page-38
367
-		$rsa->setSaltLength(0);
368
-		if(!$rsa->verify(json_encode($expectedHashes), $signature)) {
369
-			throw new InvalidSignatureException('Signature could not get verified.');
370
-		}
371
-
372
-		// Fixes for the updater as shipped with ownCloud 9.0.x: The updater is
373
-		// replaced after the code integrity check is performed.
374
-		//
375
-		// Due to this reason we exclude the whole updater/ folder from the code
376
-		// integrity check.
377
-		if($basePath === $this->environmentHelper->getServerRoot()) {
378
-			foreach($expectedHashes as $fileName => $hash) {
379
-				if(strpos($fileName, 'updater/') === 0) {
380
-					unset($expectedHashes[$fileName]);
381
-				}
382
-			}
383
-		}
384
-
385
-		// Compare the list of files which are not identical
386
-		$currentInstanceHashes = $this->generateHashes($this->getFolderIterator($basePath), $basePath);
387
-		$differencesA = array_diff($expectedHashes, $currentInstanceHashes);
388
-		$differencesB = array_diff($currentInstanceHashes, $expectedHashes);
389
-		$differences = array_unique(array_merge($differencesA, $differencesB));
390
-		$differenceArray = [];
391
-		foreach($differences as $filename => $hash) {
392
-			// Check if file should not exist in the new signature table
393
-			if(!array_key_exists($filename, $expectedHashes)) {
394
-				$differenceArray['EXTRA_FILE'][$filename]['expected'] = '';
395
-				$differenceArray['EXTRA_FILE'][$filename]['current'] = $hash;
396
-				continue;
397
-			}
398
-
399
-			// Check if file is missing
400
-			if(!array_key_exists($filename, $currentInstanceHashes)) {
401
-				$differenceArray['FILE_MISSING'][$filename]['expected'] = $expectedHashes[$filename];
402
-				$differenceArray['FILE_MISSING'][$filename]['current'] = '';
403
-				continue;
404
-			}
405
-
406
-			// Check if hash does mismatch
407
-			if($expectedHashes[$filename] !== $currentInstanceHashes[$filename]) {
408
-				$differenceArray['INVALID_HASH'][$filename]['expected'] = $expectedHashes[$filename];
409
-				$differenceArray['INVALID_HASH'][$filename]['current'] = $currentInstanceHashes[$filename];
410
-				continue;
411
-			}
412
-
413
-			// Should never happen.
414
-			throw new \Exception('Invalid behaviour in file hash comparison experienced. Please report this error to the developers.');
415
-		}
416
-
417
-		return $differenceArray;
418
-	}
419
-
420
-	/**
421
-	 * Whether the code integrity check has passed successful or not
422
-	 *
423
-	 * @return bool
424
-	 */
425
-	public function hasPassedCheck() {
426
-		$results = $this->getResults();
427
-		if(empty($results)) {
428
-			return true;
429
-		}
430
-
431
-		return false;
432
-	}
433
-
434
-	/**
435
-	 * @return array
436
-	 */
437
-	public function getResults() {
438
-		$cachedResults = $this->cache->get(self::CACHE_KEY);
439
-		if(!is_null($cachedResults)) {
440
-			return json_decode($cachedResults, true);
441
-		}
442
-
443
-		if ($this->config !== null) {
444
-			return json_decode($this->config->getAppValue('core', self::CACHE_KEY, '{}'), true);
445
-		}
446
-		return [];
447
-	}
448
-
449
-	/**
450
-	 * Stores the results in the app config as well as cache
451
-	 *
452
-	 * @param string $scope
453
-	 * @param array $result
454
-	 */
455
-	private function storeResults($scope, array $result) {
456
-		$resultArray = $this->getResults();
457
-		unset($resultArray[$scope]);
458
-		if(!empty($result)) {
459
-			$resultArray[$scope] = $result;
460
-		}
461
-		if ($this->config !== null) {
462
-			$this->config->setAppValue('core', self::CACHE_KEY, json_encode($resultArray));
463
-		}
464
-		$this->cache->set(self::CACHE_KEY, json_encode($resultArray));
465
-	}
466
-
467
-	/**
468
-	 *
469
-	 * Clean previous results for a proper rescanning. Otherwise
470
-	 */
471
-	private function cleanResults() {
472
-		$this->config->deleteAppValue('core', self::CACHE_KEY);
473
-		$this->cache->remove(self::CACHE_KEY);
474
-	}
475
-
476
-	/**
477
-	 * Verify the signature of $appId. Returns an array with the following content:
478
-	 * [
479
-	 * 	'FILE_MISSING' =>
480
-	 * 	[
481
-	 * 		'filename' => [
482
-	 * 			'expected' => 'expectedSHA512',
483
-	 * 			'current' => 'currentSHA512',
484
-	 * 		],
485
-	 * 	],
486
-	 * 	'EXTRA_FILE' =>
487
-	 * 	[
488
-	 * 		'filename' => [
489
-	 * 			'expected' => 'expectedSHA512',
490
-	 * 			'current' => 'currentSHA512',
491
-	 * 		],
492
-	 * 	],
493
-	 * 	'INVALID_HASH' =>
494
-	 * 	[
495
-	 * 		'filename' => [
496
-	 * 			'expected' => 'expectedSHA512',
497
-	 * 			'current' => 'currentSHA512',
498
-	 * 		],
499
-	 * 	],
500
-	 * ]
501
-	 *
502
-	 * Array may be empty in case no problems have been found.
503
-	 *
504
-	 * @param string $appId
505
-	 * @param string $path Optional path. If none is given it will be guessed.
506
-	 * @return array
507
-	 */
508
-	public function verifyAppSignature($appId, $path = '') {
509
-		try {
510
-			if($path === '') {
511
-				$path = $this->appLocator->getAppPath($appId);
512
-			}
513
-			$result = $this->verify(
514
-					$path . '/appinfo/signature.json',
515
-					$path,
516
-					$appId
517
-			);
518
-		} catch (\Exception $e) {
519
-			$result = [
520
-					'EXCEPTION' => [
521
-							'class' => get_class($e),
522
-							'message' => $e->getMessage(),
523
-					],
524
-			];
525
-		}
526
-		$this->storeResults($appId, $result);
527
-
528
-		return $result;
529
-	}
530
-
531
-	/**
532
-	 * Verify the signature of core. Returns an array with the following content:
533
-	 * [
534
-	 * 	'FILE_MISSING' =>
535
-	 * 	[
536
-	 * 		'filename' => [
537
-	 * 			'expected' => 'expectedSHA512',
538
-	 * 			'current' => 'currentSHA512',
539
-	 * 		],
540
-	 * 	],
541
-	 * 	'EXTRA_FILE' =>
542
-	 * 	[
543
-	 * 		'filename' => [
544
-	 * 			'expected' => 'expectedSHA512',
545
-	 * 			'current' => 'currentSHA512',
546
-	 * 		],
547
-	 * 	],
548
-	 * 	'INVALID_HASH' =>
549
-	 * 	[
550
-	 * 		'filename' => [
551
-	 * 			'expected' => 'expectedSHA512',
552
-	 * 			'current' => 'currentSHA512',
553
-	 * 		],
554
-	 * 	],
555
-	 * ]
556
-	 *
557
-	 * Array may be empty in case no problems have been found.
558
-	 *
559
-	 * @return array
560
-	 */
561
-	public function verifyCoreSignature() {
562
-		try {
563
-			$result = $this->verify(
564
-					$this->environmentHelper->getServerRoot() . '/core/signature.json',
565
-					$this->environmentHelper->getServerRoot(),
566
-					'core'
567
-			);
568
-		} catch (\Exception $e) {
569
-			$result = [
570
-					'EXCEPTION' => [
571
-							'class' => get_class($e),
572
-							'message' => $e->getMessage(),
573
-					],
574
-			];
575
-		}
576
-		$this->storeResults('core', $result);
577
-
578
-		return $result;
579
-	}
580
-
581
-	/**
582
-	 * Verify the core code of the instance as well as all applicable applications
583
-	 * and store the results.
584
-	 */
585
-	public function runInstanceVerification() {
586
-		$this->cleanResults();
587
-		$this->verifyCoreSignature();
588
-		$appIds = $this->appLocator->getAllApps();
589
-		foreach($appIds as $appId) {
590
-			// If an application is shipped a valid signature is required
591
-			$isShipped = $this->appManager->isShipped($appId);
592
-			$appNeedsToBeChecked = false;
593
-			if ($isShipped) {
594
-				$appNeedsToBeChecked = true;
595
-			} elseif ($this->fileAccessHelper->file_exists($this->appLocator->getAppPath($appId) . '/appinfo/signature.json')) {
596
-				// Otherwise only if the application explicitly ships a signature.json file
597
-				$appNeedsToBeChecked = true;
598
-			}
599
-
600
-			if($appNeedsToBeChecked) {
601
-				$this->verifyAppSignature($appId);
602
-			}
603
-		}
604
-	}
54
+    const CACHE_KEY = 'oc.integritycheck.checker';
55
+    /** @var EnvironmentHelper */
56
+    private $environmentHelper;
57
+    /** @var AppLocator */
58
+    private $appLocator;
59
+    /** @var FileAccessHelper */
60
+    private $fileAccessHelper;
61
+    /** @var IConfig */
62
+    private $config;
63
+    /** @var ICache */
64
+    private $cache;
65
+    /** @var IAppManager */
66
+    private $appManager;
67
+    /** @var ITempManager */
68
+    private $tempManager;
69
+
70
+    /**
71
+     * @param EnvironmentHelper $environmentHelper
72
+     * @param FileAccessHelper $fileAccessHelper
73
+     * @param AppLocator $appLocator
74
+     * @param IConfig $config
75
+     * @param ICacheFactory $cacheFactory
76
+     * @param IAppManager $appManager
77
+     * @param ITempManager $tempManager
78
+     */
79
+    public function __construct(EnvironmentHelper $environmentHelper,
80
+                                FileAccessHelper $fileAccessHelper,
81
+                                AppLocator $appLocator,
82
+                                IConfig $config = null,
83
+                                ICacheFactory $cacheFactory,
84
+                                IAppManager $appManager = null,
85
+                                ITempManager $tempManager) {
86
+        $this->environmentHelper = $environmentHelper;
87
+        $this->fileAccessHelper = $fileAccessHelper;
88
+        $this->appLocator = $appLocator;
89
+        $this->config = $config;
90
+        $this->cache = $cacheFactory->createDistributed(self::CACHE_KEY);
91
+        $this->appManager = $appManager;
92
+        $this->tempManager = $tempManager;
93
+    }
94
+
95
+    /**
96
+     * Whether code signing is enforced or not.
97
+     *
98
+     * @return bool
99
+     */
100
+    public function isCodeCheckEnforced() {
101
+        $notSignedChannels = [ '', 'git'];
102
+        if (in_array($this->environmentHelper->getChannel(), $notSignedChannels, true)) {
103
+            return false;
104
+        }
105
+
106
+        /**
107
+         * This config option is undocumented and supposed to be so, it's only
108
+         * applicable for very specific scenarios and we should not advertise it
109
+         * too prominent. So please do not add it to config.sample.php.
110
+         */
111
+        if ($this->config !== null) {
112
+            $isIntegrityCheckDisabled = $this->config->getSystemValue('integrity.check.disabled', false);
113
+        } else {
114
+            $isIntegrityCheckDisabled = false;
115
+        }
116
+        if ($isIntegrityCheckDisabled === true) {
117
+            return false;
118
+        }
119
+
120
+        return true;
121
+    }
122
+
123
+    /**
124
+     * Enumerates all files belonging to the folder. Sensible defaults are excluded.
125
+     *
126
+     * @param string $folderToIterate
127
+     * @param string $root
128
+     * @return \RecursiveIteratorIterator
129
+     * @throws \Exception
130
+     */
131
+    private function getFolderIterator($folderToIterate, $root = '') {
132
+        $dirItr = new \RecursiveDirectoryIterator(
133
+            $folderToIterate,
134
+            \RecursiveDirectoryIterator::SKIP_DOTS
135
+        );
136
+        if($root === '') {
137
+            $root = \OC::$SERVERROOT;
138
+        }
139
+        $root = rtrim($root, '/');
140
+
141
+        $excludeGenericFilesIterator = new ExcludeFileByNameFilterIterator($dirItr);
142
+        $excludeFoldersIterator = new ExcludeFoldersByPathFilterIterator($excludeGenericFilesIterator, $root);
143
+
144
+        return new \RecursiveIteratorIterator(
145
+            $excludeFoldersIterator,
146
+            \RecursiveIteratorIterator::SELF_FIRST
147
+        );
148
+    }
149
+
150
+    /**
151
+     * Returns an array of ['filename' => 'SHA512-hash-of-file'] for all files found
152
+     * in the iterator.
153
+     *
154
+     * @param \RecursiveIteratorIterator $iterator
155
+     * @param string $path
156
+     * @return array Array of hashes.
157
+     */
158
+    private function generateHashes(\RecursiveIteratorIterator $iterator,
159
+                                    $path) {
160
+        $hashes = [];
161
+        $copiedWebserverSettingFiles = false;
162
+        $tmpFolder = '';
163
+
164
+        $baseDirectoryLength = strlen($path);
165
+        foreach($iterator as $filename => $data) {
166
+            /** @var \DirectoryIterator $data */
167
+            if($data->isDir()) {
168
+                continue;
169
+            }
170
+
171
+            $relativeFileName = substr($filename, $baseDirectoryLength);
172
+            $relativeFileName = ltrim($relativeFileName, '/');
173
+
174
+            // Exclude signature.json files in the appinfo and root folder
175
+            if($relativeFileName === 'appinfo/signature.json') {
176
+                continue;
177
+            }
178
+            // Exclude signature.json files in the appinfo and core folder
179
+            if($relativeFileName === 'core/signature.json') {
180
+                continue;
181
+            }
182
+
183
+            // The .user.ini and the .htaccess file of ownCloud can contain some
184
+            // custom modifications such as for example the maximum upload size
185
+            // to ensure that this will not lead to false positives this will
186
+            // copy the file to a temporary folder and reset it to the default
187
+            // values.
188
+            if($filename === $this->environmentHelper->getServerRoot() . '/.htaccess'
189
+                || $filename === $this->environmentHelper->getServerRoot() . '/.user.ini') {
190
+
191
+                if(!$copiedWebserverSettingFiles) {
192
+                    $tmpFolder = rtrim($this->tempManager->getTemporaryFolder(), '/');
193
+                    copy($this->environmentHelper->getServerRoot() . '/.htaccess', $tmpFolder . '/.htaccess');
194
+                    copy($this->environmentHelper->getServerRoot() . '/.user.ini', $tmpFolder . '/.user.ini');
195
+                    \OC_Files::setUploadLimit(
196
+                        \OCP\Util::computerFileSize('511MB'),
197
+                        [
198
+                            '.htaccess' => $tmpFolder . '/.htaccess',
199
+                            '.user.ini' => $tmpFolder . '/.user.ini',
200
+                        ]
201
+                    );
202
+                }
203
+            }
204
+
205
+            // The .user.ini file can contain custom modifications to the file size
206
+            // as well.
207
+            if($filename === $this->environmentHelper->getServerRoot() . '/.user.ini') {
208
+                $fileContent = file_get_contents($tmpFolder . '/.user.ini');
209
+                $hashes[$relativeFileName] = hash('sha512', $fileContent);
210
+                continue;
211
+            }
212
+
213
+            // The .htaccess file in the root folder of ownCloud can contain
214
+            // custom content after the installation due to the fact that dynamic
215
+            // content is written into it at installation time as well. This
216
+            // includes for example the 404 and 403 instructions.
217
+            // Thus we ignore everything below the first occurrence of
218
+            // "#### DO NOT CHANGE ANYTHING ABOVE THIS LINE ####" and have the
219
+            // hash generated based on this.
220
+            if($filename === $this->environmentHelper->getServerRoot() . '/.htaccess') {
221
+                $fileContent = file_get_contents($tmpFolder . '/.htaccess');
222
+                $explodedArray = explode('#### DO NOT CHANGE ANYTHING ABOVE THIS LINE ####', $fileContent);
223
+                if(count($explodedArray) === 2) {
224
+                    $hashes[$relativeFileName] = hash('sha512', $explodedArray[0]);
225
+                    continue;
226
+                }
227
+            }
228
+
229
+            $hashes[$relativeFileName] = hash_file('sha512', $filename);
230
+        }
231
+
232
+        return $hashes;
233
+    }
234
+
235
+    /**
236
+     * Creates the signature data
237
+     *
238
+     * @param array $hashes
239
+     * @param X509 $certificate
240
+     * @param RSA $privateKey
241
+     * @return string
242
+     */
243
+    private function createSignatureData(array $hashes,
244
+                                            X509 $certificate,
245
+                                            RSA $privateKey) {
246
+        ksort($hashes);
247
+
248
+        $privateKey->setSignatureMode(RSA::SIGNATURE_PSS);
249
+        $privateKey->setMGFHash('sha512');
250
+        // See https://tools.ietf.org/html/rfc3447#page-38
251
+        $privateKey->setSaltLength(0);
252
+        $signature = $privateKey->sign(json_encode($hashes));
253
+
254
+        return [
255
+                'hashes' => $hashes,
256
+                'signature' => base64_encode($signature),
257
+                'certificate' => $certificate->saveX509($certificate->currentCert),
258
+            ];
259
+    }
260
+
261
+    /**
262
+     * Write the signature of the app in the specified folder
263
+     *
264
+     * @param string $path
265
+     * @param X509 $certificate
266
+     * @param RSA $privateKey
267
+     * @throws \Exception
268
+     */
269
+    public function writeAppSignature($path,
270
+                                        X509 $certificate,
271
+                                        RSA $privateKey) {
272
+        $appInfoDir = $path . '/appinfo';
273
+        try {
274
+            $this->fileAccessHelper->assertDirectoryExists($appInfoDir);
275
+
276
+            $iterator = $this->getFolderIterator($path);
277
+            $hashes = $this->generateHashes($iterator, $path);
278
+            $signature = $this->createSignatureData($hashes, $certificate, $privateKey);
279
+                $this->fileAccessHelper->file_put_contents(
280
+                    $appInfoDir . '/signature.json',
281
+                json_encode($signature, JSON_PRETTY_PRINT)
282
+            );
283
+        } catch (\Exception $e){
284
+            if (!$this->fileAccessHelper->is_writable($appInfoDir)) {
285
+                throw new \Exception($appInfoDir . ' is not writable');
286
+            }
287
+            throw $e;
288
+        }
289
+    }
290
+
291
+    /**
292
+     * Write the signature of core
293
+     *
294
+     * @param X509 $certificate
295
+     * @param RSA $rsa
296
+     * @param string $path
297
+     * @throws \Exception
298
+     */
299
+    public function writeCoreSignature(X509 $certificate,
300
+                                        RSA $rsa,
301
+                                        $path) {
302
+        $coreDir = $path . '/core';
303
+        try {
304
+
305
+            $this->fileAccessHelper->assertDirectoryExists($coreDir);
306
+            $iterator = $this->getFolderIterator($path, $path);
307
+            $hashes = $this->generateHashes($iterator, $path);
308
+            $signatureData = $this->createSignatureData($hashes, $certificate, $rsa);
309
+            $this->fileAccessHelper->file_put_contents(
310
+                $coreDir . '/signature.json',
311
+                json_encode($signatureData, JSON_PRETTY_PRINT)
312
+            );
313
+        } catch (\Exception $e){
314
+            if (!$this->fileAccessHelper->is_writable($coreDir)) {
315
+                throw new \Exception($coreDir . ' is not writable');
316
+            }
317
+            throw $e;
318
+        }
319
+    }
320
+
321
+    /**
322
+     * Verifies the signature for the specified path.
323
+     *
324
+     * @param string $signaturePath
325
+     * @param string $basePath
326
+     * @param string $certificateCN
327
+     * @return array
328
+     * @throws InvalidSignatureException
329
+     * @throws \Exception
330
+     */
331
+    private function verify($signaturePath, $basePath, $certificateCN) {
332
+        if(!$this->isCodeCheckEnforced()) {
333
+            return [];
334
+        }
335
+
336
+        $signatureData = json_decode($this->fileAccessHelper->file_get_contents($signaturePath), true);
337
+        if(!is_array($signatureData)) {
338
+            throw new InvalidSignatureException('Signature data not found.');
339
+        }
340
+
341
+        $expectedHashes = $signatureData['hashes'];
342
+        ksort($expectedHashes);
343
+        $signature = base64_decode($signatureData['signature']);
344
+        $certificate = $signatureData['certificate'];
345
+
346
+        // Check if certificate is signed by Nextcloud Root Authority
347
+        $x509 = new \phpseclib\File\X509();
348
+        $rootCertificatePublicKey = $this->fileAccessHelper->file_get_contents($this->environmentHelper->getServerRoot().'/resources/codesigning/root.crt');
349
+        $x509->loadCA($rootCertificatePublicKey);
350
+        $x509->loadX509($certificate);
351
+        if(!$x509->validateSignature()) {
352
+            throw new InvalidSignatureException('Certificate is not valid.');
353
+        }
354
+        // Verify if certificate has proper CN. "core" CN is always trusted.
355
+        if($x509->getDN(X509::DN_OPENSSL)['CN'] !== $certificateCN && $x509->getDN(X509::DN_OPENSSL)['CN'] !== 'core') {
356
+            throw new InvalidSignatureException(
357
+                    sprintf('Certificate is not valid for required scope. (Requested: %s, current: CN=%s)', $certificateCN, $x509->getDN(true)['CN'])
358
+            );
359
+        }
360
+
361
+        // Check if the signature of the files is valid
362
+        $rsa = new \phpseclib\Crypt\RSA();
363
+        $rsa->loadKey($x509->currentCert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']);
364
+        $rsa->setSignatureMode(RSA::SIGNATURE_PSS);
365
+        $rsa->setMGFHash('sha512');
366
+        // See https://tools.ietf.org/html/rfc3447#page-38
367
+        $rsa->setSaltLength(0);
368
+        if(!$rsa->verify(json_encode($expectedHashes), $signature)) {
369
+            throw new InvalidSignatureException('Signature could not get verified.');
370
+        }
371
+
372
+        // Fixes for the updater as shipped with ownCloud 9.0.x: The updater is
373
+        // replaced after the code integrity check is performed.
374
+        //
375
+        // Due to this reason we exclude the whole updater/ folder from the code
376
+        // integrity check.
377
+        if($basePath === $this->environmentHelper->getServerRoot()) {
378
+            foreach($expectedHashes as $fileName => $hash) {
379
+                if(strpos($fileName, 'updater/') === 0) {
380
+                    unset($expectedHashes[$fileName]);
381
+                }
382
+            }
383
+        }
384
+
385
+        // Compare the list of files which are not identical
386
+        $currentInstanceHashes = $this->generateHashes($this->getFolderIterator($basePath), $basePath);
387
+        $differencesA = array_diff($expectedHashes, $currentInstanceHashes);
388
+        $differencesB = array_diff($currentInstanceHashes, $expectedHashes);
389
+        $differences = array_unique(array_merge($differencesA, $differencesB));
390
+        $differenceArray = [];
391
+        foreach($differences as $filename => $hash) {
392
+            // Check if file should not exist in the new signature table
393
+            if(!array_key_exists($filename, $expectedHashes)) {
394
+                $differenceArray['EXTRA_FILE'][$filename]['expected'] = '';
395
+                $differenceArray['EXTRA_FILE'][$filename]['current'] = $hash;
396
+                continue;
397
+            }
398
+
399
+            // Check if file is missing
400
+            if(!array_key_exists($filename, $currentInstanceHashes)) {
401
+                $differenceArray['FILE_MISSING'][$filename]['expected'] = $expectedHashes[$filename];
402
+                $differenceArray['FILE_MISSING'][$filename]['current'] = '';
403
+                continue;
404
+            }
405
+
406
+            // Check if hash does mismatch
407
+            if($expectedHashes[$filename] !== $currentInstanceHashes[$filename]) {
408
+                $differenceArray['INVALID_HASH'][$filename]['expected'] = $expectedHashes[$filename];
409
+                $differenceArray['INVALID_HASH'][$filename]['current'] = $currentInstanceHashes[$filename];
410
+                continue;
411
+            }
412
+
413
+            // Should never happen.
414
+            throw new \Exception('Invalid behaviour in file hash comparison experienced. Please report this error to the developers.');
415
+        }
416
+
417
+        return $differenceArray;
418
+    }
419
+
420
+    /**
421
+     * Whether the code integrity check has passed successful or not
422
+     *
423
+     * @return bool
424
+     */
425
+    public function hasPassedCheck() {
426
+        $results = $this->getResults();
427
+        if(empty($results)) {
428
+            return true;
429
+        }
430
+
431
+        return false;
432
+    }
433
+
434
+    /**
435
+     * @return array
436
+     */
437
+    public function getResults() {
438
+        $cachedResults = $this->cache->get(self::CACHE_KEY);
439
+        if(!is_null($cachedResults)) {
440
+            return json_decode($cachedResults, true);
441
+        }
442
+
443
+        if ($this->config !== null) {
444
+            return json_decode($this->config->getAppValue('core', self::CACHE_KEY, '{}'), true);
445
+        }
446
+        return [];
447
+    }
448
+
449
+    /**
450
+     * Stores the results in the app config as well as cache
451
+     *
452
+     * @param string $scope
453
+     * @param array $result
454
+     */
455
+    private function storeResults($scope, array $result) {
456
+        $resultArray = $this->getResults();
457
+        unset($resultArray[$scope]);
458
+        if(!empty($result)) {
459
+            $resultArray[$scope] = $result;
460
+        }
461
+        if ($this->config !== null) {
462
+            $this->config->setAppValue('core', self::CACHE_KEY, json_encode($resultArray));
463
+        }
464
+        $this->cache->set(self::CACHE_KEY, json_encode($resultArray));
465
+    }
466
+
467
+    /**
468
+     *
469
+     * Clean previous results for a proper rescanning. Otherwise
470
+     */
471
+    private function cleanResults() {
472
+        $this->config->deleteAppValue('core', self::CACHE_KEY);
473
+        $this->cache->remove(self::CACHE_KEY);
474
+    }
475
+
476
+    /**
477
+     * Verify the signature of $appId. Returns an array with the following content:
478
+     * [
479
+     * 	'FILE_MISSING' =>
480
+     * 	[
481
+     * 		'filename' => [
482
+     * 			'expected' => 'expectedSHA512',
483
+     * 			'current' => 'currentSHA512',
484
+     * 		],
485
+     * 	],
486
+     * 	'EXTRA_FILE' =>
487
+     * 	[
488
+     * 		'filename' => [
489
+     * 			'expected' => 'expectedSHA512',
490
+     * 			'current' => 'currentSHA512',
491
+     * 		],
492
+     * 	],
493
+     * 	'INVALID_HASH' =>
494
+     * 	[
495
+     * 		'filename' => [
496
+     * 			'expected' => 'expectedSHA512',
497
+     * 			'current' => 'currentSHA512',
498
+     * 		],
499
+     * 	],
500
+     * ]
501
+     *
502
+     * Array may be empty in case no problems have been found.
503
+     *
504
+     * @param string $appId
505
+     * @param string $path Optional path. If none is given it will be guessed.
506
+     * @return array
507
+     */
508
+    public function verifyAppSignature($appId, $path = '') {
509
+        try {
510
+            if($path === '') {
511
+                $path = $this->appLocator->getAppPath($appId);
512
+            }
513
+            $result = $this->verify(
514
+                    $path . '/appinfo/signature.json',
515
+                    $path,
516
+                    $appId
517
+            );
518
+        } catch (\Exception $e) {
519
+            $result = [
520
+                    'EXCEPTION' => [
521
+                            'class' => get_class($e),
522
+                            'message' => $e->getMessage(),
523
+                    ],
524
+            ];
525
+        }
526
+        $this->storeResults($appId, $result);
527
+
528
+        return $result;
529
+    }
530
+
531
+    /**
532
+     * Verify the signature of core. Returns an array with the following content:
533
+     * [
534
+     * 	'FILE_MISSING' =>
535
+     * 	[
536
+     * 		'filename' => [
537
+     * 			'expected' => 'expectedSHA512',
538
+     * 			'current' => 'currentSHA512',
539
+     * 		],
540
+     * 	],
541
+     * 	'EXTRA_FILE' =>
542
+     * 	[
543
+     * 		'filename' => [
544
+     * 			'expected' => 'expectedSHA512',
545
+     * 			'current' => 'currentSHA512',
546
+     * 		],
547
+     * 	],
548
+     * 	'INVALID_HASH' =>
549
+     * 	[
550
+     * 		'filename' => [
551
+     * 			'expected' => 'expectedSHA512',
552
+     * 			'current' => 'currentSHA512',
553
+     * 		],
554
+     * 	],
555
+     * ]
556
+     *
557
+     * Array may be empty in case no problems have been found.
558
+     *
559
+     * @return array
560
+     */
561
+    public function verifyCoreSignature() {
562
+        try {
563
+            $result = $this->verify(
564
+                    $this->environmentHelper->getServerRoot() . '/core/signature.json',
565
+                    $this->environmentHelper->getServerRoot(),
566
+                    'core'
567
+            );
568
+        } catch (\Exception $e) {
569
+            $result = [
570
+                    'EXCEPTION' => [
571
+                            'class' => get_class($e),
572
+                            'message' => $e->getMessage(),
573
+                    ],
574
+            ];
575
+        }
576
+        $this->storeResults('core', $result);
577
+
578
+        return $result;
579
+    }
580
+
581
+    /**
582
+     * Verify the core code of the instance as well as all applicable applications
583
+     * and store the results.
584
+     */
585
+    public function runInstanceVerification() {
586
+        $this->cleanResults();
587
+        $this->verifyCoreSignature();
588
+        $appIds = $this->appLocator->getAllApps();
589
+        foreach($appIds as $appId) {
590
+            // If an application is shipped a valid signature is required
591
+            $isShipped = $this->appManager->isShipped($appId);
592
+            $appNeedsToBeChecked = false;
593
+            if ($isShipped) {
594
+                $appNeedsToBeChecked = true;
595
+            } elseif ($this->fileAccessHelper->file_exists($this->appLocator->getAppPath($appId) . '/appinfo/signature.json')) {
596
+                // Otherwise only if the application explicitly ships a signature.json file
597
+                $appNeedsToBeChecked = true;
598
+            }
599
+
600
+            if($appNeedsToBeChecked) {
601
+                $this->verifyAppSignature($appId);
602
+            }
603
+        }
604
+    }
605 605
 }
Please login to merge, or discard this patch.
lib/public/IContainer.php 1 patch
Indentation   +50 added lines, -50 removed lines patch added patch discarded remove patch
@@ -47,58 +47,58 @@
 block discarded – undo
47 47
  */
48 48
 interface IContainer {
49 49
 
50
-	/**
51
-	 * If a parameter is not registered in the container try to instantiate it
52
-	 * by using reflection to find out how to build the class
53
-	 * @param string $name the class name to resolve
54
-	 * @return \stdClass
55
-	 * @since 8.2.0
56
-	 * @throws QueryException if the class could not be found or instantiated
57
-	 */
58
-	public function resolve($name);
50
+    /**
51
+     * If a parameter is not registered in the container try to instantiate it
52
+     * by using reflection to find out how to build the class
53
+     * @param string $name the class name to resolve
54
+     * @return \stdClass
55
+     * @since 8.2.0
56
+     * @throws QueryException if the class could not be found or instantiated
57
+     */
58
+    public function resolve($name);
59 59
 
60
-	/**
61
-	 * Look up a service for a given name in the container.
62
-	 *
63
-	 * @param string $name
64
-	 * @return mixed
65
-	 * @throws QueryException if the query could not be resolved
66
-	 * @since 6.0.0
67
-	 */
68
-	public function query($name);
60
+    /**
61
+     * Look up a service for a given name in the container.
62
+     *
63
+     * @param string $name
64
+     * @return mixed
65
+     * @throws QueryException if the query could not be resolved
66
+     * @since 6.0.0
67
+     */
68
+    public function query($name);
69 69
 
70
-	/**
71
-	 * A value is stored in the container with it's corresponding name
72
-	 *
73
-	 * @param string $name
74
-	 * @param mixed $value
75
-	 * @return void
76
-	 * @since 6.0.0
77
-	 */
78
-	public function registerParameter($name, $value);
70
+    /**
71
+     * A value is stored in the container with it's corresponding name
72
+     *
73
+     * @param string $name
74
+     * @param mixed $value
75
+     * @return void
76
+     * @since 6.0.0
77
+     */
78
+    public function registerParameter($name, $value);
79 79
 
80
-	/**
81
-	 * A service is registered in the container where a closure is passed in which will actually
82
-	 * create the service on demand.
83
-	 * In case the parameter $shared is set to true (the default usage) the once created service will remain in
84
-	 * memory and be reused on subsequent calls.
85
-	 * In case the parameter is false the service will be recreated on every call.
86
-	 *
87
-	 * @param string $name
88
-	 * @param \Closure $closure
89
-	 * @param bool $shared
90
-	 * @return void
91
-	 * @since 6.0.0
92
-	 */
93
-	public function registerService($name, Closure $closure, $shared = true);
80
+    /**
81
+     * A service is registered in the container where a closure is passed in which will actually
82
+     * create the service on demand.
83
+     * In case the parameter $shared is set to true (the default usage) the once created service will remain in
84
+     * memory and be reused on subsequent calls.
85
+     * In case the parameter is false the service will be recreated on every call.
86
+     *
87
+     * @param string $name
88
+     * @param \Closure $closure
89
+     * @param bool $shared
90
+     * @return void
91
+     * @since 6.0.0
92
+     */
93
+    public function registerService($name, Closure $closure, $shared = true);
94 94
 
95
-	/**
96
-	 * Shortcut for returning a service from a service under a different key,
97
-	 * e.g. to tell the container to return a class when queried for an
98
-	 * interface
99
-	 * @param string $alias the alias that should be registered
100
-	 * @param string $target the target that should be resolved instead
101
-	 * @since 8.2.0
102
-	 */
103
-	public function registerAlias($alias, $target);
95
+    /**
96
+     * Shortcut for returning a service from a service under a different key,
97
+     * e.g. to tell the container to return a class when queried for an
98
+     * interface
99
+     * @param string $alias the alias that should be registered
100
+     * @param string $target the target that should be resolved instead
101
+     * @since 8.2.0
102
+     */
103
+    public function registerAlias($alias, $target);
104 104
 }
Please login to merge, or discard this patch.
lib/private/AppFramework/App.php 2 patches
Indentation   +133 added lines, -133 removed lines patch added patch discarded remove patch
@@ -42,143 +42,143 @@
 block discarded – undo
42 42
  */
43 43
 class App {
44 44
 
45
-	/** @var string[] */
46
-	private static $nameSpaceCache = [];
47
-
48
-	/**
49
-	 * Turns an app id into a namespace by either reading the appinfo.xml's
50
-	 * namespace tag or uppercasing the appid's first letter
51
-	 * @param string $appId the app id
52
-	 * @param string $topNamespace the namespace which should be prepended to
53
-	 * the transformed app id, defaults to OCA\
54
-	 * @return string the starting namespace for the app
55
-	 */
56
-	public static function buildAppNamespace($appId, $topNamespace='OCA\\') {
57
-		// Hit the cache!
58
-		if (isset(self::$nameSpaceCache[$appId])) {
59
-			return $topNamespace . self::$nameSpaceCache[$appId];
60
-		}
61
-
62
-		$appInfo = \OC_App::getAppInfo($appId);
63
-		if (isset($appInfo['namespace'])) {
64
-			self::$nameSpaceCache[$appId] = trim($appInfo['namespace']);
65
-		} else {
66
-			// if the tag is not found, fall back to uppercasing the first letter
67
-			self::$nameSpaceCache[$appId] = ucfirst($appId);
68
-		}
69
-
70
-		return $topNamespace . self::$nameSpaceCache[$appId];
71
-	}
72
-
73
-
74
-	/**
75
-	 * Shortcut for calling a controller method and printing the result
76
-	 * @param string $controllerName the name of the controller under which it is
77
-	 *                               stored in the DI container
78
-	 * @param string $methodName the method that you want to call
79
-	 * @param DIContainer $container an instance of a pimple container.
80
-	 * @param array $urlParams list of URL parameters (optional)
81
-	 */
82
-	public static function main($controllerName, $methodName, DIContainer $container, array $urlParams = null) {
83
-		if (!is_null($urlParams)) {
84
-			$container['OCP\\IRequest']->setUrlParameters($urlParams);
85
-		} else if (isset($container['urlParams']) && !is_null($container['urlParams'])) {
86
-			$container['OCP\\IRequest']->setUrlParameters($container['urlParams']);
87
-		}
88
-		$appName = $container['AppName'];
89
-
90
-		// first try $controllerName then go for \OCA\AppName\Controller\$controllerName
91
-		try {
92
-			$controller = $container->query($controllerName);
93
-		} catch(QueryException $e) {
94
-			if ($appName === 'core') {
95
-				$appNameSpace = 'OC\\Core';
96
-			} else if ($appName === 'settings') {
97
-				$appNameSpace = 'OC\\Settings';
98
-			} else {
99
-				$appNameSpace = self::buildAppNamespace($appName);
100
-			}
101
-			$controllerName = $appNameSpace . '\\Controller\\' . $controllerName;
102
-			$controller = $container->query($controllerName);
103
-		}
104
-
105
-		// initialize the dispatcher and run all the middleware before the controller
106
-		/** @var Dispatcher $dispatcher */
107
-		$dispatcher = $container['Dispatcher'];
108
-
109
-		list(
110
-			$httpHeaders,
111
-			$responseHeaders,
112
-			$responseCookies,
113
-			$output,
114
-			$response
115
-		) = $dispatcher->dispatch($controller, $methodName);
116
-
117
-		$io = $container['OCP\\AppFramework\\Http\\IOutput'];
118
-
119
-		if(!is_null($httpHeaders)) {
120
-			$io->setHeader($httpHeaders);
121
-		}
122
-
123
-		foreach($responseHeaders as $name => $value) {
124
-			$io->setHeader($name . ': ' . $value);
125
-		}
126
-
127
-		foreach($responseCookies as $name => $value) {
128
-			$expireDate = null;
129
-			if($value['expireDate'] instanceof \DateTime) {
130
-				$expireDate = $value['expireDate']->getTimestamp();
131
-			}
132
-			$io->setCookie(
133
-				$name,
134
-				$value['value'],
135
-				$expireDate,
136
-				$container->getServer()->getWebRoot(),
137
-				null,
138
-				$container->getServer()->getRequest()->getServerProtocol() === 'https',
139
-				true
140
-			);
141
-		}
142
-
143
-		/*
45
+    /** @var string[] */
46
+    private static $nameSpaceCache = [];
47
+
48
+    /**
49
+     * Turns an app id into a namespace by either reading the appinfo.xml's
50
+     * namespace tag or uppercasing the appid's first letter
51
+     * @param string $appId the app id
52
+     * @param string $topNamespace the namespace which should be prepended to
53
+     * the transformed app id, defaults to OCA\
54
+     * @return string the starting namespace for the app
55
+     */
56
+    public static function buildAppNamespace($appId, $topNamespace='OCA\\') {
57
+        // Hit the cache!
58
+        if (isset(self::$nameSpaceCache[$appId])) {
59
+            return $topNamespace . self::$nameSpaceCache[$appId];
60
+        }
61
+
62
+        $appInfo = \OC_App::getAppInfo($appId);
63
+        if (isset($appInfo['namespace'])) {
64
+            self::$nameSpaceCache[$appId] = trim($appInfo['namespace']);
65
+        } else {
66
+            // if the tag is not found, fall back to uppercasing the first letter
67
+            self::$nameSpaceCache[$appId] = ucfirst($appId);
68
+        }
69
+
70
+        return $topNamespace . self::$nameSpaceCache[$appId];
71
+    }
72
+
73
+
74
+    /**
75
+     * Shortcut for calling a controller method and printing the result
76
+     * @param string $controllerName the name of the controller under which it is
77
+     *                               stored in the DI container
78
+     * @param string $methodName the method that you want to call
79
+     * @param DIContainer $container an instance of a pimple container.
80
+     * @param array $urlParams list of URL parameters (optional)
81
+     */
82
+    public static function main($controllerName, $methodName, DIContainer $container, array $urlParams = null) {
83
+        if (!is_null($urlParams)) {
84
+            $container['OCP\\IRequest']->setUrlParameters($urlParams);
85
+        } else if (isset($container['urlParams']) && !is_null($container['urlParams'])) {
86
+            $container['OCP\\IRequest']->setUrlParameters($container['urlParams']);
87
+        }
88
+        $appName = $container['AppName'];
89
+
90
+        // first try $controllerName then go for \OCA\AppName\Controller\$controllerName
91
+        try {
92
+            $controller = $container->query($controllerName);
93
+        } catch(QueryException $e) {
94
+            if ($appName === 'core') {
95
+                $appNameSpace = 'OC\\Core';
96
+            } else if ($appName === 'settings') {
97
+                $appNameSpace = 'OC\\Settings';
98
+            } else {
99
+                $appNameSpace = self::buildAppNamespace($appName);
100
+            }
101
+            $controllerName = $appNameSpace . '\\Controller\\' . $controllerName;
102
+            $controller = $container->query($controllerName);
103
+        }
104
+
105
+        // initialize the dispatcher and run all the middleware before the controller
106
+        /** @var Dispatcher $dispatcher */
107
+        $dispatcher = $container['Dispatcher'];
108
+
109
+        list(
110
+            $httpHeaders,
111
+            $responseHeaders,
112
+            $responseCookies,
113
+            $output,
114
+            $response
115
+        ) = $dispatcher->dispatch($controller, $methodName);
116
+
117
+        $io = $container['OCP\\AppFramework\\Http\\IOutput'];
118
+
119
+        if(!is_null($httpHeaders)) {
120
+            $io->setHeader($httpHeaders);
121
+        }
122
+
123
+        foreach($responseHeaders as $name => $value) {
124
+            $io->setHeader($name . ': ' . $value);
125
+        }
126
+
127
+        foreach($responseCookies as $name => $value) {
128
+            $expireDate = null;
129
+            if($value['expireDate'] instanceof \DateTime) {
130
+                $expireDate = $value['expireDate']->getTimestamp();
131
+            }
132
+            $io->setCookie(
133
+                $name,
134
+                $value['value'],
135
+                $expireDate,
136
+                $container->getServer()->getWebRoot(),
137
+                null,
138
+                $container->getServer()->getRequest()->getServerProtocol() === 'https',
139
+                true
140
+            );
141
+        }
142
+
143
+        /*
144 144
 		 * Status 204 does not have a body and no Content Length
145 145
 		 * Status 304 does not have a body and does not need a Content Length
146 146
 		 * https://tools.ietf.org/html/rfc7230#section-3.3
147 147
 		 * https://tools.ietf.org/html/rfc7230#section-3.3.2
148 148
 		 */
149
-		if ($httpHeaders !== Http::STATUS_NO_CONTENT && $httpHeaders !== Http::STATUS_NOT_MODIFIED) {
150
-			if ($response instanceof ICallbackResponse) {
151
-				$response->callback($io);
152
-			} else if (!is_null($output)) {
153
-				$io->setHeader('Content-Length: ' . strlen($output));
154
-				$io->setOutput($output);
155
-			}
156
-		}
157
-
158
-	}
159
-
160
-	/**
161
-	 * Shortcut for calling a controller method and printing the result.
162
-	 * Similar to App:main except that no headers will be sent.
163
-	 * This should be used for example when registering sections via
164
-	 * \OC\AppFramework\Core\API::registerAdmin()
165
-	 *
166
-	 * @param string $controllerName the name of the controller under which it is
167
-	 *                               stored in the DI container
168
-	 * @param string $methodName the method that you want to call
169
-	 * @param array $urlParams an array with variables extracted from the routes
170
-	 * @param DIContainer $container an instance of a pimple container.
171
-	 */
172
-	public static function part($controllerName, $methodName, array $urlParams,
173
-								DIContainer $container){
174
-
175
-		$container['urlParams'] = $urlParams;
176
-		$controller = $container[$controllerName];
177
-
178
-		$dispatcher = $container['Dispatcher'];
179
-
180
-		list(, , $output) =  $dispatcher->dispatch($controller, $methodName);
181
-		return $output;
182
-	}
149
+        if ($httpHeaders !== Http::STATUS_NO_CONTENT && $httpHeaders !== Http::STATUS_NOT_MODIFIED) {
150
+            if ($response instanceof ICallbackResponse) {
151
+                $response->callback($io);
152
+            } else if (!is_null($output)) {
153
+                $io->setHeader('Content-Length: ' . strlen($output));
154
+                $io->setOutput($output);
155
+            }
156
+        }
157
+
158
+    }
159
+
160
+    /**
161
+     * Shortcut for calling a controller method and printing the result.
162
+     * Similar to App:main except that no headers will be sent.
163
+     * This should be used for example when registering sections via
164
+     * \OC\AppFramework\Core\API::registerAdmin()
165
+     *
166
+     * @param string $controllerName the name of the controller under which it is
167
+     *                               stored in the DI container
168
+     * @param string $methodName the method that you want to call
169
+     * @param array $urlParams an array with variables extracted from the routes
170
+     * @param DIContainer $container an instance of a pimple container.
171
+     */
172
+    public static function part($controllerName, $methodName, array $urlParams,
173
+                                DIContainer $container){
174
+
175
+        $container['urlParams'] = $urlParams;
176
+        $controller = $container[$controllerName];
177
+
178
+        $dispatcher = $container['Dispatcher'];
179
+
180
+        list(, , $output) =  $dispatcher->dispatch($controller, $methodName);
181
+        return $output;
182
+    }
183 183
 
184 184
 }
Please login to merge, or discard this patch.
Spacing   +13 added lines, -13 removed lines patch added patch discarded remove patch
@@ -53,10 +53,10 @@  discard block
 block discarded – undo
53 53
 	 * the transformed app id, defaults to OCA\
54 54
 	 * @return string the starting namespace for the app
55 55
 	 */
56
-	public static function buildAppNamespace($appId, $topNamespace='OCA\\') {
56
+	public static function buildAppNamespace($appId, $topNamespace = 'OCA\\') {
57 57
 		// Hit the cache!
58 58
 		if (isset(self::$nameSpaceCache[$appId])) {
59
-			return $topNamespace . self::$nameSpaceCache[$appId];
59
+			return $topNamespace.self::$nameSpaceCache[$appId];
60 60
 		}
61 61
 
62 62
 		$appInfo = \OC_App::getAppInfo($appId);
@@ -67,7 +67,7 @@  discard block
 block discarded – undo
67 67
 			self::$nameSpaceCache[$appId] = ucfirst($appId);
68 68
 		}
69 69
 
70
-		return $topNamespace . self::$nameSpaceCache[$appId];
70
+		return $topNamespace.self::$nameSpaceCache[$appId];
71 71
 	}
72 72
 
73 73
 
@@ -90,7 +90,7 @@  discard block
 block discarded – undo
90 90
 		// first try $controllerName then go for \OCA\AppName\Controller\$controllerName
91 91
 		try {
92 92
 			$controller = $container->query($controllerName);
93
-		} catch(QueryException $e) {
93
+		} catch (QueryException $e) {
94 94
 			if ($appName === 'core') {
95 95
 				$appNameSpace = 'OC\\Core';
96 96
 			} else if ($appName === 'settings') {
@@ -98,7 +98,7 @@  discard block
 block discarded – undo
98 98
 			} else {
99 99
 				$appNameSpace = self::buildAppNamespace($appName);
100 100
 			}
101
-			$controllerName = $appNameSpace . '\\Controller\\' . $controllerName;
101
+			$controllerName = $appNameSpace.'\\Controller\\'.$controllerName;
102 102
 			$controller = $container->query($controllerName);
103 103
 		}
104 104
 
@@ -116,17 +116,17 @@  discard block
 block discarded – undo
116 116
 
117 117
 		$io = $container['OCP\\AppFramework\\Http\\IOutput'];
118 118
 
119
-		if(!is_null($httpHeaders)) {
119
+		if (!is_null($httpHeaders)) {
120 120
 			$io->setHeader($httpHeaders);
121 121
 		}
122 122
 
123
-		foreach($responseHeaders as $name => $value) {
124
-			$io->setHeader($name . ': ' . $value);
123
+		foreach ($responseHeaders as $name => $value) {
124
+			$io->setHeader($name.': '.$value);
125 125
 		}
126 126
 
127
-		foreach($responseCookies as $name => $value) {
127
+		foreach ($responseCookies as $name => $value) {
128 128
 			$expireDate = null;
129
-			if($value['expireDate'] instanceof \DateTime) {
129
+			if ($value['expireDate'] instanceof \DateTime) {
130 130
 				$expireDate = $value['expireDate']->getTimestamp();
131 131
 			}
132 132
 			$io->setCookie(
@@ -150,7 +150,7 @@  discard block
 block discarded – undo
150 150
 			if ($response instanceof ICallbackResponse) {
151 151
 				$response->callback($io);
152 152
 			} else if (!is_null($output)) {
153
-				$io->setHeader('Content-Length: ' . strlen($output));
153
+				$io->setHeader('Content-Length: '.strlen($output));
154 154
 				$io->setOutput($output);
155 155
 			}
156 156
 		}
@@ -170,14 +170,14 @@  discard block
 block discarded – undo
170 170
 	 * @param DIContainer $container an instance of a pimple container.
171 171
 	 */
172 172
 	public static function part($controllerName, $methodName, array $urlParams,
173
-								DIContainer $container){
173
+								DIContainer $container) {
174 174
 
175 175
 		$container['urlParams'] = $urlParams;
176 176
 		$controller = $container[$controllerName];
177 177
 
178 178
 		$dispatcher = $container['Dispatcher'];
179 179
 
180
-		list(, , $output) =  $dispatcher->dispatch($controller, $methodName);
180
+		list(,, $output) = $dispatcher->dispatch($controller, $methodName);
181 181
 		return $output;
182 182
 	}
183 183
 
Please login to merge, or discard this patch.
lib/private/Template/JSResourceLocator.php 3 patches
Doc Comments   +6 added lines patch added patch discarded remove patch
@@ -30,6 +30,9 @@  discard block
 block discarded – undo
30 30
 	/** @var JSCombiner */
31 31
 	protected $jsCombiner;
32 32
 
33
+	/**
34
+	 * @param string $theme
35
+	 */
33 36
 	public function __construct(\OCP\ILogger $logger, $theme, array $core_map, array $party_map, JSCombiner $JSCombiner) {
34 37
 		parent::__construct($logger, $theme, $core_map, $party_map);
35 38
 
@@ -91,6 +94,9 @@  discard block
 block discarded – undo
91 94
 	public function doFindTheme($script) {
92 95
 	}
93 96
 
97
+	/**
98
+	 * @param string $file
99
+	 */
94 100
 	protected function cacheAndAppendCombineJsonIfExist($root, $file, $app = 'core') {
95 101
 		if (is_file($root.'/'.$file)) {
96 102
 			if ($this->jsCombiner->process($root, $file, $app)) {
Please login to merge, or discard this patch.
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -71,26 +71,26 @@
 block discarded – undo
71 71
 		}
72 72
 
73 73
 		$app = substr($script, 0, strpos($script, '/'));
74
-		$script = substr($script, strpos($script, '/')+1);
74
+		$script = substr($script, strpos($script, '/') + 1);
75 75
 		$app_path = \OC_App::getAppPath($app);
76 76
 		$app_url = \OC_App::getAppWebPath($app);
77 77
 
78 78
 		// missing translations files fill be ignored
79 79
 		if (strpos($script, 'l10n/') === 0) {
80
-			$this->appendIfExist($app_path, $script . '.js', $app_url);
80
+			$this->appendIfExist($app_path, $script.'.js', $app_url);
81 81
 			return;
82 82
 		}
83 83
 
84 84
 		if ($app_path === false && $app_url === false) {
85 85
 			$this->logger->error('Could not find resource {resource} to load', [
86
-				'resource' => $app . '/' . $script . '.js',
86
+				'resource' => $app.'/'.$script.'.js',
87 87
 				'app' => 'jsresourceloader',
88 88
 			]);
89 89
 			return;
90 90
 		}
91 91
 
92 92
 		if (!$this->cacheAndAppendCombineJsonIfExist($app_path, $script.'.json', $app)) {
93
-			$this->append($app_path, $script . '.js', $app_url);
93
+			$this->append($app_path, $script.'.js', $app_url);
94 94
 		}
95 95
 	}
96 96
 
Please login to merge, or discard this patch.
Indentation   +98 added lines, -98 removed lines patch added patch discarded remove patch
@@ -28,102 +28,102 @@
 block discarded – undo
28 28
 
29 29
 class JSResourceLocator extends ResourceLocator {
30 30
 
31
-	/** @var JSCombiner */
32
-	protected $jsCombiner;
33
-
34
-	public function __construct(\OCP\ILogger $logger, $theme, array $core_map, array $party_map, JSCombiner $JSCombiner) {
35
-		parent::__construct($logger, $theme, $core_map, $party_map);
36
-
37
-		$this->jsCombiner = $JSCombiner;
38
-	}
39
-
40
-	/**
41
-	 * @param string $script
42
-	 */
43
-	public function doFind($script) {
44
-		$theme_dir = 'themes/'.$this->theme.'/';
45
-		if (strpos($script, '3rdparty') === 0
46
-			&& $this->appendIfExist($this->thirdpartyroot, $script.'.js')) {
47
-			return;
48
-		}
49
-
50
-		if (strpos($script, '/l10n/') !== false) {
51
-			// For language files we try to load them all, so themes can overwrite
52
-			// single l10n strings without having to translate all of them.
53
-			$found = 0;
54
-			$found += $this->appendIfExist($this->serverroot, 'core/'.$script.'.js');
55
-			$found += $this->appendIfExist($this->serverroot, $theme_dir.'core/'.$script.'.js');
56
-			$found += $this->appendIfExist($this->serverroot, $script.'.js');
57
-			$found += $this->appendIfExist($this->serverroot, $theme_dir.$script.'.js');
58
-			$found += $this->appendIfExist($this->serverroot, $theme_dir.'apps/'.$script.'.js');
59
-
60
-			if ($found) {
61
-				return;
62
-			}
63
-		} else if ($this->appendIfExist($this->serverroot, $theme_dir.'apps/'.$script.'.js')
64
-			|| $this->appendIfExist($this->serverroot, $theme_dir.$script.'.js')
65
-			|| $this->appendIfExist($this->serverroot, $script.'.js')
66
-			|| $this->cacheAndAppendCombineJsonIfExist($this->serverroot, $script.'.json')
67
-			|| $this->appendIfExist($this->serverroot, $theme_dir.'core/'.$script.'.js')
68
-			|| $this->appendIfExist($this->serverroot, 'core/'.$script.'.js')
69
-			|| $this->cacheAndAppendCombineJsonIfExist($this->serverroot, 'core/'.$script.'.json')
70
-		) {
71
-			return;
72
-		}
73
-
74
-		$app = substr($script, 0, strpos($script, '/'));
75
-		$script = substr($script, strpos($script, '/')+1);
76
-		$app_path = \OC_App::getAppPath($app);
77
-		$app_url = \OC_App::getAppWebPath($app);
78
-
79
-		if ($app_path !== false) {
80
-			// Account for the possibility of having symlinks in app path. Only
81
-			// do this if $app_path is set, because an empty argument to realpath
82
-			// gets turned into cwd.
83
-			$app_path = realpath($app_path);
84
-		}
85
-
86
-		// missing translations files fill be ignored
87
-		if (strpos($script, 'l10n/') === 0) {
88
-			$this->appendIfExist($app_path, $script . '.js', $app_url);
89
-			return;
90
-		}
91
-
92
-		if ($app_path === false && $app_url === false) {
93
-			$this->logger->error('Could not find resource {resource} to load', [
94
-				'resource' => $app . '/' . $script . '.js',
95
-				'app' => 'jsresourceloader',
96
-			]);
97
-			return;
98
-		}
99
-
100
-		if (!$this->cacheAndAppendCombineJsonIfExist($app_path, $script.'.json', $app)) {
101
-			$this->append($app_path, $script . '.js', $app_url);
102
-		}
103
-	}
104
-
105
-	/**
106
-	 * @param string $script
107
-	 */
108
-	public function doFindTheme($script) {
109
-	}
110
-
111
-	protected function cacheAndAppendCombineJsonIfExist($root, $file, $app = 'core') {
112
-		if (is_file($root.'/'.$file)) {
113
-			if ($this->jsCombiner->process($root, $file, $app)) {
114
-				$this->append($this->serverroot, $this->jsCombiner->getCachedJS($app, $file), false, false);
115
-			} else {
116
-				// Add all the files from the json
117
-				$files = $this->jsCombiner->getContent($root, $file);
118
-				$app_url = \OC_App::getAppWebPath($app);
119
-
120
-				foreach ($files as $jsFile) {
121
-					$this->append($root, $jsFile, $app_url);
122
-				}
123
-			}
124
-			return true;
125
-		}
126
-
127
-		return false;
128
-	}
31
+    /** @var JSCombiner */
32
+    protected $jsCombiner;
33
+
34
+    public function __construct(\OCP\ILogger $logger, $theme, array $core_map, array $party_map, JSCombiner $JSCombiner) {
35
+        parent::__construct($logger, $theme, $core_map, $party_map);
36
+
37
+        $this->jsCombiner = $JSCombiner;
38
+    }
39
+
40
+    /**
41
+     * @param string $script
42
+     */
43
+    public function doFind($script) {
44
+        $theme_dir = 'themes/'.$this->theme.'/';
45
+        if (strpos($script, '3rdparty') === 0
46
+            && $this->appendIfExist($this->thirdpartyroot, $script.'.js')) {
47
+            return;
48
+        }
49
+
50
+        if (strpos($script, '/l10n/') !== false) {
51
+            // For language files we try to load them all, so themes can overwrite
52
+            // single l10n strings without having to translate all of them.
53
+            $found = 0;
54
+            $found += $this->appendIfExist($this->serverroot, 'core/'.$script.'.js');
55
+            $found += $this->appendIfExist($this->serverroot, $theme_dir.'core/'.$script.'.js');
56
+            $found += $this->appendIfExist($this->serverroot, $script.'.js');
57
+            $found += $this->appendIfExist($this->serverroot, $theme_dir.$script.'.js');
58
+            $found += $this->appendIfExist($this->serverroot, $theme_dir.'apps/'.$script.'.js');
59
+
60
+            if ($found) {
61
+                return;
62
+            }
63
+        } else if ($this->appendIfExist($this->serverroot, $theme_dir.'apps/'.$script.'.js')
64
+            || $this->appendIfExist($this->serverroot, $theme_dir.$script.'.js')
65
+            || $this->appendIfExist($this->serverroot, $script.'.js')
66
+            || $this->cacheAndAppendCombineJsonIfExist($this->serverroot, $script.'.json')
67
+            || $this->appendIfExist($this->serverroot, $theme_dir.'core/'.$script.'.js')
68
+            || $this->appendIfExist($this->serverroot, 'core/'.$script.'.js')
69
+            || $this->cacheAndAppendCombineJsonIfExist($this->serverroot, 'core/'.$script.'.json')
70
+        ) {
71
+            return;
72
+        }
73
+
74
+        $app = substr($script, 0, strpos($script, '/'));
75
+        $script = substr($script, strpos($script, '/')+1);
76
+        $app_path = \OC_App::getAppPath($app);
77
+        $app_url = \OC_App::getAppWebPath($app);
78
+
79
+        if ($app_path !== false) {
80
+            // Account for the possibility of having symlinks in app path. Only
81
+            // do this if $app_path is set, because an empty argument to realpath
82
+            // gets turned into cwd.
83
+            $app_path = realpath($app_path);
84
+        }
85
+
86
+        // missing translations files fill be ignored
87
+        if (strpos($script, 'l10n/') === 0) {
88
+            $this->appendIfExist($app_path, $script . '.js', $app_url);
89
+            return;
90
+        }
91
+
92
+        if ($app_path === false && $app_url === false) {
93
+            $this->logger->error('Could not find resource {resource} to load', [
94
+                'resource' => $app . '/' . $script . '.js',
95
+                'app' => 'jsresourceloader',
96
+            ]);
97
+            return;
98
+        }
99
+
100
+        if (!$this->cacheAndAppendCombineJsonIfExist($app_path, $script.'.json', $app)) {
101
+            $this->append($app_path, $script . '.js', $app_url);
102
+        }
103
+    }
104
+
105
+    /**
106
+     * @param string $script
107
+     */
108
+    public function doFindTheme($script) {
109
+    }
110
+
111
+    protected function cacheAndAppendCombineJsonIfExist($root, $file, $app = 'core') {
112
+        if (is_file($root.'/'.$file)) {
113
+            if ($this->jsCombiner->process($root, $file, $app)) {
114
+                $this->append($this->serverroot, $this->jsCombiner->getCachedJS($app, $file), false, false);
115
+            } else {
116
+                // Add all the files from the json
117
+                $files = $this->jsCombiner->getContent($root, $file);
118
+                $app_url = \OC_App::getAppWebPath($app);
119
+
120
+                foreach ($files as $jsFile) {
121
+                    $this->append($root, $jsFile, $app_url);
122
+                }
123
+            }
124
+            return true;
125
+        }
126
+
127
+        return false;
128
+    }
129 129
 }
Please login to merge, or discard this patch.
lib/private/Files/Config/MountProviderCollection.php 2 patches
Indentation   +140 added lines, -140 removed lines patch added patch discarded remove patch
@@ -35,144 +35,144 @@
 block discarded – undo
35 35
 use OCP\IUser;
36 36
 
37 37
 class MountProviderCollection implements IMountProviderCollection, Emitter {
38
-	use EmitterTrait;
39
-
40
-	/**
41
-	 * @var \OCP\Files\Config\IHomeMountProvider[]
42
-	 */
43
-	private $homeProviders = [];
44
-
45
-	/**
46
-	 * @var \OCP\Files\Config\IMountProvider[]
47
-	 */
48
-	private $providers = array();
49
-
50
-	/**
51
-	 * @var \OCP\Files\Storage\IStorageFactory
52
-	 */
53
-	private $loader;
54
-
55
-	/**
56
-	 * @var \OCP\Files\Config\IUserMountCache
57
-	 */
58
-	private $mountCache;
59
-
60
-	/**
61
-	 * @param \OCP\Files\Storage\IStorageFactory $loader
62
-	 * @param IUserMountCache $mountCache
63
-	 */
64
-	public function __construct(IStorageFactory $loader, IUserMountCache $mountCache) {
65
-		$this->loader = $loader;
66
-		$this->mountCache = $mountCache;
67
-	}
68
-
69
-	/**
70
-	 * Get all configured mount points for the user
71
-	 *
72
-	 * @param \OCP\IUser $user
73
-	 * @return \OCP\Files\Mount\IMountPoint[]
74
-	 */
75
-	public function getMountsForUser(IUser $user) {
76
-		$loader = $this->loader;
77
-		$mounts = array_map(function (IMountProvider $provider) use ($user, $loader) {
78
-			return $provider->getMountsForUser($user, $loader);
79
-		}, $this->providers);
80
-		$mounts = array_filter($mounts, function ($result) {
81
-			return is_array($result);
82
-		});
83
-		return array_reduce($mounts, function (array $mounts, array $providerMounts) {
84
-			return array_merge($mounts, $providerMounts);
85
-		}, array());
86
-	}
87
-
88
-	public function addMountForUser(IUser $user, IMountManager $mountManager) {
89
-		// shared mount provider gets to go last since it needs to know existing files
90
-		// to check for name collisions
91
-		$firstMounts = [];
92
-		$firstProviders = array_filter($this->providers, function (IMountProvider $provider) {
93
-			return (get_class($provider) !== 'OCA\Files_Sharing\MountProvider');
94
-		});
95
-		$lastProviders = array_filter($this->providers, function (IMountProvider $provider) {
96
-			return (get_class($provider) === 'OCA\Files_Sharing\MountProvider');
97
-		});
98
-		foreach ($firstProviders as $provider) {
99
-			$mounts = $provider->getMountsForUser($user, $this->loader);
100
-			if (is_array($mounts)) {
101
-				$firstMounts = array_merge($firstMounts, $mounts);
102
-			}
103
-		}
104
-		array_walk($firstMounts, [$mountManager, 'addMount']);
105
-
106
-		$lateMounts = [];
107
-		foreach ($lastProviders as $provider) {
108
-			$mounts = $provider->getMountsForUser($user, $this->loader);
109
-			if (is_array($mounts)) {
110
-				$lateMounts = array_merge($lateMounts, $mounts);
111
-			}
112
-		}
113
-
114
-		array_walk($lateMounts, [$mountManager, 'addMount']);
115
-
116
-		return array_merge($lateMounts, $firstMounts);
117
-	}
118
-
119
-	/**
120
-	 * Get the configured home mount for this user
121
-	 *
122
-	 * @param \OCP\IUser $user
123
-	 * @return \OCP\Files\Mount\IMountPoint
124
-	 * @since 9.1.0
125
-	 */
126
-	public function getHomeMountForUser(IUser $user) {
127
-		/** @var \OCP\Files\Config\IHomeMountProvider[] $providers */
128
-		$providers = array_reverse($this->homeProviders); // call the latest registered provider first to give apps an opportunity to overwrite builtin
129
-		foreach ($providers as $homeProvider) {
130
-			if ($mount = $homeProvider->getHomeMountForUser($user, $this->loader)) {
131
-				$mount->setMountPoint('/' . $user->getUID()); //make sure the mountpoint is what we expect
132
-				return $mount;
133
-			}
134
-		}
135
-		throw new \Exception('No home storage configured for user ' . $user);
136
-	}
137
-
138
-	/**
139
-	 * Add a provider for mount points
140
-	 *
141
-	 * @param \OCP\Files\Config\IMountProvider $provider
142
-	 */
143
-	public function registerProvider(IMountProvider $provider) {
144
-		$this->providers[] = $provider;
145
-
146
-		$this->emit('\OC\Files\Config', 'registerMountProvider', [$provider]);
147
-	}
148
-
149
-	/**
150
-	 * Add a provider for home mount points
151
-	 *
152
-	 * @param \OCP\Files\Config\IHomeMountProvider $provider
153
-	 * @since 9.1.0
154
-	 */
155
-	public function registerHomeProvider(IHomeMountProvider $provider) {
156
-		$this->homeProviders[] = $provider;
157
-		$this->emit('\OC\Files\Config', 'registerHomeMountProvider', [$provider]);
158
-	}
159
-
160
-	/**
161
-	 * Cache mounts for user
162
-	 *
163
-	 * @param IUser $user
164
-	 * @param IMountPoint[] $mountPoints
165
-	 */
166
-	public function registerMounts(IUser $user, array $mountPoints) {
167
-		$this->mountCache->registerMounts($user, $mountPoints);
168
-	}
169
-
170
-	/**
171
-	 * Get the mount cache which can be used to search for mounts without setting up the filesystem
172
-	 *
173
-	 * @return IUserMountCache
174
-	 */
175
-	public function getMountCache() {
176
-		return $this->mountCache;
177
-	}
38
+    use EmitterTrait;
39
+
40
+    /**
41
+     * @var \OCP\Files\Config\IHomeMountProvider[]
42
+     */
43
+    private $homeProviders = [];
44
+
45
+    /**
46
+     * @var \OCP\Files\Config\IMountProvider[]
47
+     */
48
+    private $providers = array();
49
+
50
+    /**
51
+     * @var \OCP\Files\Storage\IStorageFactory
52
+     */
53
+    private $loader;
54
+
55
+    /**
56
+     * @var \OCP\Files\Config\IUserMountCache
57
+     */
58
+    private $mountCache;
59
+
60
+    /**
61
+     * @param \OCP\Files\Storage\IStorageFactory $loader
62
+     * @param IUserMountCache $mountCache
63
+     */
64
+    public function __construct(IStorageFactory $loader, IUserMountCache $mountCache) {
65
+        $this->loader = $loader;
66
+        $this->mountCache = $mountCache;
67
+    }
68
+
69
+    /**
70
+     * Get all configured mount points for the user
71
+     *
72
+     * @param \OCP\IUser $user
73
+     * @return \OCP\Files\Mount\IMountPoint[]
74
+     */
75
+    public function getMountsForUser(IUser $user) {
76
+        $loader = $this->loader;
77
+        $mounts = array_map(function (IMountProvider $provider) use ($user, $loader) {
78
+            return $provider->getMountsForUser($user, $loader);
79
+        }, $this->providers);
80
+        $mounts = array_filter($mounts, function ($result) {
81
+            return is_array($result);
82
+        });
83
+        return array_reduce($mounts, function (array $mounts, array $providerMounts) {
84
+            return array_merge($mounts, $providerMounts);
85
+        }, array());
86
+    }
87
+
88
+    public function addMountForUser(IUser $user, IMountManager $mountManager) {
89
+        // shared mount provider gets to go last since it needs to know existing files
90
+        // to check for name collisions
91
+        $firstMounts = [];
92
+        $firstProviders = array_filter($this->providers, function (IMountProvider $provider) {
93
+            return (get_class($provider) !== 'OCA\Files_Sharing\MountProvider');
94
+        });
95
+        $lastProviders = array_filter($this->providers, function (IMountProvider $provider) {
96
+            return (get_class($provider) === 'OCA\Files_Sharing\MountProvider');
97
+        });
98
+        foreach ($firstProviders as $provider) {
99
+            $mounts = $provider->getMountsForUser($user, $this->loader);
100
+            if (is_array($mounts)) {
101
+                $firstMounts = array_merge($firstMounts, $mounts);
102
+            }
103
+        }
104
+        array_walk($firstMounts, [$mountManager, 'addMount']);
105
+
106
+        $lateMounts = [];
107
+        foreach ($lastProviders as $provider) {
108
+            $mounts = $provider->getMountsForUser($user, $this->loader);
109
+            if (is_array($mounts)) {
110
+                $lateMounts = array_merge($lateMounts, $mounts);
111
+            }
112
+        }
113
+
114
+        array_walk($lateMounts, [$mountManager, 'addMount']);
115
+
116
+        return array_merge($lateMounts, $firstMounts);
117
+    }
118
+
119
+    /**
120
+     * Get the configured home mount for this user
121
+     *
122
+     * @param \OCP\IUser $user
123
+     * @return \OCP\Files\Mount\IMountPoint
124
+     * @since 9.1.0
125
+     */
126
+    public function getHomeMountForUser(IUser $user) {
127
+        /** @var \OCP\Files\Config\IHomeMountProvider[] $providers */
128
+        $providers = array_reverse($this->homeProviders); // call the latest registered provider first to give apps an opportunity to overwrite builtin
129
+        foreach ($providers as $homeProvider) {
130
+            if ($mount = $homeProvider->getHomeMountForUser($user, $this->loader)) {
131
+                $mount->setMountPoint('/' . $user->getUID()); //make sure the mountpoint is what we expect
132
+                return $mount;
133
+            }
134
+        }
135
+        throw new \Exception('No home storage configured for user ' . $user);
136
+    }
137
+
138
+    /**
139
+     * Add a provider for mount points
140
+     *
141
+     * @param \OCP\Files\Config\IMountProvider $provider
142
+     */
143
+    public function registerProvider(IMountProvider $provider) {
144
+        $this->providers[] = $provider;
145
+
146
+        $this->emit('\OC\Files\Config', 'registerMountProvider', [$provider]);
147
+    }
148
+
149
+    /**
150
+     * Add a provider for home mount points
151
+     *
152
+     * @param \OCP\Files\Config\IHomeMountProvider $provider
153
+     * @since 9.1.0
154
+     */
155
+    public function registerHomeProvider(IHomeMountProvider $provider) {
156
+        $this->homeProviders[] = $provider;
157
+        $this->emit('\OC\Files\Config', 'registerHomeMountProvider', [$provider]);
158
+    }
159
+
160
+    /**
161
+     * Cache mounts for user
162
+     *
163
+     * @param IUser $user
164
+     * @param IMountPoint[] $mountPoints
165
+     */
166
+    public function registerMounts(IUser $user, array $mountPoints) {
167
+        $this->mountCache->registerMounts($user, $mountPoints);
168
+    }
169
+
170
+    /**
171
+     * Get the mount cache which can be used to search for mounts without setting up the filesystem
172
+     *
173
+     * @return IUserMountCache
174
+     */
175
+    public function getMountCache() {
176
+        return $this->mountCache;
177
+    }
178 178
 }
Please login to merge, or discard this patch.
Spacing   +7 added lines, -7 removed lines patch added patch discarded remove patch
@@ -74,13 +74,13 @@  discard block
 block discarded – undo
74 74
 	 */
75 75
 	public function getMountsForUser(IUser $user) {
76 76
 		$loader = $this->loader;
77
-		$mounts = array_map(function (IMountProvider $provider) use ($user, $loader) {
77
+		$mounts = array_map(function(IMountProvider $provider) use ($user, $loader) {
78 78
 			return $provider->getMountsForUser($user, $loader);
79 79
 		}, $this->providers);
80
-		$mounts = array_filter($mounts, function ($result) {
80
+		$mounts = array_filter($mounts, function($result) {
81 81
 			return is_array($result);
82 82
 		});
83
-		return array_reduce($mounts, function (array $mounts, array $providerMounts) {
83
+		return array_reduce($mounts, function(array $mounts, array $providerMounts) {
84 84
 			return array_merge($mounts, $providerMounts);
85 85
 		}, array());
86 86
 	}
@@ -89,10 +89,10 @@  discard block
 block discarded – undo
89 89
 		// shared mount provider gets to go last since it needs to know existing files
90 90
 		// to check for name collisions
91 91
 		$firstMounts = [];
92
-		$firstProviders = array_filter($this->providers, function (IMountProvider $provider) {
92
+		$firstProviders = array_filter($this->providers, function(IMountProvider $provider) {
93 93
 			return (get_class($provider) !== 'OCA\Files_Sharing\MountProvider');
94 94
 		});
95
-		$lastProviders = array_filter($this->providers, function (IMountProvider $provider) {
95
+		$lastProviders = array_filter($this->providers, function(IMountProvider $provider) {
96 96
 			return (get_class($provider) === 'OCA\Files_Sharing\MountProvider');
97 97
 		});
98 98
 		foreach ($firstProviders as $provider) {
@@ -128,11 +128,11 @@  discard block
 block discarded – undo
128 128
 		$providers = array_reverse($this->homeProviders); // call the latest registered provider first to give apps an opportunity to overwrite builtin
129 129
 		foreach ($providers as $homeProvider) {
130 130
 			if ($mount = $homeProvider->getHomeMountForUser($user, $this->loader)) {
131
-				$mount->setMountPoint('/' . $user->getUID()); //make sure the mountpoint is what we expect
131
+				$mount->setMountPoint('/'.$user->getUID()); //make sure the mountpoint is what we expect
132 132
 				return $mount;
133 133
 			}
134 134
 		}
135
-		throw new \Exception('No home storage configured for user ' . $user);
135
+		throw new \Exception('No home storage configured for user '.$user);
136 136
 	}
137 137
 
138 138
 	/**
Please login to merge, or discard this patch.
apps/files_trashbin/lib/Helper.php 2 patches
Indentation   +86 added lines, -86 removed lines patch added patch discarded remove patch
@@ -30,97 +30,97 @@
 block discarded – undo
30 30
 use OCP\Files\Cache\ICacheEntry;
31 31
 
32 32
 class Helper {
33
-	/**
34
-	 * Retrieves the contents of a trash bin directory.
35
-	 *
36
-	 * @param string $dir path to the directory inside the trashbin
37
-	 * or empty to retrieve the root of the trashbin
38
-	 * @param string $user
39
-	 * @param string $sortAttribute attribute to sort on or empty to disable sorting
40
-	 * @param bool $sortDescending true for descending sort, false otherwise
41
-	 * @return \OCP\Files\FileInfo[]
42
-	 */
43
-	public static function getTrashFiles($dir, $user, $sortAttribute = '', $sortDescending = false) {
44
-		$result = array();
45
-		$timestamp = null;
33
+    /**
34
+     * Retrieves the contents of a trash bin directory.
35
+     *
36
+     * @param string $dir path to the directory inside the trashbin
37
+     * or empty to retrieve the root of the trashbin
38
+     * @param string $user
39
+     * @param string $sortAttribute attribute to sort on or empty to disable sorting
40
+     * @param bool $sortDescending true for descending sort, false otherwise
41
+     * @return \OCP\Files\FileInfo[]
42
+     */
43
+    public static function getTrashFiles($dir, $user, $sortAttribute = '', $sortDescending = false) {
44
+        $result = array();
45
+        $timestamp = null;
46 46
 
47
-		$view = new \OC\Files\View('/' . $user . '/files_trashbin/files');
47
+        $view = new \OC\Files\View('/' . $user . '/files_trashbin/files');
48 48
 
49
-		if (ltrim($dir, '/') !== '' && !$view->is_dir($dir)) {
50
-			throw new \Exception('Directory does not exists');
51
-		}
49
+        if (ltrim($dir, '/') !== '' && !$view->is_dir($dir)) {
50
+            throw new \Exception('Directory does not exists');
51
+        }
52 52
 
53
-		$mount = $view->getMount($dir);
54
-		$storage = $mount->getStorage();
55
-		$absoluteDir = $view->getAbsolutePath($dir);
56
-		$internalPath = $mount->getInternalPath($absoluteDir);
53
+        $mount = $view->getMount($dir);
54
+        $storage = $mount->getStorage();
55
+        $absoluteDir = $view->getAbsolutePath($dir);
56
+        $internalPath = $mount->getInternalPath($absoluteDir);
57 57
 
58
-		$originalLocations = \OCA\Files_Trashbin\Trashbin::getLocations($user);
59
-		$dirContent = $storage->getCache()->getFolderContents($mount->getInternalPath($view->getAbsolutePath($dir)));
60
-		foreach ($dirContent as $entry) {
61
-			$entryName = $entry->getName();
62
-			$id = $entry->getId();
63
-			$name = $entryName;
64
-			if ($dir === '' || $dir === '/') {
65
-				$pathparts = pathinfo($entryName);
66
-				$timestamp = substr($pathparts['extension'], 1);
67
-				$name = $pathparts['filename'];
58
+        $originalLocations = \OCA\Files_Trashbin\Trashbin::getLocations($user);
59
+        $dirContent = $storage->getCache()->getFolderContents($mount->getInternalPath($view->getAbsolutePath($dir)));
60
+        foreach ($dirContent as $entry) {
61
+            $entryName = $entry->getName();
62
+            $id = $entry->getId();
63
+            $name = $entryName;
64
+            if ($dir === '' || $dir === '/') {
65
+                $pathparts = pathinfo($entryName);
66
+                $timestamp = substr($pathparts['extension'], 1);
67
+                $name = $pathparts['filename'];
68 68
 
69
-			} else if ($timestamp === null) {
70
-				// for subfolders we need to calculate the timestamp only once
71
-				$parts = explode('/', ltrim($dir, '/'));
72
-				$timestamp = substr(pathinfo($parts[0], PATHINFO_EXTENSION), 1);
73
-			}
74
-			$originalPath = '';
75
-			$originalName = substr($entryName, 0, -strlen($timestamp)-2);
76
-			if (isset($originalLocations[$originalName][$timestamp])) {
77
-				$originalPath = $originalLocations[$originalName][$timestamp];
78
-				if (substr($originalPath, -1) === '/') {
79
-					$originalPath = substr($originalPath, 0, -1);
80
-				}
81
-			}
82
-			$type = $entry->getMimeType() === ICacheEntry::DIRECTORY_MIMETYPE ? 'dir' : 'file';
83
-			$i = array(
84
-				'name' => $name,
85
-				'mtime' => $timestamp,
86
-				'mimetype' => $type === 'dir' ? 'httpd/unix-directory' : \OC::$server->getMimeTypeDetector()->detectPath($name),
87
-				'type' => $type,
88
-				'directory' => ($dir === '/') ? '' : $dir,
89
-				'size' => $entry->getSize(),
90
-				'etag' => '',
91
-				'permissions' => Constants::PERMISSION_ALL - Constants::PERMISSION_SHARE
92
-			);
93
-			if ($originalPath) {
94
-				if ($originalPath !== '.') {
95
-					$i['extraData'] = $originalPath . '/' . $originalName;
96
-				} else {
97
-					$i['extraData'] = $originalName;
98
-				}
99
-			}
100
-			$result[] = new FileInfo($absoluteDir . '/' . $i['name'], $storage, $internalPath . '/' . $i['name'], $i, $mount);
101
-		}
69
+            } else if ($timestamp === null) {
70
+                // for subfolders we need to calculate the timestamp only once
71
+                $parts = explode('/', ltrim($dir, '/'));
72
+                $timestamp = substr(pathinfo($parts[0], PATHINFO_EXTENSION), 1);
73
+            }
74
+            $originalPath = '';
75
+            $originalName = substr($entryName, 0, -strlen($timestamp)-2);
76
+            if (isset($originalLocations[$originalName][$timestamp])) {
77
+                $originalPath = $originalLocations[$originalName][$timestamp];
78
+                if (substr($originalPath, -1) === '/') {
79
+                    $originalPath = substr($originalPath, 0, -1);
80
+                }
81
+            }
82
+            $type = $entry->getMimeType() === ICacheEntry::DIRECTORY_MIMETYPE ? 'dir' : 'file';
83
+            $i = array(
84
+                'name' => $name,
85
+                'mtime' => $timestamp,
86
+                'mimetype' => $type === 'dir' ? 'httpd/unix-directory' : \OC::$server->getMimeTypeDetector()->detectPath($name),
87
+                'type' => $type,
88
+                'directory' => ($dir === '/') ? '' : $dir,
89
+                'size' => $entry->getSize(),
90
+                'etag' => '',
91
+                'permissions' => Constants::PERMISSION_ALL - Constants::PERMISSION_SHARE
92
+            );
93
+            if ($originalPath) {
94
+                if ($originalPath !== '.') {
95
+                    $i['extraData'] = $originalPath . '/' . $originalName;
96
+                } else {
97
+                    $i['extraData'] = $originalName;
98
+                }
99
+            }
100
+            $result[] = new FileInfo($absoluteDir . '/' . $i['name'], $storage, $internalPath . '/' . $i['name'], $i, $mount);
101
+        }
102 102
 
103
-		if ($sortAttribute !== '') {
104
-			return \OCA\Files\Helper::sortFiles($result, $sortAttribute, $sortDescending);
105
-		}
106
-		return $result;
107
-	}
103
+        if ($sortAttribute !== '') {
104
+            return \OCA\Files\Helper::sortFiles($result, $sortAttribute, $sortDescending);
105
+        }
106
+        return $result;
107
+    }
108 108
 
109
-	/**
110
-	 * Format file infos for JSON
111
-	 *
112
-	 * @param \OCP\Files\FileInfo[] $fileInfos file infos
113
-	 */
114
-	public static function formatFileInfos($fileInfos) {
115
-		$files = array();
116
-		$id = 0;
117
-		foreach ($fileInfos as $i) {
118
-			$entry = \OCA\Files\Helper::formatFileInfo($i);
119
-			$entry['id'] = $id++;
120
-			$entry['etag'] = $entry['mtime']; // add fake etag, it is only needed to identify the preview image
121
-			$entry['permissions'] = \OCP\Constants::PERMISSION_READ;
122
-			$files[] = $entry;
123
-		}
124
-		return $files;
125
-	}
109
+    /**
110
+     * Format file infos for JSON
111
+     *
112
+     * @param \OCP\Files\FileInfo[] $fileInfos file infos
113
+     */
114
+    public static function formatFileInfos($fileInfos) {
115
+        $files = array();
116
+        $id = 0;
117
+        foreach ($fileInfos as $i) {
118
+            $entry = \OCA\Files\Helper::formatFileInfo($i);
119
+            $entry['id'] = $id++;
120
+            $entry['etag'] = $entry['mtime']; // add fake etag, it is only needed to identify the preview image
121
+            $entry['permissions'] = \OCP\Constants::PERMISSION_READ;
122
+            $files[] = $entry;
123
+        }
124
+        return $files;
125
+    }
126 126
 }
Please login to merge, or discard this patch.
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -44,7 +44,7 @@  discard block
 block discarded – undo
44 44
 		$result = array();
45 45
 		$timestamp = null;
46 46
 
47
-		$view = new \OC\Files\View('/' . $user . '/files_trashbin/files');
47
+		$view = new \OC\Files\View('/'.$user.'/files_trashbin/files');
48 48
 
49 49
 		if (ltrim($dir, '/') !== '' && !$view->is_dir($dir)) {
50 50
 			throw new \Exception('Directory does not exists');
@@ -72,7 +72,7 @@  discard block
 block discarded – undo
72 72
 				$timestamp = substr(pathinfo($parts[0], PATHINFO_EXTENSION), 1);
73 73
 			}
74 74
 			$originalPath = '';
75
-			$originalName = substr($entryName, 0, -strlen($timestamp)-2);
75
+			$originalName = substr($entryName, 0, -strlen($timestamp) - 2);
76 76
 			if (isset($originalLocations[$originalName][$timestamp])) {
77 77
 				$originalPath = $originalLocations[$originalName][$timestamp];
78 78
 				if (substr($originalPath, -1) === '/') {
@@ -92,12 +92,12 @@  discard block
 block discarded – undo
92 92
 			);
93 93
 			if ($originalPath) {
94 94
 				if ($originalPath !== '.') {
95
-					$i['extraData'] = $originalPath . '/' . $originalName;
95
+					$i['extraData'] = $originalPath.'/'.$originalName;
96 96
 				} else {
97 97
 					$i['extraData'] = $originalName;
98 98
 				}
99 99
 			}
100
-			$result[] = new FileInfo($absoluteDir . '/' . $i['name'], $storage, $internalPath . '/' . $i['name'], $i, $mount);
100
+			$result[] = new FileInfo($absoluteDir.'/'.$i['name'], $storage, $internalPath.'/'.$i['name'], $i, $mount);
101 101
 		}
102 102
 
103 103
 		if ($sortAttribute !== '') {
Please login to merge, or discard this patch.