Passed
Push — master ( 7fcb75...dada6e )
by Morris
36:19 queued 25:19
created
apps/dav/lib/Upload/AssemblyStream.php 2 patches
Indentation   +260 added lines, -260 removed lines patch added patch discarded remove patch
@@ -41,264 +41,264 @@
 block discarded – undo
41 41
  */
42 42
 class AssemblyStream implements \Icewind\Streams\File {
43 43
 
44
-	/** @var resource */
45
-	private $context;
46
-
47
-	/** @var IFile[] */
48
-	private $nodes;
49
-
50
-	/** @var int */
51
-	private $pos = 0;
52
-
53
-	/** @var int */
54
-	private $size = 0;
55
-
56
-	/** @var resource */
57
-	private $currentStream = null;
58
-
59
-	/** @var int */
60
-	private $currentNode = 0;
61
-
62
-	/** @var int */
63
-	private $currentNodeRead = 0;
64
-
65
-	/**
66
-	 * @param string $path
67
-	 * @param string $mode
68
-	 * @param int $options
69
-	 * @param string &$opened_path
70
-	 * @return bool
71
-	 */
72
-	public function stream_open($path, $mode, $options, &$opened_path) {
73
-		$this->loadContext('assembly');
74
-
75
-		$nodes = $this->nodes;
76
-		// https://stackoverflow.com/a/10985500
77
-		@usort($nodes, function (IFile $a, IFile $b) {
78
-			return strnatcmp($a->getName(), $b->getName());
79
-		});
80
-		$this->nodes = array_values($nodes);
81
-		$this->size = array_reduce($this->nodes, function ($size, IFile $file) {
82
-			return $size + $file->getSize();
83
-		}, 0);
84
-		return true;
85
-	}
86
-
87
-	/**
88
-	 * @param int $offset
89
-	 * @param int $whence
90
-	 * @return bool
91
-	 */
92
-	public function stream_seek($offset, $whence = SEEK_SET) {
93
-		if ($whence === SEEK_CUR) {
94
-			$offset = $this->stream_tell() + $offset;
95
-		} elseif ($whence === SEEK_END) {
96
-			$offset = $this->size + $offset;
97
-		}
98
-
99
-		if ($offset > $this->size) {
100
-			return false;
101
-		}
102
-
103
-		$nodeIndex = 0;
104
-		$nodeStart = 0;
105
-		while (true) {
106
-			if (!isset($this->nodes[$nodeIndex + 1])) {
107
-				break;
108
-			}
109
-			$node = $this->nodes[$nodeIndex];
110
-			if ($nodeStart + $node->getSize() > $offset) {
111
-				break;
112
-			}
113
-			$nodeIndex++;
114
-			$nodeStart += $node->getSize();
115
-		}
116
-
117
-		$stream = $this->getStream($this->nodes[$nodeIndex]);
118
-		$nodeOffset = $offset - $nodeStart;
119
-		if (fseek($stream, $nodeOffset) === -1) {
120
-			return false;
121
-		}
122
-		$this->currentNode = $nodeIndex;
123
-		$this->currentNodeRead = $nodeOffset;
124
-		$this->currentStream = $stream;
125
-		$this->pos = $offset;
126
-
127
-		return true;
128
-	}
129
-
130
-	/**
131
-	 * @return int
132
-	 */
133
-	public function stream_tell() {
134
-		return $this->pos;
135
-	}
136
-
137
-	/**
138
-	 * @param int $count
139
-	 * @return string
140
-	 */
141
-	public function stream_read($count) {
142
-		if (is_null($this->currentStream)) {
143
-			if ($this->currentNode < count($this->nodes)) {
144
-				$this->currentStream = $this->getStream($this->nodes[$this->currentNode]);
145
-			} else {
146
-				return '';
147
-			}
148
-		}
149
-
150
-		do {
151
-			$data = fread($this->currentStream, $count);
152
-			$read = strlen($data);
153
-			$this->currentNodeRead += $read;
154
-
155
-			if (feof($this->currentStream)) {
156
-				fclose($this->currentStream);
157
-				$currentNodeSize = $this->nodes[$this->currentNode]->getSize();
158
-				if ($this->currentNodeRead < $currentNodeSize) {
159
-					throw new \Exception('Stream from assembly node shorter than expected, got ' . $this->currentNodeRead . ' bytes, expected ' . $currentNodeSize);
160
-				}
161
-				$this->currentNode++;
162
-				$this->currentNodeRead = 0;
163
-				if ($this->currentNode < count($this->nodes)) {
164
-					$this->currentStream = $this->getStream($this->nodes[$this->currentNode]);
165
-				} else {
166
-					$this->currentStream = null;
167
-				}
168
-			}
169
-			// if no data read, try again with the next node because
170
-			// returning empty data can make the caller think there is no more
171
-			// data left to read
172
-		} while ($read === 0 && !is_null($this->currentStream));
173
-
174
-		// update position
175
-		$this->pos += $read;
176
-		return $data;
177
-	}
178
-
179
-	/**
180
-	 * @param string $data
181
-	 * @return int
182
-	 */
183
-	public function stream_write($data) {
184
-		return false;
185
-	}
186
-
187
-	/**
188
-	 * @param int $option
189
-	 * @param int $arg1
190
-	 * @param int $arg2
191
-	 * @return bool
192
-	 */
193
-	public function stream_set_option($option, $arg1, $arg2) {
194
-		return false;
195
-	}
196
-
197
-	/**
198
-	 * @param int $size
199
-	 * @return bool
200
-	 */
201
-	public function stream_truncate($size) {
202
-		return false;
203
-	}
204
-
205
-	/**
206
-	 * @return array
207
-	 */
208
-	public function stream_stat() {
209
-		return [
210
-			'size' => $this->size,
211
-		];
212
-	}
213
-
214
-	/**
215
-	 * @param int $operation
216
-	 * @return bool
217
-	 */
218
-	public function stream_lock($operation) {
219
-		return false;
220
-	}
221
-
222
-	/**
223
-	 * @return bool
224
-	 */
225
-	public function stream_flush() {
226
-		return false;
227
-	}
228
-
229
-	/**
230
-	 * @return bool
231
-	 */
232
-	public function stream_eof() {
233
-		return $this->pos >= $this->size || ($this->currentNode >= count($this->nodes) && $this->currentNode === null);
234
-	}
235
-
236
-	/**
237
-	 * @return bool
238
-	 */
239
-	public function stream_close() {
240
-		return true;
241
-	}
242
-
243
-
244
-	/**
245
-	 * Load the source from the stream context and return the context options
246
-	 *
247
-	 * @param string $name
248
-	 * @return array
249
-	 * @throws \BadMethodCallException
250
-	 */
251
-	protected function loadContext($name) {
252
-		$context = stream_context_get_options($this->context);
253
-		if (isset($context[$name])) {
254
-			$context = $context[$name];
255
-		} else {
256
-			throw new \BadMethodCallException('Invalid context, "' . $name . '" options not set');
257
-		}
258
-		if (isset($context['nodes']) and is_array($context['nodes'])) {
259
-			$this->nodes = $context['nodes'];
260
-		} else {
261
-			throw new \BadMethodCallException('Invalid context, nodes not set');
262
-		}
263
-		return $context;
264
-	}
265
-
266
-	/**
267
-	 * @param IFile[] $nodes
268
-	 * @return resource
269
-	 *
270
-	 * @throws \BadMethodCallException
271
-	 */
272
-	public static function wrap(array $nodes) {
273
-		$context = stream_context_create([
274
-			'assembly' => [
275
-				'nodes' => $nodes
276
-			]
277
-		]);
278
-		stream_wrapper_register('assembly', self::class);
279
-		try {
280
-			$wrapped = fopen('assembly://', 'r', null, $context);
281
-		} catch (\BadMethodCallException $e) {
282
-			stream_wrapper_unregister('assembly');
283
-			throw $e;
284
-		}
285
-		stream_wrapper_unregister('assembly');
286
-		return $wrapped;
287
-	}
288
-
289
-	/**
290
-	 * @param IFile $node
291
-	 * @return resource
292
-	 */
293
-	private function getStream(IFile $node) {
294
-		$data = $node->get();
295
-		if (is_resource($data)) {
296
-			return $data;
297
-		} else {
298
-			$tmp = fopen('php://temp', 'w+');
299
-			fwrite($tmp, $data);
300
-			rewind($tmp);
301
-			return $tmp;
302
-		}
303
-	}
44
+    /** @var resource */
45
+    private $context;
46
+
47
+    /** @var IFile[] */
48
+    private $nodes;
49
+
50
+    /** @var int */
51
+    private $pos = 0;
52
+
53
+    /** @var int */
54
+    private $size = 0;
55
+
56
+    /** @var resource */
57
+    private $currentStream = null;
58
+
59
+    /** @var int */
60
+    private $currentNode = 0;
61
+
62
+    /** @var int */
63
+    private $currentNodeRead = 0;
64
+
65
+    /**
66
+     * @param string $path
67
+     * @param string $mode
68
+     * @param int $options
69
+     * @param string &$opened_path
70
+     * @return bool
71
+     */
72
+    public function stream_open($path, $mode, $options, &$opened_path) {
73
+        $this->loadContext('assembly');
74
+
75
+        $nodes = $this->nodes;
76
+        // https://stackoverflow.com/a/10985500
77
+        @usort($nodes, function (IFile $a, IFile $b) {
78
+            return strnatcmp($a->getName(), $b->getName());
79
+        });
80
+        $this->nodes = array_values($nodes);
81
+        $this->size = array_reduce($this->nodes, function ($size, IFile $file) {
82
+            return $size + $file->getSize();
83
+        }, 0);
84
+        return true;
85
+    }
86
+
87
+    /**
88
+     * @param int $offset
89
+     * @param int $whence
90
+     * @return bool
91
+     */
92
+    public function stream_seek($offset, $whence = SEEK_SET) {
93
+        if ($whence === SEEK_CUR) {
94
+            $offset = $this->stream_tell() + $offset;
95
+        } elseif ($whence === SEEK_END) {
96
+            $offset = $this->size + $offset;
97
+        }
98
+
99
+        if ($offset > $this->size) {
100
+            return false;
101
+        }
102
+
103
+        $nodeIndex = 0;
104
+        $nodeStart = 0;
105
+        while (true) {
106
+            if (!isset($this->nodes[$nodeIndex + 1])) {
107
+                break;
108
+            }
109
+            $node = $this->nodes[$nodeIndex];
110
+            if ($nodeStart + $node->getSize() > $offset) {
111
+                break;
112
+            }
113
+            $nodeIndex++;
114
+            $nodeStart += $node->getSize();
115
+        }
116
+
117
+        $stream = $this->getStream($this->nodes[$nodeIndex]);
118
+        $nodeOffset = $offset - $nodeStart;
119
+        if (fseek($stream, $nodeOffset) === -1) {
120
+            return false;
121
+        }
122
+        $this->currentNode = $nodeIndex;
123
+        $this->currentNodeRead = $nodeOffset;
124
+        $this->currentStream = $stream;
125
+        $this->pos = $offset;
126
+
127
+        return true;
128
+    }
129
+
130
+    /**
131
+     * @return int
132
+     */
133
+    public function stream_tell() {
134
+        return $this->pos;
135
+    }
136
+
137
+    /**
138
+     * @param int $count
139
+     * @return string
140
+     */
141
+    public function stream_read($count) {
142
+        if (is_null($this->currentStream)) {
143
+            if ($this->currentNode < count($this->nodes)) {
144
+                $this->currentStream = $this->getStream($this->nodes[$this->currentNode]);
145
+            } else {
146
+                return '';
147
+            }
148
+        }
149
+
150
+        do {
151
+            $data = fread($this->currentStream, $count);
152
+            $read = strlen($data);
153
+            $this->currentNodeRead += $read;
154
+
155
+            if (feof($this->currentStream)) {
156
+                fclose($this->currentStream);
157
+                $currentNodeSize = $this->nodes[$this->currentNode]->getSize();
158
+                if ($this->currentNodeRead < $currentNodeSize) {
159
+                    throw new \Exception('Stream from assembly node shorter than expected, got ' . $this->currentNodeRead . ' bytes, expected ' . $currentNodeSize);
160
+                }
161
+                $this->currentNode++;
162
+                $this->currentNodeRead = 0;
163
+                if ($this->currentNode < count($this->nodes)) {
164
+                    $this->currentStream = $this->getStream($this->nodes[$this->currentNode]);
165
+                } else {
166
+                    $this->currentStream = null;
167
+                }
168
+            }
169
+            // if no data read, try again with the next node because
170
+            // returning empty data can make the caller think there is no more
171
+            // data left to read
172
+        } while ($read === 0 && !is_null($this->currentStream));
173
+
174
+        // update position
175
+        $this->pos += $read;
176
+        return $data;
177
+    }
178
+
179
+    /**
180
+     * @param string $data
181
+     * @return int
182
+     */
183
+    public function stream_write($data) {
184
+        return false;
185
+    }
186
+
187
+    /**
188
+     * @param int $option
189
+     * @param int $arg1
190
+     * @param int $arg2
191
+     * @return bool
192
+     */
193
+    public function stream_set_option($option, $arg1, $arg2) {
194
+        return false;
195
+    }
196
+
197
+    /**
198
+     * @param int $size
199
+     * @return bool
200
+     */
201
+    public function stream_truncate($size) {
202
+        return false;
203
+    }
204
+
205
+    /**
206
+     * @return array
207
+     */
208
+    public function stream_stat() {
209
+        return [
210
+            'size' => $this->size,
211
+        ];
212
+    }
213
+
214
+    /**
215
+     * @param int $operation
216
+     * @return bool
217
+     */
218
+    public function stream_lock($operation) {
219
+        return false;
220
+    }
221
+
222
+    /**
223
+     * @return bool
224
+     */
225
+    public function stream_flush() {
226
+        return false;
227
+    }
228
+
229
+    /**
230
+     * @return bool
231
+     */
232
+    public function stream_eof() {
233
+        return $this->pos >= $this->size || ($this->currentNode >= count($this->nodes) && $this->currentNode === null);
234
+    }
235
+
236
+    /**
237
+     * @return bool
238
+     */
239
+    public function stream_close() {
240
+        return true;
241
+    }
242
+
243
+
244
+    /**
245
+     * Load the source from the stream context and return the context options
246
+     *
247
+     * @param string $name
248
+     * @return array
249
+     * @throws \BadMethodCallException
250
+     */
251
+    protected function loadContext($name) {
252
+        $context = stream_context_get_options($this->context);
253
+        if (isset($context[$name])) {
254
+            $context = $context[$name];
255
+        } else {
256
+            throw new \BadMethodCallException('Invalid context, "' . $name . '" options not set');
257
+        }
258
+        if (isset($context['nodes']) and is_array($context['nodes'])) {
259
+            $this->nodes = $context['nodes'];
260
+        } else {
261
+            throw new \BadMethodCallException('Invalid context, nodes not set');
262
+        }
263
+        return $context;
264
+    }
265
+
266
+    /**
267
+     * @param IFile[] $nodes
268
+     * @return resource
269
+     *
270
+     * @throws \BadMethodCallException
271
+     */
272
+    public static function wrap(array $nodes) {
273
+        $context = stream_context_create([
274
+            'assembly' => [
275
+                'nodes' => $nodes
276
+            ]
277
+        ]);
278
+        stream_wrapper_register('assembly', self::class);
279
+        try {
280
+            $wrapped = fopen('assembly://', 'r', null, $context);
281
+        } catch (\BadMethodCallException $e) {
282
+            stream_wrapper_unregister('assembly');
283
+            throw $e;
284
+        }
285
+        stream_wrapper_unregister('assembly');
286
+        return $wrapped;
287
+    }
288
+
289
+    /**
290
+     * @param IFile $node
291
+     * @return resource
292
+     */
293
+    private function getStream(IFile $node) {
294
+        $data = $node->get();
295
+        if (is_resource($data)) {
296
+            return $data;
297
+        } else {
298
+            $tmp = fopen('php://temp', 'w+');
299
+            fwrite($tmp, $data);
300
+            rewind($tmp);
301
+            return $tmp;
302
+        }
303
+    }
304 304
 }
