SafePath.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. /* eslint-disable
  2. max-len,
  3. no-return-assign,
  4. */
  5. // TODO: This file was created by bulk-decaffeinate.
  6. // Fix any style issues and re-enable lint.
  7. /*
  8. * decaffeinate suggestions:
  9. * DS101: Remove unnecessary use of Array.from
  10. * DS102: Remove unnecessary code created because of implicit returns
  11. * DS207: Consider shorter variations of null checks
  12. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  13. */
  14. // This file is shared between the frontend and server code of web, so that
  15. // filename validation is the same in both implementations.
  16. // The logic in all copies must be kept in sync:
  17. // app/src/Features/Project/SafePath.js
  18. // frontend/js/ide/directives/SafePath.js
  19. // frontend/js/features/file-tree/util/safe-path.js
  20. const load = function() {
  21. let SafePath
  22. const BADCHAR_RX = new RegExp(
  23. `\
  24. [\
  25. \\/\
  26. \\\\\
  27. \\*\
  28. \\u0000-\\u001F\
  29. \\u007F\
  30. \\u0080-\\u009F\
  31. \\uD800-\\uDFFF\
  32. ]\
  33. `,
  34. 'g'
  35. )
  36. const BADFILE_RX = new RegExp(
  37. `\
  38. (^\\.$)\
  39. |(^\\.\\.$)\
  40. |(^\\s+)\
  41. |(\\s+$)\
  42. `,
  43. 'g'
  44. )
  45. // Put a block on filenames which match javascript property names, as they
  46. // can cause exceptions where the code puts filenames into a hash. This is a
  47. // temporary workaround until the code in other places is made safe against
  48. // property names.
  49. //
  50. // The list of property names is taken from
  51. // ['prototype'].concat(Object.getOwnPropertyNames(Object.prototype))
  52. const BLOCKEDFILE_RX = new RegExp(`\
  53. ^(\
  54. prototype\
  55. |constructor\
  56. |toString\
  57. |toLocaleString\
  58. |valueOf\
  59. |hasOwnProperty\
  60. |isPrototypeOf\
  61. |propertyIsEnumerable\
  62. |__defineGetter__\
  63. |__lookupGetter__\
  64. |__defineSetter__\
  65. |__lookupSetter__\
  66. |__proto__\
  67. )$\
  68. `)
  69. const MAX_PATH = 1024 // Maximum path length, in characters. This is fairly arbitrary.
  70. return (SafePath = {
  71. // convert any invalid characters to underscores in the given filename
  72. clean(filename) {
  73. filename = filename.replace(BADCHAR_RX, '_')
  74. // for BADFILE_RX replace any matches with an equal number of underscores
  75. filename = filename.replace(BADFILE_RX, match =>
  76. new Array(match.length + 1).join('_')
  77. )
  78. // replace blocked filenames 'prototype' with '@prototype'
  79. filename = filename.replace(BLOCKEDFILE_RX, '@$1')
  80. return filename
  81. },
  82. // returns whether the filename is 'clean' (does not contain any invalid
  83. // characters or reserved words)
  84. isCleanFilename(filename) {
  85. return (
  86. SafePath.isAllowedLength(filename) &&
  87. !filename.match(BADCHAR_RX) &&
  88. !filename.match(BADFILE_RX)
  89. )
  90. },
  91. isBlockedFilename(filename) {
  92. return BLOCKEDFILE_RX.test(filename)
  93. },
  94. // returns whether a full path is 'clean' - e.g. is a full or relative path
  95. // that points to a file, and each element passes the rules in 'isCleanFilename'
  96. isCleanPath(path) {
  97. const elements = path.split('/')
  98. const lastElementIsEmpty = elements[elements.length - 1].length === 0
  99. if (lastElementIsEmpty) {
  100. return false
  101. }
  102. for (let element of Array.from(elements)) {
  103. if (element.length > 0 && !SafePath.isCleanFilename(element)) {
  104. return false
  105. }
  106. }
  107. // check for a top-level reserved name
  108. if (BLOCKEDFILE_RX.test(path.replace(/^\/?/, ''))) {
  109. return false
  110. } // remove leading slash if present
  111. return true
  112. },
  113. isAllowedLength(pathname) {
  114. return pathname.length > 0 && pathname.length <= MAX_PATH
  115. }
  116. })
  117. }
  118. module.exports = load()