Verzeichnisstruktur phpBB-3.2.0


Veröffentlicht
06.01.2017

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

BuiltInFilters.js

Zuletzt modifiziert: 09.10.2024, 12:57 - Dateigröße: 11.47 KiB


001  /**
002  * @param  {!string} str
003  * @return {!string}
004  */
005  function rawurlencode(str)
006  {
007      return encodeURIComponent(str).replace(
008          /[!'()*]/g,
009          /**
010          * @param {!string} c
011          */
012          function(c)
013          {
014              return '%' + c.charCodeAt(0).toString(16).toUpperCase();
015          }
016      );
017  }
018   
019  /**
020  * IMPORTANT NOTE: those filters are only meant to catch bad input and honest mistakes. They don't
021  *                 match their PHP equivalent exactly and may let unwanted values through. Their
022  *                 result should always be checked by PHP filters
023  *
024  * @const
025  */
026  var BuiltInFilters =
027  {
028      /**
029      * @param  {*} attrValue
030      * @return {*}
031      */
032      filterAlnum: function(attrValue)
033      {
034          return /^[0-9A-Za-z]+$/.test(attrValue) ? attrValue : false;
035      },
036   
037      /**
038      * @param  {*} attrValue
039      * @return {*}
040      */
041      filterColor: function(attrValue)
042      {
043          return /^(?:#[0-9a-f]{3,6}|rgb\(\d{1,3}, *\d{1,3}, *\d{1,3}\)|[a-z]+)$/i.test(attrValue) ? attrValue : false;
044      },
045   
046      /**
047      * @param  {*} attrValue
048      * @return {*}
049      */
050      filterEmail: function(attrValue)
051      {
052          return /^[-\w.+]+@[-\w.]+$/.test(attrValue) ? attrValue : false;
053      },
054   
055      /**
056      * @param  {*} attrValue
057      * @return {!boolean}
058      */
059      filterFalse: function(attrValue)
060      {
061          return false;
062      },
063   
064      /**
065      * @param  {*} attrValue
066      * @return {*}
067      */
068      filterFloat: function(attrValue)
069      {
070          return /^(?:0|-?[1-9]\d*)(?:\.\d+)?(?:e[1-9]\d*)?$/i.test(attrValue) ? attrValue : false;
071      },
072   
073      /**
074      * @param  {*}        attrValue Original value
075      * @param  {!Object}  map       Hash map
076      * @param  {!boolean} strict    Whether this map is strict (values with no match are invalid)
077      * @return {*}                  Filtered value, or FALSE if invalid
078      */
079      filterHashmap: function(attrValue, map, strict)
080      {
081          if (attrValue in map)
082          {
083              return map[attrValue];
084          }
085   
086          return (strict) ? false : attrValue;
087      },
088   
089      /**
090      * @param  {*} attrValue
091      * @return {*}
092      */
093      filterIdentifier: function(attrValue)
094      {
095          return /^[-\w]+$/.test(attrValue) ? attrValue : false;
096      },
097   
098      /**
099      * @param  {*} attrValue
100      * @return {*}
101      */
102      filterInt: function(attrValue)
103      {
104          return /^(?:0|-?[1-9]\d*)$/.test(attrValue) ? attrValue : false;
105      },
106   
107      /**
108      * @param  {*} attrValue
109      * @return {*}
110      */
111      filterIp: function(attrValue)
112      {
113          if (/^[\d.]+$/.test(attrValue))
114          {
115              return BuiltInFilters.filterIpv4(attrValue);
116          }
117   
118          if (/^[\da-f:]+$/i.test(attrValue))
119          {
120              return BuiltInFilters.filterIpv6(attrValue);
121          }
122   
123          return false;
124      },
125   
126      /**
127      * @param  {*} attrValue
128      * @return {*}
129      */
130      filterIpport: function(attrValue)
131      {
132          var m, ip;
133   
134          if (m = /^\[([\da-f:]+)(\]:[1-9]\d*)$/i.exec(attrValue))
135          {
136              ip = BuiltInFilters.filterIpv6(m[1]);
137   
138              if (ip === false)
139              {
140                  return false;
141              }
142   
143              return '[' + ip + m[2];
144          }
145   
146          if (m = /^([\d.]+)(:[1-9]\d*)$/.exec(attrValue))
147          {
148              ip = BuiltInFilters.filterIpv4(m[1]);
149   
150              if (ip === false)
151              {
152                  return false;
153              }
154   
155              return ip + m[2];
156          }
157   
158          return false;
159      },
160   
161      /**
162      * @param  {*} attrValue
163      * @return {*}
164      */
165      filterIpv4: function(attrValue)
166      {
167          if (!/^\d+\.\d+\.\d+\.\d+$/.test(attrValue))
168          {
169              return false;
170          }
171   
172          var i = 4, p = attrValue.split('.');
173          while (--i >= 0)
174          {
175              // NOTE: ext/filter doesn't support octal notation
176              if (p[i].charAt(0) === '0' || p[i] > 255)
177              {
178                  return false;
179              }
180          }
181   
182          return attrValue;
183      },
184   
185      /**
186      * @param  {*} attrValue
187      * @return {*}
188      */
189      filterIpv6: function(attrValue)
190      {
191          return /^(\d*:){2,7}\d+(?:\.\d+\.\d+\.\d+)?$/.test(attrValue) ? attrValue : false;
192      },
193   
194      /**
195      * @param  {*} attrValue
196      * @param  {!Array.<!Array>}  map
197      * @return {*}
198      */
199      filterMap: function(attrValue, map)
200      {
201          var i = -1, cnt = map.length;
202          while (++i < cnt)
203          {
204              if (map[i][0].test(attrValue))
205              {
206                  return map[i][1];
207              }
208          }
209   
210          return attrValue;
211      },
212   
213      /**
214      * @param  {*} attrValue
215      * @return {*}
216      */
217      filterNumber: function(attrValue)
218      {
219          return /^\d+$/.test(attrValue) ? attrValue : false;
220      },
221   
222      /**
223      * @param  {*}       attrValue
224      * @param  {!number} min
225      * @param  {!number} max
226      * @param  {Logger}  logger
227      * @return {!number|boolean}
228      */
229      filterRange: function(attrValue, min, max, logger)
230      {
231          if (!/^(?:0|-?[1-9]\d*)$/.test(attrValue))
232          {
233              return false;
234          }
235   
236          attrValue = parseInt(attrValue, 10);
237   
238          if (attrValue < min)
239          {
240              if (logger)
241              {
242                  logger.warn(
243                      'Value outside of range, adjusted up to min value',
244                      {
245                          'attrValue' : attrValue,
246                          'min'       : min,
247                          'max'       : max
248                      }
249                  );
250              }
251   
252              return min;
253          }
254   
255          if (attrValue > max)
256          {
257              if (logger)
258              {
259                  logger.warn(
260                      'Value outside of range, adjusted down to max value',
261                      {
262                          'attrValue' : attrValue,
263                          'min'       : min,
264                          'max'       : max
265                      }
266                  );
267              }
268   
269              return max;
270          }
271   
272          return attrValue;
273      },
274   
275      /**
276      * @param  {*} attrValue
277      * @param  {!RegExp} regexp
278      * @return {*}
279      */
280      filterRegexp: function(attrValue, regexp)
281      {
282          return regexp.test(attrValue) ? attrValue : false;
283      },
284   
285      /**
286      * @param  {*} attrValue
287      * @return {*}
288      */
289      filterSimpletext: function(attrValue)
290      {
291          return /^[-\w+., ]+$/.test(attrValue) ? attrValue : false;
292      },
293   
294      /**
295      * @param  {*} attrValue
296      * @return {*}
297      */
298      filterUint: function(attrValue)
299      {
300          return /^(?:0|[1-9]\d*)$/.test(attrValue) ? attrValue : false;
301      },
302   
303      /**
304      * @param  {*} attrValue
305      * @param  {!Object} urlConfig
306      * @param  {Logger} logger
307      * @return {*}
308      */
309      filterUrl: function(attrValue, urlConfig, logger)
310      {
311          /**
312          * Trim the URL to conform with HTML5 then parse it
313          * @link http://dev.w3.org/html5/spec/links.html#attr-hyperlink-href
314          */
315          var p = BuiltInFilters.parseUrl(attrValue.replace(/^\s+/, '').replace(/\s+$/, ''));
316   
317          var error = BuiltInFilters.validateUrl(urlConfig, p);
318          if (error)
319          {
320              if (logger)
321              {
322                  p['attrValue'] = attrValue;
323                  logger.err(error, p);
324              }
325   
326              return false;
327          }
328   
329          return BuiltInFilters.rebuildUrl(urlConfig, p);
330      },
331   
332      /**
333      * Parse a URL and return its components
334      *
335      * Similar to PHP's own parse_url() except that all parts are always returned
336      *
337      * @param  {!string} url Original URL
338      * @return {!Object}
339      */
340      parseUrl: function(url)
341      {
342          var regexp = /^(?:([a-z][-+.\w]*):)?(?:\/\/(?:([^:\/?#]*)(?::([^\/?#]*)?)?@)?(?:(\[[a-f\d:]+\]|[^:\/?#]+)(?::(\d*))?)?(?![^\/?#]))?([^?#]*)(\?[^#]*)?(#.*)?$/i;
343   
344          // NOTE: this regexp always matches because of the last three captures
345          var m = regexp['exec'](url),
346              parts = {},
347              tokens = ['scheme', 'user', 'pass', 'host', 'port', 'path', 'query', 'fragment'];
348          tokens.forEach(
349              function(name, i)
350              {
351                  parts[name] = (m[i + 1] > '') ? m[i + 1] : '';
352              }
353          );
354   
355          /**
356          * @link http://tools.ietf.org/html/rfc3986#section-3.1
357          *
358          * 'An implementation should accept uppercase letters as equivalent to lowercase in
359          * scheme names (e.g., allow "HTTP" as well as "http") for the sake of robustness but
360          * should only produce lowercase scheme names for consistency.'
361          */
362          parts['scheme'] = parts['scheme'].toLowerCase();
363   
364          /**
365          * Normalize the domain label separators and remove trailing dots
366          * @link http://url.spec.whatwg.org/#domain-label-separators
367          */
368          parts['host'] = parts['host'].replace(/[\u3002\uff0e\uff61]/g, '.').replace(/\.+$/g, '');
369   
370          // Test whether host has non-ASCII characters and punycode it if possible
371          if (/[^\x00-\x7F]/.test(parts['host']) && typeof punycode !== 'undefined')
372          {
373              parts['host'] = punycode.toASCII(parts['host']);
374          }
375   
376          return parts;
377      },
378   
379      /**
380      * Rebuild a parsed URL
381      *
382      * @param  {!Object} urlConfig
383      * @param  {!Object} p
384      * @return {!string}
385      */
386      rebuildUrl: function(urlConfig, p)
387      {
388          var url = '';
389          if (p['scheme'] !== '')
390          {
391              url += p['scheme'] + ':';
392          }
393          if (p['host'] === '')
394          {
395              // Allow the file: scheme to not have a host and ensure it starts with slashes
396              if (p['scheme'] === 'file')
397              {
398                  url += '//';
399              }
400          }
401          else
402          {
403              url += '//';
404   
405              // Add the credentials if applicable
406              if (p['user'] !== '')
407              {
408                  // Reencode the credentials in case there are invalid chars in them, or suspicious
409                  // characters such as : or @ that could confuse a browser into connecting to the
410                  // wrong host (or at least, to a host that is different than the one we thought)
411                  url += rawurlencode(decodeURIComponent(p['user']));
412   
413                  if (p['pass'] !== '')
414                  {
415                      url += ':' + rawurlencode(decodeURIComponent(p['pass']));
416                  }
417   
418                  url += '@';
419              }
420   
421              url += p['host'];
422   
423              // Append the port number (note that as per the regexp it can only contain digits)
424              if (p['port'] !== '')
425              {
426                  url += ':' + p['port'];
427              }
428          }
429   
430          // Build the path, including the query and fragment parts
431          var path = p['path'] + p['query'] + p['fragment'];
432   
433          /**
434          * "For consistency, URI producers and normalizers should use uppercase hexadecimal digits
435          * for all percent- encodings."
436          *
437          * @link http://tools.ietf.org/html/rfc3986#section-2.1
438          */
439          path = path.replace(
440              /%.?[a-f]/,
441              function (m)
442              {
443                  return m[0].toUpperCase();
444              },
445              path
446          );
447   
448          // Append the sanitized path to the URL
449          url += BuiltInFilters.sanitizeUrl(path);
450   
451          // Replace the first colon if there's no scheme and it could potentially be interpreted as
452          // the scheme separator
453          if (!p['scheme'])
454          {
455              url = url.replace(/^([^\/]*):/, '$1%3A', url);
456          }
457   
458          return url;
459      },
460   
461      /**
462      * Sanitize a URL for safe use regardless of context
463      *
464      * This method URL-encodes some sensitive characters in case someone would want to use the URL in
465      * some JavaScript thingy, or in CSS. We also encode characters that are not allowed in the path
466      * of a URL as defined in RFC 3986 appendix A, including percent signs that are not immediately
467      * followed by two hex digits.
468      *
469      * " and ' to prevent breaking out of quotes (JavaScript or otherwise)
470      * ( and ) to prevent the use of functions in JavaScript (eval()) or CSS (expression())
471      * < and > to prevent breaking out of <script>
472      * \r and \n because they're illegal in JavaScript
473      * [ and ] because the W3 validator rejects them and they "should" be escaped as per RFC 3986
474      * Non-ASCII characters as per RFC 3986
475      * Control codes and spaces, as per RFC 3986
476      *
477      * @link http://sla.ckers.org/forum/read.php?2,51478
478      * @link http://timelessrepo.com/json-isnt-a-javascript-subset
479      * @link http://www.ietf.org/rfc/rfc3986.txt
480      * @link http://stackoverflow.com/a/1547922
481      * @link http://tools.ietf.org/html/rfc3986#appendix-A
482      *
483      * @param  {!string} url Original URL
484      * @return {!string}     Sanitized URL
485      */
486      sanitizeUrl: function(url)
487      {
488          return url.replace(/[^\u0020-\u007E]+/g, encodeURIComponent).replace(/%(?![0-9A-Fa-f]{2})|[^!#-&*-;=?-Z_a-z~]/g, escape);
489      },
490   
491      /**
492      * Validate a parsed URL
493      *
494      * @param  {!Object} urlConfig
495      * @param  {!Object} p
496      * @return {string|undefined}
497      */
498      validateUrl: function(urlConfig, p)
499      {
500          if (p['scheme'] !== '' && !urlConfig.allowedSchemes.test(p['scheme']))
501          {
502              return 'URL scheme is not allowed';
503          }
504   
505          if (p['host'] === '')
506          {
507              // Reject malformed URLs such as http:///example.org but allow schemeless paths
508              if (p['scheme'] !== 'file' && p['scheme'] !== '')
509              {
510                  return 'Missing host';
511              }
512          }
513          else
514          {
515              /**
516              * Test whether the host is valid
517              * @link http://tools.ietf.org/html/rfc1035#section-2.3.1
518              * @link http://tools.ietf.org/html/rfc1123#section-2
519              */
520              var regexp = /^(?!-)[-a-z0-9]{0,62}[a-z0-9](?:\.(?!-)[-a-z0-9]{0,62}[a-z0-9])*$/i;
521              if (!regexp.test(p['host']))
522              {
523                  // If the host invalid, retest as an IPv4 and IPv6 address (IPv6 in brackets)
524                  if (!BuiltInFilters.filterIpv4(p['host'])
525                   && !BuiltInFilters.filterIpv6(p['host'].replace(/^\[(.*)\]$/, '$1', p['host'])))
526                  {
527                      return 'URL host is invalid';
528                  }
529              }
530   
531              if ((urlConfig.disallowedHosts && urlConfig.disallowedHosts.test(p['host']))
532               || (urlConfig.restrictedHosts && !urlConfig.restrictedHosts.test(p['host'])))
533              {
534                  return 'URL host is not allowed';
535              }
536          }
537      }
538  }