FileSystemImportManager.js 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. /* eslint-disable
  2. camelcase,
  3. handle-callback-err,
  4. max-len,
  5. no-unused-vars,
  6. standard/no-callback-literal,
  7. */
  8. // TODO: This file was created by bulk-decaffeinate.
  9. // Fix any style issues and re-enable lint.
  10. /*
  11. * decaffeinate suggestions:
  12. * DS102: Remove unnecessary code created because of implicit returns
  13. * DS207: Consider shorter variations of null checks
  14. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  15. */
  16. let FileSystemImportManager
  17. const async = require('async')
  18. const fs = require('fs')
  19. const _ = require('underscore')
  20. const FileTypeManager = require('./FileTypeManager')
  21. const EditorController = require('../Editor/EditorController')
  22. const logger = require('logger-sharelatex')
  23. module.exports = FileSystemImportManager = {
  24. addDoc(
  25. user_id,
  26. project_id,
  27. folder_id,
  28. name,
  29. path,
  30. encoding,
  31. replace,
  32. callback
  33. ) {
  34. if (callback == null) {
  35. callback = function(error, doc) {}
  36. }
  37. return FileSystemImportManager._isSafeOnFileSystem(path, function(
  38. err,
  39. isSafe
  40. ) {
  41. if (!isSafe) {
  42. logger.log(
  43. { user_id, project_id, folder_id, name, path },
  44. 'add doc is from symlink, stopping process'
  45. )
  46. return callback(new Error('path is symlink'))
  47. }
  48. return fs.readFile(path, encoding, function(error, content) {
  49. if (error != null) {
  50. return callback(error)
  51. }
  52. content = content.replace(/\r\n?/g, '\n') // convert Windows line endings to unix. very old macs also created \r-separated lines
  53. const lines = content.split('\n')
  54. if (replace) {
  55. return EditorController.upsertDoc(
  56. project_id,
  57. folder_id,
  58. name,
  59. lines,
  60. 'upload',
  61. user_id,
  62. callback
  63. )
  64. } else {
  65. return EditorController.addDoc(
  66. project_id,
  67. folder_id,
  68. name,
  69. lines,
  70. 'upload',
  71. user_id,
  72. callback
  73. )
  74. }
  75. })
  76. })
  77. },
  78. addFile(user_id, project_id, folder_id, name, path, replace, callback) {
  79. if (callback == null) {
  80. callback = function(error, file) {}
  81. }
  82. return FileSystemImportManager._isSafeOnFileSystem(path, function(
  83. err,
  84. isSafe
  85. ) {
  86. if (!isSafe) {
  87. logger.log(
  88. { user_id, project_id, folder_id, name, path },
  89. 'add file is from symlink, stopping insert'
  90. )
  91. return callback(new Error('path is symlink'))
  92. }
  93. if (replace) {
  94. return EditorController.upsertFile(
  95. project_id,
  96. folder_id,
  97. name,
  98. path,
  99. null,
  100. 'upload',
  101. user_id,
  102. callback
  103. )
  104. } else {
  105. return EditorController.addFile(
  106. project_id,
  107. folder_id,
  108. name,
  109. path,
  110. null,
  111. 'upload',
  112. user_id,
  113. callback
  114. )
  115. }
  116. })
  117. },
  118. addFolder(user_id, project_id, folder_id, name, path, replace, callback) {
  119. if (callback == null) {
  120. callback = function(error) {}
  121. }
  122. return FileSystemImportManager._isSafeOnFileSystem(path, function(
  123. err,
  124. isSafe
  125. ) {
  126. if (!isSafe) {
  127. logger.log(
  128. { user_id, project_id, folder_id, path },
  129. 'add folder is from symlink, stopping insert'
  130. )
  131. return callback(new Error('path is symlink'))
  132. }
  133. return EditorController.addFolder(
  134. project_id,
  135. folder_id,
  136. name,
  137. 'upload',
  138. (error, new_folder) => {
  139. if (error != null) {
  140. return callback(error)
  141. }
  142. return FileSystemImportManager.addFolderContents(
  143. user_id,
  144. project_id,
  145. new_folder._id,
  146. path,
  147. replace,
  148. function(error) {
  149. if (error != null) {
  150. return callback(error)
  151. }
  152. return callback(null, new_folder)
  153. }
  154. )
  155. }
  156. )
  157. })
  158. },
  159. addFolderContents(
  160. user_id,
  161. project_id,
  162. parent_folder_id,
  163. folderPath,
  164. replace,
  165. callback
  166. ) {
  167. if (callback == null) {
  168. callback = function(error) {}
  169. }
  170. return FileSystemImportManager._isSafeOnFileSystem(folderPath, function(
  171. err,
  172. isSafe
  173. ) {
  174. if (!isSafe) {
  175. logger.log(
  176. { user_id, project_id, parent_folder_id, folderPath },
  177. 'add folder contents is from symlink, stopping insert'
  178. )
  179. return callback(new Error('path is symlink'))
  180. }
  181. return fs.readdir(folderPath, (error, entries) => {
  182. if (entries == null) {
  183. entries = []
  184. }
  185. if (error != null) {
  186. return callback(error)
  187. }
  188. return async.eachSeries(
  189. entries,
  190. (entry, callback) => {
  191. return FileTypeManager.shouldIgnore(entry, (error, ignore) => {
  192. if (error != null) {
  193. return callback(error)
  194. }
  195. if (!ignore) {
  196. return FileSystemImportManager.addEntity(
  197. user_id,
  198. project_id,
  199. parent_folder_id,
  200. entry,
  201. `${folderPath}/${entry}`,
  202. replace,
  203. callback
  204. )
  205. } else {
  206. return callback()
  207. }
  208. })
  209. },
  210. callback
  211. )
  212. })
  213. })
  214. },
  215. addEntity(user_id, project_id, folder_id, name, path, replace, callback) {
  216. if (callback == null) {
  217. callback = function(error, entity) {}
  218. }
  219. return FileSystemImportManager._isSafeOnFileSystem(path, function(
  220. err,
  221. isSafe
  222. ) {
  223. if (!isSafe) {
  224. logger.log(
  225. { user_id, project_id, folder_id, path },
  226. 'add entry is from symlink, stopping insert'
  227. )
  228. return callback(new Error('path is symlink'))
  229. }
  230. return FileTypeManager.isDirectory(path, (error, isDirectory) => {
  231. if (error != null) {
  232. return callback(error)
  233. }
  234. if (isDirectory) {
  235. return FileSystemImportManager.addFolder(
  236. user_id,
  237. project_id,
  238. folder_id,
  239. name,
  240. path,
  241. replace,
  242. callback
  243. )
  244. } else {
  245. return FileTypeManager.getType(
  246. name,
  247. path,
  248. (error, { binary, encoding }) => {
  249. if (error != null) {
  250. return callback(error)
  251. }
  252. if (binary) {
  253. return FileSystemImportManager.addFile(
  254. user_id,
  255. project_id,
  256. folder_id,
  257. name,
  258. path,
  259. replace,
  260. function(err, entity) {
  261. if (entity != null) {
  262. entity.type = 'file'
  263. }
  264. return callback(err, entity)
  265. }
  266. )
  267. } else {
  268. return FileSystemImportManager.addDoc(
  269. user_id,
  270. project_id,
  271. folder_id,
  272. name,
  273. path,
  274. encoding,
  275. replace,
  276. function(err, entity) {
  277. if (entity != null) {
  278. entity.type = 'doc'
  279. }
  280. return callback(err, entity)
  281. }
  282. )
  283. }
  284. }
  285. )
  286. }
  287. })
  288. })
  289. },
  290. _isSafeOnFileSystem(path, callback) {
  291. if (callback == null) {
  292. callback = function(err, isSafe) {}
  293. }
  294. return fs.lstat(path, function(err, stat) {
  295. if (err != null) {
  296. logger.warn({ err }, 'error with path symlink check')
  297. return callback(err)
  298. }
  299. const isSafe = stat.isFile() || stat.isDirectory()
  300. return callback(err, isSafe)
  301. })
  302. }
  303. }