Proyectos de Subversion Moodle

Rev

Rev 1 | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
 
3
namespace Aws\EndpointV2\Ruleset;
4
 
5
use Aws\Exception\UnresolvedEndpointException;
6
 
7
/**
8
 * Provides functions and actions to be performed for endpoint evaluation.
9
 * This is an internal only class and is not subject to backwards-compatibility guarantees.
10
 *
11
 * @internal
12
 */
13
class RulesetStandardLibrary
14
{
15
    const IPV4_RE = '/^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/';
16
    const IPV6_RE = '/([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|
17
                    . ([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]
18
                    . {1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:)
19
                    . {1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|
20
                    . [0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:
21
                    . (:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|
22
                    . 1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]
23
                    . {1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]
24
                    . |1{0,1}[0-9]){0,1}[0-9])/';
25
    const TEMPLATE_ESCAPE_RE = '/{\{\s*(.*?)\s*\}\}/';
26
    const TEMPLATE_SEARCH_RE = '/\{[a-zA-Z#]+\}/';
27
    const TEMPLATE_PARSE_RE = '#\{((?>[^\{\}]+)|(?R))*\}#x';
28
    const HOST_LABEL_RE = '/^(?!-)[a-zA-Z\d-]{1,63}(?<!-)$/';
29
 
30
    private $partitions;
31
 
32
    public function __construct($partitions)
33
    {
34
        $this->partitions = $partitions;
35
    }
36
 
37
    /**
38
     * Determines if a value is set.
39
     *
40
     * @return boolean
41
     */
42
    public function is_set($value)
43
    {
44
        return isset($value);
45
    }
46
 
47
    /**
48
     * Function implementation of logical operator `not`
49
     *
50
     * @return boolean
51
     */
52
    public function not($value)
53
    {
54
        return !$value;
55
    }
56
 
57
    /**
58
     * Find an attribute within a value given a path string.
59
     *
60
     * @return mixed
61
     */
62
    public function getAttr($from, $path)
63
    {
1441 ariadna 64
        // Handles the case where "[<int|string]" is provided as the top-level path
65
        if (preg_match('/^\[(\w+)\]$/', $path, $matches)) {
66
            $index = is_numeric($matches[1]) ? (int) $matches[1] : $matches[1];
67
 
68
            return $from[$index] ?? null;
69
        }
70
 
1 efrain 71
        $parts = explode('.', $path);
72
        foreach ($parts as $part) {
73
            $sliceIdx = strpos($part, '[');
74
            if ($sliceIdx !== false) {
75
                if (substr($part, -1) !== ']') {
76
                    return null;
77
                }
1441 ariadna 78
                $slice = (int) substr($part, $sliceIdx + 1, strlen($part) - 1);
79
                $fromIndex = substr($part, 0, $sliceIdx);
80
                $from = $from[$fromIndex][$slice] ?? null;
1 efrain 81
            } else {
82
                $from = $from[$part];
83
            }
84
        }
85
        return $from;
86
    }
87
 
88
    /**
89
     * Computes a substring given the start index and end index. If `reverse` is
90
     * true, slice the string from the end instead.
91
     *
92
     * @return mixed
93
     */
94
    public function substring($input, $start, $stop, $reverse)
95
    {
96
        if (!is_string($input)) {
97
            throw new UnresolvedEndpointException(
98
                'Input passed to `substring` must be `string`.'
99
            );
100
        }
101
 
102
        if (preg_match('/[^\x00-\x7F]/', $input)) {
103
            return null;
104
        }
105
        if ($start >= $stop or strlen($input) < $stop) {
106
            return null;
107
        }
108
        if (!$reverse) {
109
            return substr($input, $start, $stop - $start);
110
        } else {
111
            $offset = strlen($input) - $stop;
112
            $length = $stop - $start;
113
            return substr($input, $offset, $length);
114
        }
115
    }
116
 
117
    /**
118
     * Evaluates two strings for equality.
119
     *
120
     * @return boolean
121
     */
122
    public function stringEquals($string1, $string2)
123
    {
124
        if (!is_string($string1) || !is_string($string2)) {
125
            throw new UnresolvedEndpointException(
126
                'Values passed to StringEquals must be `string`.'
127
            );
128
        }
129
        return $string1 === $string2;
130
    }
131
 
132
    /**
133
     * Evaluates two booleans for equality.
134
     *
135
     * @return boolean
136
     */
137
    public function booleanEquals($boolean1, $boolean2)
138
    {
139
        return
140
            filter_var($boolean1, FILTER_VALIDATE_BOOLEAN)
141
            === filter_var($boolean2, FILTER_VALIDATE_BOOLEAN);
142
    }
143
 
144
    /**
145
     * Percent-encodes an input string.
146
     *
147
     * @return mixed
148
     */
149
    public function uriEncode($input)
150
    {
151
        if (is_null($input)) {
152
            return null;
153
        }
154
        return str_replace('%7E', '~', rawurlencode($input));
155
    }
156
 
157
    /**
158
     * Parses URL string into components.
159
     *
160
     * @return mixed
161
     */
162
    public function parseUrl($url)
163
    {
1441 ariadna 164
        if (is_null($url)) {
165
            return null;
166
        }
167
 
1 efrain 168
        $parsed = parse_url($url);
169
 
170
        if ($parsed === false || !empty($parsed['query'])) {
171
            return null;
172
        } elseif (!isset($parsed['scheme'])) {
173
            return null;
174
        }
175
 
176
        if ($parsed['scheme'] !== 'http'
177
            && $parsed['scheme'] !== 'https'
178
        ) {
179
            return null;
180
        }
181
 
182
        $urlInfo = [];
183
        $urlInfo['scheme'] = $parsed['scheme'];
184
        $urlInfo['authority'] = isset($parsed['host']) ? $parsed['host'] : '';
185
        if (isset($parsed['port'])) {
186
            $urlInfo['authority'] = $urlInfo['authority'] . ":" . $parsed['port'];
187
        }
188
        $urlInfo['path'] = isset($parsed['path']) ? $parsed['path'] : '';
189
        $urlInfo['normalizedPath'] = !empty($parsed['path'])
190
            ? rtrim($urlInfo['path'] ?: '', '/' .  "/") . '/'
191
            : '/';
192
        $urlInfo['isIp'] = !isset($parsed['host']) ?
193
            'false' : $this->isValidIp($parsed['host']);
194
 
195
        return $urlInfo;
196
    }
197
 
198
    /**
199
     * Evaluates whether a value is a valid host label per
200
     * RFC 1123. If allow_subdomains is true, split on `.` and validate
201
     * each subdomain separately.
202
     *
203
     * @return boolean
204
     */
205
    public function isValidHostLabel($hostLabel, $allowSubDomains)
206
    {
207
        if (!isset($hostLabel)
208
            || (!$allowSubDomains && strpos($hostLabel, '.') != false)
209
        ) {
210
            return false;
211
        }
212
 
213
        if ($allowSubDomains) {
214
            foreach (explode('.', $hostLabel) as $subdomain) {
215
                if (!$this->validateHostLabel($subdomain)) {
216
                    return false;
217
                }
218
            }
219
            return true;
220
        } else {
221
            return $this->validateHostLabel($hostLabel);
222
        }
223
    }
224
 
225
    /**
226
     * Parse and validate string for ARN components.
227
     *
228
     * @return array|null
229
     */
230
    public function parseArn($arnString)
231
    {
232
        if (is_null($arnString)
233
            || substr( $arnString, 0, 3 ) !== "arn"
234
        ) {
235
            return null;
236
        }
237
 
238
        $arn = [];
239
        $parts = explode(':', $arnString, 6);
240
        if (sizeof($parts) < 6) {
241
            return null;
242
        }
243
 
244
        $arn['partition'] = isset($parts[1]) ? $parts[1] : null;
245
        $arn['service'] = isset($parts[2]) ? $parts[2] : null;
246
        $arn['region'] = isset($parts[3]) ? $parts[3] : null;
247
        $arn['accountId'] = isset($parts[4]) ? $parts[4] : null;
248
        $arn['resourceId'] = isset($parts[5]) ? $parts[5] : null;
249
 
250
        if (empty($arn['partition'])
251
            || empty($arn['service'])
252
            || empty($arn['resourceId'])
253
        ) {
254
            return null;
255
        }
256
        $resource = $arn['resourceId'];
257
        $arn['resourceId'] = preg_split("/[:\/]/", $resource);
258
 
259
        return $arn;
260
    }
261
 
262
    /**
263
     * Matches a region string to an AWS partition.
264
     *
265
     * @return mixed
266
     */
267
    public function partition($region)
268
    {
269
        if (!is_string($region)) {
270
            throw new UnresolvedEndpointException(
271
                'Value passed to `partition` must be `string`.'
272
            );
273
        }
274
 
275
        $partitions = $this->partitions;
276
        foreach ($partitions['partitions'] as $partition) {
277
            if (array_key_exists($region, $partition['regions'])
278
                || preg_match("/{$partition['regionRegex']}/", $region)
279
            ) {
280
                return $partition['outputs'];
281
            }
282
        }
283
        //return `aws` partition if no match is found.
284
        return $partitions['partitions'][0]['outputs'];
285
    }
286
 
287
    /**
288
     * Evaluates whether a value is a valid bucket name for virtual host
289
     * style bucket URLs.
290
     *
291
     * @return boolean
292
     */
293
    public function isVirtualHostableS3Bucket($bucketName, $allowSubdomains)
294
    {
295
        if ((is_null($bucketName)
296
            || (strlen($bucketName) < 3 || strlen($bucketName) > 63))
297
            || preg_match(self::IPV4_RE, $bucketName)
298
            || strtolower($bucketName) !== $bucketName
299
        ) {
300
            return false;
301
        }
302
 
303
        if ($allowSubdomains) {
304
            $labels = explode('.', $bucketName);
305
            $results = [];
306
            forEach($labels as $label) {
307
                $results[] = $this->isVirtualHostableS3Bucket($label, false);
308
            }
309
            return !in_array(false, $results);
310
        }
311
        return $this->isValidHostLabel($bucketName, false);
312
    }
313
 
314
    public function callFunction($funcCondition, &$inputParameters)
315
    {
316
        $funcArgs = [];
317
 
318
        forEach($funcCondition['argv'] as $arg) {
319
            $funcArgs[] = $this->resolveValue($arg, $inputParameters);
320
        }
321
 
322
        $funcName = str_replace('aws.', '', $funcCondition['fn']);
323
        if ($funcName === 'isSet') {
324
            $funcName = 'is_set';
325
        }
326
 
327
        $result = call_user_func_array(
328
            [RulesetStandardLibrary::class, $funcName],
329
            $funcArgs
330
        );
331
 
332
        if (isset($funcCondition['assign'])) {
333
            $assign = $funcCondition['assign'];
334
            if (isset($inputParameters[$assign])){
335
                throw new UnresolvedEndpointException(
336
                    "Assignment `{$assign}` already exists in input parameters" .
337
                    " or has already been assigned by an endpoint rule and cannot be overwritten."
338
                );
339
            }
340
            $inputParameters[$assign] = $result;
341
        }
342
        return $result;
343
    }
344
 
345
    public function resolveValue($value, $inputParameters)
346
    {
347
        //Given a value, check if it's a function, reference or template.
348
        //returns resolved value
349
        if ($this->isFunc($value)) {
350
            return $this->callFunction($value, $inputParameters);
351
        } elseif ($this->isRef($value)) {
352
            return isset($inputParameters[$value['ref']]) ? $inputParameters[$value['ref']] : null;
353
        } elseif ($this->isTemplate($value)) {
354
            return $this->resolveTemplateString($value, $inputParameters);
355
        }
356
        return $value;
357
    }
358
 
359
    public function isFunc($arg)
360
    {
361
        return is_array($arg) && isset($arg['fn']);
362
    }
363
 
364
    public function isRef($arg)
365
    {
366
        return is_array($arg) && isset($arg['ref']);
367
    }
368
 
369
    public function isTemplate($arg)
370
    {
371
        return is_string($arg) && !empty(preg_match(self::TEMPLATE_SEARCH_RE, $arg));
372
    }
373
 
374
    public function resolveTemplateString($value, $inputParameters)
375
    {
376
        return preg_replace_callback(
377
            self::TEMPLATE_PARSE_RE,
378
            function ($match) use ($inputParameters) {
379
                if (preg_match(self::TEMPLATE_ESCAPE_RE, $match[0])) {
380
                    return $match[1];
381
                }
382
 
383
                $notFoundMessage = 'Resolved value was null.  Please check rules and ' .
384
                    'input parameters and try again.';
385
 
386
                $parts = explode("#", $match[1]);
387
                if (count($parts) > 1) {
388
                    $resolvedValue = $inputParameters;
389
                    foreach($parts as $part) {
390
                        if (!isset($resolvedValue[$part])) {
391
                            throw new UnresolvedEndpointException($notFoundMessage);
392
                        }
393
                        $resolvedValue = $resolvedValue[$part];
394
                    }
395
                    return $resolvedValue;
396
                } else {
397
                    if (!isset($inputParameters[$parts[0]])) {
398
                        throw new UnresolvedEndpointException($notFoundMessage);
399
                    }
400
                    return $inputParameters[$parts[0]];
401
                }
402
            },
403
            $value
404
        );
405
    }
406
 
407
    private function validateHostLabel ($hostLabel)
408
    {
409
        if (empty($hostLabel) || strlen($hostLabel) > 63) {
410
            return false;
411
        }
412
        if (preg_match(self::HOST_LABEL_RE, $hostLabel)) {
413
            return true;
414
        }
415
        return false;
416
    }
417
 
418
    private function isValidIp($hostName)
419
    {
420
        $isWrapped = strpos($hostName, '[') === 0
421
            && strrpos($hostName, ']') === strlen($hostName) - 1;
422
 
423
        return preg_match(
424
                self::IPV4_RE,
425
            $hostName
426
        )
427
        //IPV6 enclosed in brackets
428
        || ($isWrapped && preg_match(
429
            self::IPV6_RE,
430
            $hostName
431
        ))
432
            ? 'true' : 'false';
433
    }
434
}