Please login to merge, or discard this patch.
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -74,11 +74,11 @@  discard block
 block discarded – undo
74 74
 
75 75
 		$nodes = $this->nodes;
76 76
 		// https://stackoverflow.com/a/10985500
77
-		@usort($nodes, function (IFile $a, IFile $b) {
77
+		@usort($nodes, function(IFile $a, IFile $b) {
78 78
 			return strnatcmp($a->getName(), $b->getName());
79 79
 		});
80 80
 		$this->nodes = array_values($nodes);
81
-		$this->size = array_reduce($this->nodes, function ($size, IFile $file) {
81
+		$this->size = array_reduce($this->nodes, function($size, IFile $file) {
82 82
 			return $size + $file->getSize();
83 83
 		}, 0);
84 84
 		return true;
@@ -156,7 +156,7 @@  discard block
 block discarded – undo
156 156
 				fclose($this->currentStream);
157 157
 				$currentNodeSize = $this->nodes[$this->currentNode]->getSize();
158 158
 				if ($this->currentNodeRead < $currentNodeSize) {
159
-					throw new \Exception('Stream from assembly node shorter than expected, got ' . $this->currentNodeRead . ' bytes, expected ' . $currentNodeSize);
159
+					throw new \Exception('Stream from assembly node shorter than expected, got '.$this->currentNodeRead.' bytes, expected '.$currentNodeSize);
160 160
 				}
161 161
 				$this->currentNode++;
162 162
 				$this->currentNodeRead = 0;
@@ -253,7 +253,7 @@  discard block
 block discarded – undo
253 253
 		if (isset($context[$name])) {
254 254
 			$context = $context[$name];
255 255
 		} else {
256
-			throw new \BadMethodCallException('Invalid context, "' . $name . '" options not set');
256
+			throw new \BadMethodCallException('Invalid context, "'.$name.'" options not set');
257 257
 		}
258 258
 		if (isset($context['nodes']) and is_array($context['nodes'])) {
259 259
 			$this->nodes = $context['nodes'];
Please login to merge, or discard this patch.
apps/workflowengine/lib/Check/RequestRemoteAddress.php 1 patch
Indentation   +142 added lines, -142 removed lines patch added patch discarded remove patch
@@ -27,146 +27,146 @@
 block discarded – undo
27 27
 
28 28
 class RequestRemoteAddress implements ICheck {
29 29
 
30
-	/** @var IL10N */
31
-	protected $l;
32
-
33
-	/** @var IRequest */
34
-	protected $request;
35
-
36
-	/**
37
-	 * @param IL10N $l
38
-	 * @param IRequest $request
39
-	 */
40
-	public function __construct(IL10N $l, IRequest $request) {
41
-		$this->l = $l;
42
-		$this->request = $request;
43
-	}
44
-
45
-	/**
46
-	 * @param string $operator
47
-	 * @param string $value
48
-	 * @return bool
49
-	 */
50
-	public function executeCheck($operator, $value) {
51
-		$actualValue = $this->request->getRemoteAddress();
52
-		$decodedValue = explode('/', $value);
53
-
54
-		if ($operator === 'matchesIPv4') {
55
-			return $this->matchIPv4($actualValue, $decodedValue[0], $decodedValue[1]);
56
-		} elseif ($operator === '!matchesIPv4') {
57
-			return !$this->matchIPv4($actualValue, $decodedValue[0], $decodedValue[1]);
58
-		} elseif ($operator === 'matchesIPv6') {
59
-			return $this->matchIPv6($actualValue, $decodedValue[0], $decodedValue[1]);
60
-		} else {
61
-			return !$this->matchIPv6($actualValue, $decodedValue[0], $decodedValue[1]);
62
-		}
63
-	}
64
-
65
-	/**
66
-	 * @param string $operator
67
-	 * @param string $value
68
-	 * @throws \UnexpectedValueException
69
-	 */
70
-	public function validateCheck($operator, $value) {
71
-		if (!in_array($operator, ['matchesIPv4', '!matchesIPv4', 'matchesIPv6', '!matchesIPv6'])) {
72
-			throw new \UnexpectedValueException($this->l->t('The given operator is invalid'), 1);
73
-		}
74
-
75
-		$decodedValue = explode('/', $value);
76
-		if (count($decodedValue) !== 2) {
77
-			throw new \UnexpectedValueException($this->l->t('The given IP range is invalid'), 2);
78
-		}
79
-
80
-		if (in_array($operator, ['matchesIPv4', '!matchesIPv4'])) {
81
-			if (!filter_var($decodedValue[0], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
82
-				throw new \UnexpectedValueException($this->l->t('The given IP range is not valid for IPv4'), 3);
83
-			}
84
-			if ($decodedValue[1] > 32 || $decodedValue[1] <= 0) {
85
-				throw new \UnexpectedValueException($this->l->t('The given IP range is not valid for IPv4'), 4);
86
-			}
87
-		} else {
88
-			if (!filter_var($decodedValue[0], FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
89
-				throw new \UnexpectedValueException($this->l->t('The given IP range is not valid for IPv6'), 3);
90
-			}
91
-			if ($decodedValue[1] > 128 || $decodedValue[1] <= 0) {
92
-				throw new \UnexpectedValueException($this->l->t('The given IP range is not valid for IPv6'), 4);
93
-			}
94
-		}
95
-	}
96
-
97
-	/**
98
-	 * Based on https://stackoverflow.com/a/594134
99
-	 * @param string $ip
100
-	 * @param string $rangeIp
101
-	 * @param int $bits
102
-	 * @return bool
103
-	 */
104
-	protected function matchIPv4($ip, $rangeIp, $bits) {
105
-		$rangeDecimal = ip2long($rangeIp);
106
-		$ipDecimal = ip2long($ip);
107
-		$mask = -1 << (32 - $bits);
108
-		return ($ipDecimal & $mask) === ($rangeDecimal & $mask);
109
-	}
110
-
111
-	/**
112
-	 * Based on https://stackoverflow.com/a/7951507
113
-	 * @param string $ip
114
-	 * @param string $rangeIp
115
-	 * @param int $bits
116
-	 * @return bool
117
-	 */
118
-	protected function matchIPv6($ip, $rangeIp, $bits) {
119
-		$ipNet = inet_pton($ip);
120
-		$binaryIp = $this->ipv6ToBits($ipNet);
121
-		$ipNetBits = substr($binaryIp, 0, $bits);
122
-
123
-		$rangeNet = inet_pton($rangeIp);
124
-		$binaryRange = $this->ipv6ToBits($rangeNet);
125
-		$rangeNetBits = substr($binaryRange, 0, $bits);
126
-
127
-		return $ipNetBits === $rangeNetBits;
128
-	}
129
-
130
-	/**
131
-	 * Based on https://stackoverflow.com/a/7951507
132
-	 * @param string $packedIp
133
-	 * @return string
134
-	 */
135
-	protected function ipv6ToBits($packedIp) {
136
-		$unpackedIp = unpack('A16', $packedIp);
137
-		$unpackedIp = str_split($unpackedIp[1]);
138
-		$binaryIp = '';
139
-		foreach ($unpackedIp as $char) {
140
-			$binaryIp .= str_pad(decbin(ord($char)), 8, '0', STR_PAD_LEFT);
141
-		}
142
-		return str_pad($binaryIp, 128, '0', STR_PAD_RIGHT);
143
-	}
144
-
145
-	/**
146
-	 * returns a list of Entities the checker supports. The values must match
147
-	 * the class name of the entity.
148
-	 *
149
-	 * An empty result means the check is universally available.
150
-	 *
151
-	 * @since 18.0.0
152
-	 */
153
-	public function supportedEntities(): array {
154
-		return [];
155
-	}
156
-
157
-	/**
158
-	 * returns whether the operation can be used in the requested scope.
159
-	 *
160
-	 * Scope IDs are defined as constants in OCP\WorkflowEngine\IManager. At
161
-	 * time of writing these are SCOPE_ADMIN and SCOPE_USER.
162
-	 *
163
-	 * For possibly unknown future scopes the recommended behaviour is: if
164
-	 * user scope is permitted, the default behaviour should return `true`,
165
-	 * otherwise `false`.
166
-	 *
167
-	 * @since 18.0.0
168
-	 */
169
-	public function isAvailableForScope(int $scope): bool {
170
-		return true;
171
-	}
30
+    /** @var IL10N */
31
+    protected $l;
32
+
33
+    /** @var IRequest */
34
+    protected $request;
35
+
36
+    /**
37
+     * @param IL10N $l
38
+     * @param IRequest $request
39
+     */
40
+    public function __construct(IL10N $l, IRequest $request) {
41
+        $this->l = $l;
42
+        $this->request = $request;
43
+    }
44
+
45
+    /**
46
+     * @param string $operator
47
+     * @param string $value
48
+     * @return bool
49
+     */
50
+    public function executeCheck($operator, $value) {
51
+        $actualValue = $this->request->getRemoteAddress();
52
+        $decodedValue = explode('/', $value);
53
+
54
+        if ($operator === 'matchesIPv4') {
55
+            return $this->matchIPv4($actualValue, $decodedValue[0], $decodedValue[1]);
56
+        } elseif ($operator === '!matchesIPv4') {
57
+            return !$this->matchIPv4($actualValue, $decodedValue[0], $decodedValue[1]);
58
+        } elseif ($operator === 'matchesIPv6') {
59
+            return $this->matchIPv6($actualValue, $decodedValue[0], $decodedValue[1]);
60
+        } else {
61
+            return !$this->matchIPv6($actualValue, $decodedValue[0], $decodedValue[1]);
62
+        }
63
+    }
64
+
65
+    /**
66
+     * @param string $operator
67
+     * @param string $value
68
+     * @throws \UnexpectedValueException
69
+     */
70
+    public function validateCheck($operator, $value) {
71
+        if (!in_array($operator, ['matchesIPv4', '!matchesIPv4', 'matchesIPv6', '!matchesIPv6'])) {
72
+            throw new \UnexpectedValueException($this->l->t('The given operator is invalid'), 1);
73
+        }
74
+
75
+        $decodedValue = explode('/', $value);
76
+        if (count($decodedValue) !== 2) {
77
+            throw new \UnexpectedValueException($this->l->t('The given IP range is invalid'), 2);
78
+        }
79
+
80
+        if (in_array($operator, ['matchesIPv4', '!matchesIPv4'])) {
81
+            if (!filter_var($decodedValue[0], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
82
+                throw new \UnexpectedValueException($this->l->t('The given IP range is not valid for IPv4'), 3);
83
+            }
84
+            if ($decodedValue[1] > 32 || $decodedValue[1] <= 0) {
85
+                throw new \UnexpectedValueException($this->l->t('The given IP range is not valid for IPv4'), 4);
86
+            }
87
+        } else {
88
+            if (!filter_var($decodedValue[0], FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
89
+                throw new \UnexpectedValueException($this->l->t('The given IP range is not valid for IPv6'), 3);
90
+            }
91
+            if ($decodedValue[1] > 128 || $decodedValue[1] <= 0) {
92
+                throw new \UnexpectedValueException($this->l->t('The given IP range is not valid for IPv6'), 4);
93
+            }
94
+        }
95
+    }
96
+
97
+    /**
98
+     * Based on https://stackoverflow.com/a/594134
99
+     * @param string $ip
100
+     * @param string $rangeIp
101
+     * @param int $bits
102
+     * @return bool
103
+     */
104
+    protected function matchIPv4($ip, $rangeIp, $bits) {
105
+        $rangeDecimal = ip2long($rangeIp);
106
+        $ipDecimal = ip2long($ip);
107
+        $mask = -1 << (32 - $bits);
108
+        return ($ipDecimal & $mask) === ($rangeDecimal & $mask);
109
+    }
110
+
111
+    /**
112
+     * Based on https://stackoverflow.com/a/7951507
113
+     * @param string $ip
114
+     * @param string $rangeIp
115
+     * @param int $bits
116
+     * @return bool
117
+     */
118
+    protected function matchIPv6($ip, $rangeIp, $bits) {
119
+        $ipNet = inet_pton($ip);
120
+        $binaryIp = $this->ipv6ToBits($ipNet);
121
+        $ipNetBits = substr($binaryIp, 0, $bits);
122
+
123
+        $rangeNet = inet_pton($rangeIp);
124
+        $binaryRange = $this->ipv6ToBits($rangeNet);
125
+        $rangeNetBits = substr($binaryRange, 0, $bits);
126
+
127
+        return $ipNetBits === $rangeNetBits;
128
+    }
129
+
130
+    /**
131
+     * Based on https://stackoverflow.com/a/7951507
132
+     * @param string $packedIp
133
+     * @return string
134
+     */
135
+    protected function ipv6ToBits($packedIp) {
136
+        $unpackedIp = unpack('A16', $packedIp);
137
+        $unpackedIp = str_split($unpackedIp[1]);
138
+        $binaryIp = '';
139
+        foreach ($unpackedIp as $char) {
140
+            $binaryIp .= str_pad(decbin(ord($char)), 8, '0', STR_PAD_LEFT);
141
+        }
142
+        return str_pad($binaryIp, 128, '0', STR_PAD_RIGHT);
143
+    }
144
+
145
+    /**
146
+     * returns a list of Entities the checker supports. The values must match
147
+     * the class name of the entity.
148
+     *
149
+     * An empty result means the check is universally available.
150
+     *
151
+     * @since 18.0.0
152
+     */
153
+    public function supportedEntities(): array {
154
+        return [];
155
+    }
156
+
157
+    /**
158
+     * returns whether the operation can be used in the requested scope.
159
+     *
160
+     * Scope IDs are defined as constants in OCP\WorkflowEngine\IManager. At
161
+     * time of writing these are SCOPE_ADMIN and SCOPE_USER.
162
+     *
163
+     * For possibly unknown future scopes the recommended behaviour is: if
164
+     * user scope is permitted, the default behaviour should return `true`,
165
+     * otherwise `false`.
166
+     *
167
+     * @since 18.0.0
168
+     */
169
+    public function isAvailableForScope(int $scope): bool {
170
+        return true;
171
+    }
172 172
 }
Please login to merge, or discard this patch.