2017-02-18 01:56:23 -07:00
|
|
|
'use strict';
|
2014-04-17 13:11:53 -04:00
|
|
|
|
2019-09-23 22:30:17 -04:00
|
|
|
const fs = require('fs');
|
|
|
|
|
const nconf = require('nconf');
|
|
|
|
|
const path = require('path');
|
|
|
|
|
const winston = require('winston');
|
|
|
|
|
const mkdirp = require('mkdirp');
|
|
|
|
|
const mime = require('mime');
|
|
|
|
|
const graceful = require('graceful-fs');
|
|
|
|
|
|
2020-10-11 21:49:37 -04:00
|
|
|
const slugify = require('./slugify');
|
2017-10-30 14:45:41 -04:00
|
|
|
|
2017-11-16 15:43:52 -07:00
|
|
|
graceful.gracefulify(fs);
|
|
|
|
|
|
2019-09-23 22:30:17 -04:00
|
|
|
const file = module.exports;
|
2017-10-31 20:18:15 -06:00
|
|
|
|
2019-09-23 22:30:17 -04:00
|
|
|
file.saveFileToLocal = async function (filename, folder, tempPath) {
|
2017-10-30 14:45:41 -04:00
|
|
|
/*
|
|
|
|
|
* remarkable doesn't allow spaces in hyperlinks, once that's fixed, remove this.
|
|
|
|
|
*/
|
2020-10-11 21:49:37 -04:00
|
|
|
filename = filename.split('.').map(name => slugify(name)).join('.');
|
2017-10-30 14:45:41 -04:00
|
|
|
|
2019-09-23 22:30:17 -04:00
|
|
|
const uploadPath = path.join(nconf.get('upload_path'), folder, filename);
|
2020-06-22 12:08:35 -04:00
|
|
|
if (!uploadPath.startsWith(nconf.get('upload_path'))) {
|
|
|
|
|
throw new Error('[[error:invalid-path]]');
|
|
|
|
|
}
|
2014-02-13 20:43:19 -05:00
|
|
|
|
2021-02-03 23:59:08 -07:00
|
|
|
winston.verbose(`Saving file ${filename} to : ${uploadPath}`);
|
2020-01-31 14:10:00 -05:00
|
|
|
await mkdirp(path.dirname(uploadPath));
|
2020-08-14 00:05:03 -04:00
|
|
|
await fs.promises.copyFile(tempPath, uploadPath);
|
2019-09-23 22:30:17 -04:00
|
|
|
return {
|
2021-02-03 23:59:08 -07:00
|
|
|
url: `/assets/uploads/${folder ? `${folder}/` : ''}${filename}`,
|
2019-09-23 22:30:17 -04:00
|
|
|
path: uploadPath,
|
|
|
|
|
};
|
2014-04-17 13:11:53 -04:00
|
|
|
};
|
2014-02-13 20:43:19 -05:00
|
|
|
|
2019-09-23 22:30:17 -04:00
|
|
|
file.base64ToLocal = async function (imageData, uploadPath) {
|
|
|
|
|
const buffer = Buffer.from(imageData.slice(imageData.indexOf('base64') + 7), 'base64');
|
2017-02-08 11:41:24 -07:00
|
|
|
uploadPath = path.join(nconf.get('upload_path'), uploadPath);
|
2016-02-04 10:13:03 -05:00
|
|
|
|
2020-08-14 00:05:03 -04:00
|
|
|
await fs.promises.writeFile(uploadPath, buffer, {
|
2017-02-17 19:31:21 -07:00
|
|
|
encoding: 'base64',
|
2016-02-04 10:13:03 -05:00
|
|
|
});
|
2019-09-23 22:30:17 -04:00
|
|
|
return uploadPath;
|
2016-02-04 10:13:03 -05:00
|
|
|
};
|
|
|
|
|
|
2018-09-20 17:05:52 -04:00
|
|
|
// https://stackoverflow.com/a/31205878/583363
|
|
|
|
|
file.appendToFileName = function (filename, string) {
|
2019-09-23 22:30:17 -04:00
|
|
|
const dotIndex = filename.lastIndexOf('.');
|
2018-09-20 17:05:52 -04:00
|
|
|
if (dotIndex === -1) {
|
|
|
|
|
return filename + string;
|
|
|
|
|
}
|
|
|
|
|
return filename.substring(0, dotIndex) + string + filename.substring(dotIndex);
|
|
|
|
|
};
|
|
|
|
|
|
2016-10-13 11:43:39 +02:00
|
|
|
file.allowedExtensions = function () {
|
2019-09-23 22:30:17 -04:00
|
|
|
const meta = require('./meta');
|
|
|
|
|
let allowedExtensions = (meta.config.allowedFileExtensions || '').trim();
|
2015-12-28 15:38:02 +02:00
|
|
|
if (!allowedExtensions) {
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
allowedExtensions = allowedExtensions.split(',');
|
2021-02-04 00:01:39 -07:00
|
|
|
allowedExtensions = allowedExtensions.filter(Boolean).map((extension) => {
|
2015-12-28 15:38:02 +02:00
|
|
|
extension = extension.trim();
|
|
|
|
|
if (!extension.startsWith('.')) {
|
2021-02-03 23:59:08 -07:00
|
|
|
extension = `.${extension}`;
|
2015-12-28 15:38:02 +02:00
|
|
|
}
|
2017-05-01 20:58:34 -04:00
|
|
|
return extension.toLowerCase();
|
2015-12-28 15:38:02 +02:00
|
|
|
});
|
|
|
|
|
|
2018-10-20 14:40:48 -04:00
|
|
|
if (allowedExtensions.includes('.jpg') && !allowedExtensions.includes('.jpeg')) {
|
2015-12-28 15:38:02 +02:00
|
|
|
allowedExtensions.push('.jpeg');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return allowedExtensions;
|
|
|
|
|
};
|
|
|
|
|
|
2019-09-23 22:30:17 -04:00
|
|
|
file.exists = async function (path) {
|
|
|
|
|
try {
|
2020-08-14 00:05:03 -04:00
|
|
|
await fs.promises.stat(path);
|
2019-09-23 22:30:17 -04:00
|
|
|
} catch (err) {
|
|
|
|
|
if (err.code === 'ENOENT') {
|
|
|
|
|
return false;
|
2017-01-02 22:23:17 -07:00
|
|
|
}
|
2019-09-23 22:30:17 -04:00
|
|
|
throw err;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
2015-09-29 18:22:41 -04:00
|
|
|
};
|
|
|
|
|
|
2016-10-13 11:43:39 +02:00
|
|
|
file.existsSync = function (path) {
|
2015-09-29 18:22:41 -04:00
|
|
|
try {
|
2017-01-02 22:23:17 -07:00
|
|
|
fs.statSync(path);
|
|
|
|
|
} catch (err) {
|
|
|
|
|
if (err.code === 'ENOENT') {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
throw err;
|
2015-09-29 18:22:41 -04:00
|
|
|
}
|
|
|
|
|
|
2017-01-02 22:23:17 -07:00
|
|
|
return true;
|
2015-09-29 18:22:41 -04:00
|
|
|
};
|
|
|
|
|
|
2019-09-23 22:30:17 -04:00
|
|
|
file.delete = async function (path) {
|
2018-04-06 15:16:28 -04:00
|
|
|
if (!path) {
|
2019-09-23 22:30:17 -04:00
|
|
|
return;
|
2017-05-24 00:02:30 -04:00
|
|
|
}
|
2019-09-23 22:30:17 -04:00
|
|
|
try {
|
2020-08-14 00:05:03 -04:00
|
|
|
await fs.promises.unlink(path);
|
2019-09-23 22:30:17 -04:00
|
|
|
} catch (err) {
|
|
|
|
|
winston.warn(err);
|
2017-10-31 20:18:15 -06:00
|
|
|
}
|
2019-09-23 22:30:17 -04:00
|
|
|
};
|
2017-10-31 20:18:15 -06:00
|
|
|
|
2019-09-23 22:30:17 -04:00
|
|
|
file.link = async function link(filePath, destPath, relative) {
|
2017-10-31 20:18:15 -06:00
|
|
|
if (relative && process.platform !== 'win32') {
|
|
|
|
|
filePath = path.relative(path.dirname(destPath), filePath);
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-15 12:38:16 -07:00
|
|
|
if (process.platform === 'win32') {
|
2020-08-14 00:05:03 -04:00
|
|
|
await fs.promises.link(filePath, destPath);
|
2017-01-15 12:38:16 -07:00
|
|
|
} else {
|
2020-08-14 00:05:03 -04:00
|
|
|
await fs.promises.symlink(filePath, destPath, 'file');
|
2017-01-15 12:38:16 -07:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2019-09-23 22:30:17 -04:00
|
|
|
file.linkDirs = async function linkDirs(sourceDir, destDir, relative) {
|
2017-10-31 20:18:15 -06:00
|
|
|
if (relative && process.platform !== 'win32') {
|
|
|
|
|
sourceDir = path.relative(path.dirname(destDir), sourceDir);
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-23 22:30:17 -04:00
|
|
|
const type = (process.platform === 'win32') ? 'junction' : 'dir';
|
2020-08-14 00:05:03 -04:00
|
|
|
await fs.promises.symlink(sourceDir, destDir, type);
|
2017-01-21 18:57:27 -07:00
|
|
|
};
|
|
|
|
|
|
2017-02-17 19:42:02 +00:00
|
|
|
file.typeToExtension = function (type) {
|
2019-09-23 22:30:17 -04:00
|
|
|
let extension = '';
|
2017-02-17 19:42:02 +00:00
|
|
|
if (type) {
|
2021-02-03 23:59:08 -07:00
|
|
|
extension = `.${mime.getExtension(type)}`;
|
2017-02-17 19:42:02 +00:00
|
|
|
}
|
|
|
|
|
return extension;
|
|
|
|
|
};
|
|
|
|
|
|
2017-04-08 20:22:21 -06:00
|
|
|
// Adapted from http://stackoverflow.com/questions/5827612/node-js-fs-readdir-recursive-directory-search
|
2019-09-23 22:30:17 -04:00
|
|
|
file.walk = async function (dir) {
|
2020-08-14 00:05:03 -04:00
|
|
|
const subdirs = await fs.promises.readdir(dir);
|
2019-09-23 22:30:17 -04:00
|
|
|
const files = await Promise.all(subdirs.map(async (subdir) => {
|
|
|
|
|
const res = path.resolve(dir, subdir);
|
2020-08-14 00:05:03 -04:00
|
|
|
return (await fs.promises.stat(res)).isDirectory() ? file.walk(res) : res;
|
2019-09-23 22:30:17 -04:00
|
|
|
}));
|
2019-09-23 22:31:55 -04:00
|
|
|
return files.reduce((a, f) => a.concat(f), []);
|
2017-04-08 20:22:21 -06:00
|
|
|
};
|
2019-07-09 12:46:49 -04:00
|
|
|
|
|
|
|
|
require('./promisify')(file);
|