safe-path.ts 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. // This file is shared between the frontend and server code of web, so that
  2. // filename validation is the same in both implementations.
  3. // The logic in all copies must be kept in sync:
  4. // app/src/Features/Project/SafePath.js
  5. // frontend/js/ide/directives/SafePath.js
  6. // frontend/js/features/file-tree/util/safe-path.js
  7. // eslint-disable-next-line prefer-regex-literals
  8. const BADCHAR_RX = new RegExp(
  9. `\
  10. [\
  11. \\/\
  12. \\\\\
  13. \\*\
  14. \\u0000-\\u001F\
  15. \\u007F\
  16. \\u0080-\\u009F\
  17. \\uD800-\\uDFFF\
  18. ]\
  19. `,
  20. 'g'
  21. )
  22. // eslint-disable-next-line prefer-regex-literals
  23. const BADFILE_RX = new RegExp(
  24. `\
  25. (^\\.$)\
  26. |(^\\.\\.$)\
  27. |(^\\s+)\
  28. |(\\s+$)\
  29. `,
  30. 'g'
  31. )
  32. // Put a block on filenames which match javascript property names, as they
  33. // can cause exceptions where the code puts filenames into a hash. This is a
  34. // temporary workaround until the code in other places is made safe against
  35. // property names.
  36. //
  37. // The list of property names is taken from
  38. // ['prototype'].concat(Object.getOwnPropertyNames(Object.prototype))
  39. // eslint-disable-next-line prefer-regex-literals
  40. const BLOCKEDFILE_RX = new RegExp(`\
  41. ^(\
  42. prototype\
  43. |constructor\
  44. |toString\
  45. |toLocaleString\
  46. |valueOf\
  47. |hasOwnProperty\
  48. |isPrototypeOf\
  49. |propertyIsEnumerable\
  50. |__defineGetter__\
  51. |__lookupGetter__\
  52. |__defineSetter__\
  53. |__lookupSetter__\
  54. |__proto__\
  55. )$\
  56. `)
  57. const MAX_PATH = 1024 // Maximum path length, in characters. This is fairly arbitrary.
  58. export function isCleanFilename(filename: string): boolean {
  59. return (
  60. isAllowedLength(filename) &&
  61. !filename.match(BADCHAR_RX) &&
  62. !filename.match(BADFILE_RX)
  63. )
  64. }
  65. export function isBlockedFilename(filename: string): boolean {
  66. return BLOCKEDFILE_RX.test(filename)
  67. }
  68. export function isAllowedLength(pathname: string): boolean {
  69. return pathname.length > 0 && pathname.length <= MAX_PATH
  70. }