test.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. "use strict";
  2. var test = require("tape"),
  3. sanitize = require("./");
  4. function repeat(string, times) {
  5. return new Array(times + 1).join(string);
  6. }
  7. var REPLACEMENT_OPTS = {
  8. replacement: "_",
  9. };
  10. test("valid names", function(t) {
  11. ["the quick brown fox jumped over the lazy dog.mp3",
  12. "résumé"].forEach(function(name) {
  13. t.equal(sanitize(name), name);
  14. });
  15. t.end();
  16. });
  17. test("valid names", function(t) {
  18. ["valid name.mp3", "résumé"].forEach(function(name) {
  19. t.equal(sanitize(name, REPLACEMENT_OPTS), name);
  20. });
  21. t.end();
  22. });
  23. test("null character", function(t) {
  24. t.equal(sanitize("hello\u0000world"), "helloworld");
  25. t.end();
  26. });
  27. test("null character", function(t) {
  28. t.equal(sanitize("hello\u0000world", REPLACEMENT_OPTS), "hello_world");
  29. t.end();
  30. });
  31. test("control characters", function(t) {
  32. t.equal(sanitize("hello\nworld"), "helloworld");
  33. t.end();
  34. });
  35. test("control characters", function(t) {
  36. t.equal(sanitize("hello\nworld", REPLACEMENT_OPTS), "hello_world");
  37. t.end();
  38. });
  39. test("restricted codes", function(t) {
  40. ["h?w", "h/w", "h*w"].forEach(function(name) {
  41. t.equal(sanitize(name), "hw");
  42. });
  43. t.end();
  44. });
  45. test("restricted codes", function(t) {
  46. ["h?w", "h/w", "h*w"].forEach(function(name) {
  47. t.equal(sanitize(name, REPLACEMENT_OPTS), "h_w");
  48. });
  49. t.end();
  50. });
  51. // https://msdn.microsoft.com/en-us/library/aa365247(v=vs.85).aspx
  52. test("restricted suffixes", function(t) {
  53. ["mr.", "mr..", "mr ", "mr "].forEach(function(name) {
  54. t.equal(sanitize(name), "mr");
  55. });
  56. t.end();
  57. });
  58. test("relative paths", function(t) {
  59. [".", "..", "./", "../", "/..", "/../", "*.|."].forEach(function(name) {
  60. t.equal(sanitize(name), "");
  61. });
  62. t.end();
  63. });
  64. test("relative path with replacement", function(t) {
  65. t.equal(sanitize("..", REPLACEMENT_OPTS), "_");
  66. t.end();
  67. });
  68. test("reserved filename in Windows", function(t) {
  69. t.equal(sanitize("con"), "");
  70. t.equal(sanitize("COM1"), "");
  71. t.equal(sanitize("PRN."), "");
  72. t.equal(sanitize("aux.txt"), "");
  73. t.equal(sanitize("LPT9.asdfasdf"), "");
  74. t.equal(sanitize("LPT10.txt"), "LPT10.txt");
  75. t.end();
  76. });
  77. test("reserved filename in Windows with replacement", function(t) {
  78. t.equal(sanitize("con", REPLACEMENT_OPTS), "_");
  79. t.equal(sanitize("COM1", REPLACEMENT_OPTS), "_");
  80. t.equal(sanitize("PRN.", REPLACEMENT_OPTS), "_");
  81. t.equal(sanitize("aux.txt", REPLACEMENT_OPTS), "_");
  82. t.equal(sanitize("LPT9.asdfasdf", REPLACEMENT_OPTS), "_");
  83. t.equal(sanitize("LPT10.txt", REPLACEMENT_OPTS), "LPT10.txt");
  84. t.end();
  85. });
  86. test("invalid replacement", function (t) {
  87. t.equal(sanitize(".", { replacement: "."}), "");
  88. t.equal(sanitize("foo?.txt", { replacement: ">"}), "foo.txt");
  89. t.equal(sanitize("con.txt", { replacement: "aux"}), "");
  90. t.equal(sanitize("valid.txt", { replacement: "\/:*?\"<>|"}), "valid.txt");
  91. t.end();
  92. });
  93. test("255 characters max", function(t) {
  94. var string = repeat("a", 300);
  95. t.ok(string.length > 255);
  96. t.ok(sanitize(string).length <= 255);
  97. t.end();
  98. });
  99. // Test the handling of non-BMP chars in UTF-8
  100. //
  101. test("non-bmp SADDLES the limit", function(t){
  102. var str25x = repeat("a", 252),
  103. name = str25x + '\uD800\uDC00';
  104. t.equal(sanitize(name), str25x);
  105. t.end();
  106. });
  107. test("non-bmp JUST WITHIN the limit", function(t){
  108. var str25x = repeat('a', 251),
  109. name = str25x + '\uD800\uDC00';
  110. t.equal(sanitize(name), name);
  111. t.end();
  112. });
  113. test("non-bmp JUST OUTSIDE the limit", function(t){
  114. var str25x = repeat('a', 253),
  115. name = str25x + '\uD800\uDC00';
  116. t.equal(sanitize(name), str25x);
  117. t.end();
  118. });
  119. function testStringUsingFS(str, t) {
  120. var sanitized = sanitize(str) || "default";
  121. var filepath = path.join(tempdir, sanitized);
  122. // Should not contain any directories or relative paths
  123. t.equal(path.dirname(path.resolve("/abs/path", sanitized)), path.resolve("/abs/path"));
  124. // Should be max 255 bytes
  125. t.assert(Buffer.byteLength(sanitized) <= 255, "max 255 bytes");
  126. // Should write and read file to disk
  127. t.equal(path.dirname(path.normalize(filepath)), tempdir);
  128. fs.writeFile(filepath, "foobar", function(err) {
  129. t.ifError(err, "no error writing file");
  130. fs.readFile(filepath, function(err, data) {
  131. t.ifError(err, "no error reading file");
  132. t.equal(data.toString(), "foobar", "file contents equals");
  133. fs.unlink(filepath, function(err) {
  134. t.ifError(err, "no error unlinking file");
  135. t.end();
  136. });
  137. });
  138. });
  139. }
  140. // Don't run these tests in browser environments
  141. if ( ! process.browser) {
  142. // ## Browserify Build
  143. //
  144. // Make sure Buffer is not used when building using browserify.
  145. //
  146. var browserify = require("browserify");
  147. var concat = require("concat-stream");
  148. test("browserify build", function(t) {
  149. var bundle = browserify(__dirname).bundle();
  150. bundle.on("error", t.ifError);
  151. bundle.pipe(concat(function(data) {
  152. var source = data.toString();
  153. t.ok(source.indexOf("Buffer") === -1);
  154. t.end();
  155. }));
  156. });
  157. // ## Filesystem Tests
  158. //
  159. // Test writing files to the local filesystem.
  160. //
  161. var fs = require("fs");
  162. var path = require("path");
  163. var mktemp = require("mktemp");
  164. var tempdir = mktemp.createDirSync("sanitize-filename-test-XXXXXX");
  165. try {
  166. var blns = require("./vendor/big-list-of-naughty-strings/blns.json");
  167. }
  168. catch (err) {
  169. console.error("Error: Cannot load file './vendor/big-list-of-naughty-strings/blns.json'");
  170. console.error();
  171. console.error("Make sure you've initialized git submodules by running");
  172. console.error();
  173. console.error(" git submodule update --init");
  174. console.error();
  175. process.exit(1);
  176. }
  177. [].concat(
  178. [
  179. repeat("a", 300),
  180. "the quick brown fox jumped over the lazy dog",
  181. "résumé",
  182. "hello\u0000world",
  183. "hello\nworld",
  184. "semi;colon.js",
  185. ";leading-semi.js",
  186. "slash\\.js",
  187. "slash/.js",
  188. "col:on.js",
  189. "star*.js",
  190. "question?.js",
  191. "quote\".js",
  192. "singlequote'.js",
  193. "brack<e>ts.js",
  194. "p|pes.js",
  195. "plus+.js",
  196. "'five and six<seven'.js",
  197. " space at front",
  198. "space at end ",
  199. ".period",
  200. "period.",
  201. "relative/path/to/some/dir",
  202. "/abs/path/to/some/dir",
  203. "~/.\u0000notssh/authorized_keys",
  204. "",
  205. "h?w",
  206. "h/w",
  207. "h*w",
  208. ".",
  209. "..",
  210. "./",
  211. "../",
  212. "/..",
  213. "/../",
  214. "*.|.",
  215. "./",
  216. "./foobar",
  217. "../foobar",
  218. "../../foobar",
  219. "./././foobar",
  220. "|*.what",
  221. "LPT9.asdf",
  222. ],
  223. blns
  224. ).forEach(function(str) {
  225. test(JSON.stringify(str), function(t) {
  226. testStringUsingFS(str, t);
  227. });
  228. });
  229. test("remove temp directory", function(t) {
  230. fs.rmdir(tempdir, function(err) {
  231. t.ifError(err);
  232. t.end();
  233. });
  234. });
  235. }