Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

File comment max length #282

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions app.js
Expand Up @@ -34,6 +34,11 @@ if(config.sslPort && config.sslKeyFile && config.sslCertFile) {
});
}

if(config['fileCommentMaxLength'] > 255 ) {
console.error("fileCommentMaxLength must be lower than 256. Please update your config file!");
shutdown();
}


// graceful shutdown
function shutdown() {
Expand Down
10 changes: 9 additions & 1 deletion app/src/Upload.vue
Expand Up @@ -90,7 +90,7 @@

computed: {
...mapState(['state']),
...mapState('config', ['uploadPassRequired', 'uploadPass', 'requireBucketPassword', 'disableQrCode']),
...mapState('config', ['uploadPassRequired', 'uploadPass', 'requireBucketPassword', 'disableQrCode', 'fileCommentMaxLength']),
...mapState('upload', ['sid', 'files', 'password']),
...mapGetters(['error', 'disabled']),
...mapGetters('upload', ['percentUploaded', 'shareUrl', 'bucketSize', 'bytesUploaded']),
Expand All @@ -105,7 +105,15 @@
showUploadBtn() {
return this.files.length
&& !this.disabled
&& !this.isUploadBtnDisabled
&& (this.requireBucketPassword && this.password || !this.requireBucketPassword)
},
isUploadBtnDisabled(){
let error = false;
this.files.forEach(file => {
if(file.comment.length > this.fileCommentMaxLength) error = true;
})
return error;
}
},

Expand Down
1 change: 1 addition & 0 deletions app/src/Upload/Files.vue
Expand Up @@ -23,6 +23,7 @@
small ({{ file.humanSize }})
p
input.form-control.input-sm(type="text", :placeholder="$root.lang.comment", v-model="file.comment", :disabled="disabled")
div.text-end(v-show="file.comment.length > $store.state.config.fileCommentMaxLength") {{ file.comment.length }} / {{ $store.state.config.fileCommentMaxLength }}
.alert.alert-danger(v-if="file.error")
icon.fa-fw(name="exclamation-triangle")
| {{ file.error }}
Expand Down
3 changes: 2 additions & 1 deletion config.dev.js
Expand Up @@ -18,7 +18,8 @@ module.exports = {
"uploadAppPath": '/',
// "maxFileSize": Math.pow(2, 20) * 15,
// "maxBucketSize": Math.pow(2, 20) * 20,
"mailFrom": "PsiTransfer <psitransfer@psi.cx>"
"mailFrom": "PsiTransfer <psitransfer@psi.cx>",
// "sslKeyFile": './tmp/cert.key',
// "sslCertFile": './tmp/cert.pem',
"fileCommentMaxLength": 200,
};
7 changes: 4 additions & 3 deletions config.js
Expand Up @@ -62,10 +62,11 @@ const config = {
"plugins": ['file-downloaded-webhook', 'file-uploaded-webhook'],
// Disable the QR code button for download url sharing, set to true to disable
"disableQrCode": false,
"fileCommentMaxLength": 200,
};

// Load NODE_ENV specific config
const envConfFile = path.resolve(__dirname, `config.${ process.env.NODE_ENV }.js`);
const envConfFile = path.resolve(__dirname, `config.${process.env.NODE_ENV}.js`);
if (process.env.NODE_ENV && fsp.existsSync(envConfFile)) {
Object.assign(config, require(envConfFile));
}
Expand Down Expand Up @@ -94,14 +95,14 @@ config.uploadAppPath = config.baseUrl.substr(0, config.baseUrl.length - 1) + con

// Load language files
config.languages = {
[config.defaultLanguage]: require(`./lang/${ config.defaultLanguage }`) // default language
[config.defaultLanguage]: require(`./lang/${config.defaultLanguage}`) // default language
};
fs.readdirSync(path.resolve(__dirname, 'lang')).forEach(lang => {
lang = lang.replace('.js', '');
if (lang === config.defaultLanguage) return;
config.languages[lang] = {
...config.languages[config.defaultLanguage],
...require(`./lang/${ lang }`)
...require(`./lang/${lang}`)
};
});

Expand Down
61 changes: 31 additions & 30 deletions lib/endpoints.js
Expand Up @@ -43,16 +43,16 @@ if (config.accessLog) {

if (config.forceHttps) {
app.enable('trust proxy');
app.use(function(req, res, next) {
app.use(function (req, res, next) {
if (req.secure) return next();
const target = config.forceHttps === 'true' ? 'https://' + req.headers.host : config.forceHttps;
res.redirect(target + req.url);
});
}

// Static files
app.use(`${ config.baseUrl }app`, express.static(path.join(__dirname, '../public/app')));
app.use(`${ config.baseUrl }assets`, express.static(path.join(__dirname, '../public/assets')));
app.use(`${config.baseUrl}app`, express.static(path.join(__dirname, '../public/app')));
app.use(`${config.baseUrl}assets`, express.static(path.join(__dirname, '../public/assets')));

// Resolve language
app.use((req, res, next) => {
Expand All @@ -62,7 +62,7 @@ app.use((req, res, next) => {
});

// robots.txt
app.get(`${ config.baseUrl }robots.txt`, (req, res) => {
app.get(`${config.baseUrl}robots.txt`, (req, res) => {
res.sendFile(path.join(__dirname, '../public/robots.txt'));
});

Expand All @@ -82,13 +82,13 @@ app.get(config.uploadAppPath, (req, res) => {
});

// Return translations
app.get(`${ config.baseUrl }lang.json`, (req, res) => {
app.get(`${config.baseUrl}lang.json`, (req, res) => {
eventBus.emit('getLang', req.translations);
res.json(req.translations);
});

// Config
app.get(`${ config.baseUrl }config.json`, (req, res) => {
app.get(`${config.baseUrl}config.json`, (req, res) => {
// Upload password protection
if (config.uploadPass) {
const bfTimeout = 200;
Expand All @@ -110,19 +110,20 @@ app.get(`${ config.baseUrl }config.json`, (req, res) => {
maxFileSize: config.maxFileSize,
maxBucketSize: config.maxBucketSize,
disableQrCode: config.disableQrCode,
fileCommentMaxLength: config.fileCommentMaxLength,
};

eventBus.emit('getFrontendConfig', frontendConfig);

res.json(frontendConfig);
});

app.get(`${ config.baseUrl }admin`, (req, res, next) => {
app.get(`${config.baseUrl}admin`, (req, res, next) => {
if (!config.adminPass) return next();
res.send(adminPage({ ...pugVars, lang: req.translations }));
});

app.get(`${ config.baseUrl }admin/data.json`, (req, res, next) => {
app.get(`${config.baseUrl}admin/data.json`, (req, res, next) => {
if (!config.adminPass) return next();

const bfTimeout = 500;
Expand Down Expand Up @@ -154,21 +155,21 @@ app.get(`${ config.baseUrl }admin/data.json`, (req, res, next) => {


// List files / Download App
app.get(`${ config.baseUrl }:sid`, (req, res, next) => {
app.get(`${config.baseUrl}:sid`, (req, res, next) => {
if (req.url.endsWith('.json')) {
const sid = req.params.sid.substr(0, req.params.sid.length - 5);
if (!db.get(sid)) return res.status(404).end();

const downloadPassword = req.get('x-download-pass');
const items = db.get(sid).map(item => ({
...item,
url: `${ config.baseUrl }files/${ sid }++${ item.key }`
url: `${config.baseUrl}files/${sid}++${item.key}`
}));

res.header('Cache-control', 'private, max-age=0, no-cache, no-store, must-revalidate');

// Currently, every item in a bucket must have the same password
if(items.some(item => item.metadata.password && item.metadata.password !== downloadPassword)) {
if (items.some(item => item.metadata.password && item.metadata.password !== downloadPassword)) {
setTimeout(() => res.status(401).send('Unauthorized'), 500);
return;
}
Expand All @@ -187,7 +188,7 @@ app.get(`${ config.baseUrl }:sid`, (req, res, next) => {


// Download files
app.get(`${ config.baseUrl }files/:fid`, async (req, res, next) => {
app.get(`${config.baseUrl}files/:fid`, async (req, res, next) => {
// let tusboy handle HEAD requests with Tus Header
if (req.method === 'HEAD' && req.get('Tus-Resumable')) return next();

Expand All @@ -199,11 +200,11 @@ app.get(`${ config.baseUrl }files/:fid`, async (req, res, next) => {
const bucket = db.get(sid);

if (!bucket) return res.status(404).send(errorPage({
...pugVars,
error: 'Download bucket not found.',
lang: req.translations,
uploadAppPath: config.uploadAppPath || config.baseUrl,
}));
...pugVars,
error: 'Download bucket not found.',
lang: req.translations,
uploadAppPath: config.uploadAppPath || config.baseUrl,
}));

if (req.params.fid !== sid + '++' + MD5(bucket.map(f => f.key).join()).toString() + '.' + format) {
res.status(404).send(errorPage({
Expand All @@ -214,10 +215,10 @@ app.get(`${ config.baseUrl }files/:fid`, async (req, res, next) => {
}));
return;
}
debug(`Download Bucket ${ sid }`);
debug(`Download Bucket ${sid}`);

const filename = `${ sid }.${ format }`;
res.header('Content-Disposition', `attachment; filename="${ filename }"`);
const filename = `${sid}.${format}`;
res.header('Content-Disposition', `attachment; filename="${filename}"`);

try {
res.on('finish', async () => {
Expand All @@ -242,10 +243,10 @@ app.get(`${ config.baseUrl }files/:fid`, async (req, res, next) => {
console.error(e);
}

if(format === 'zip') {
if (format === 'zip') {
res.header('ContentType', 'application/zip');
const archive = archiver('zip');
archive.on('error', function(err) {
archive.on('error', function (err) {
console.error(err);
});
archive.pipe(res);
Expand All @@ -270,7 +271,7 @@ app.get(`${ config.baseUrl }files/:fid`, async (req, res, next) => {
const entry = pack.entry({ name: info.metadata.name, size: info.size });
readStream.on('error', reject);
entry.on('error', reject);
entry.on('finish',resolve);
entry.on('finish', resolve);
readStream.pipe(entry);
});
}
Expand All @@ -281,7 +282,7 @@ app.get(`${ config.baseUrl }files/:fid`, async (req, res, next) => {
}

// Download single file
debug(`Download ${ req.params.fid }`);
debug(`Download ${req.params.fid}`);
try {
const info = await store.info(req.params.fid); // throws on 404
res.download(store.getFilename(req.params.fid), info.metadata.name);
Expand Down Expand Up @@ -314,8 +315,8 @@ app.get(`${ config.baseUrl }files/:fid`, async (req, res, next) => {


// Upload file
app.use(`${ config.uploadAppPath }files`,
function(req, res, next) {
app.use(`${config.uploadAppPath}files`,
function (req, res, next) {
// Upload password protection
if (config.uploadPass) {
const bfTimeout = 500;
Expand All @@ -341,7 +342,7 @@ app.use(`${ config.uploadAppPath }files`,
assert(meta.sid, 'tus meta prop missing: sid');
assert(meta.retention, 'tus meta prop missing: retention');
assert(Object.keys(config.retentions).indexOf(meta.retention) >= 0,
`invalid tus meta prop retention. Value ${ meta.retention } not in [${ Object.keys(config.retentions).join(',') }]`);
`invalid tus meta prop retention. Value ${meta.retention} not in [${Object.keys(config.retentions).join(',')}]`);

const uploadLength = req.get('Upload-Length');
assert(uploadLength, 'missing Upload-Length header');
Expand All @@ -354,11 +355,11 @@ app.use(`${ config.uploadAppPath }files`,
if (config.maxFileSize && config.maxFileSize < +uploadLength) {
return res
.status(413)
.json({ message: `File exceeds maximum upload size ${ config.maxFileSize }.` });
.json({ message: `File exceeds maximum upload size ${config.maxFileSize}.` });
} else if (config.maxBucketSize && db.bucketSize(meta.sid) + +uploadLength > config.maxBucketSize) {
return res
.status(413)
.json({ message: `Bucket exceeds maximum upload size ${ config.maxBucketSize }.` });
.json({ message: `Bucket exceeds maximum upload size ${config.maxBucketSize}.` });
}

// store changed metadata for tusboy
Expand Down Expand Up @@ -386,7 +387,7 @@ app.use(`${ config.uploadAppPath }files`,
maxUploadLength: config.maxFileSize || Infinity,
afterComplete: (req, upload, fid) => {
db.add(upload.metadata.sid, upload.metadata.key, upload);
debug(`Completed upload ${ fid }, size=${ upload.size } name=${ upload.metadata.name }`);
debug(`Completed upload ${fid}, size=${upload.size} name=${upload.metadata.name}`);

eventBus.emit('fileUploaded', upload);
},
Expand Down
3 changes: 3 additions & 0 deletions public/assets/styles.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.