mirror of
https://github.com/BobbyWibowo/lolisafe.git
synced 2025-02-21 12:49:07 +00:00
Various updates
* Switched ESLint + Aqua to Standard. I'm a big fan of Standard. Updated yarn.lock file too. * Lots of refactors to follow the rules of Standard. * Fixed issue with uploading as a not logged in user.
This commit is contained in:
parent
da40ea71b1
commit
bcdfcd7064
134
config.sample.js
134
config.sample.js
@ -1,84 +1,84 @@
|
||||
module.exports = {
|
||||
|
||||
/*
|
||||
If set to true the user will need to specify the auto-generated token
|
||||
on each API call, meaning random strangers wont be able to use the service
|
||||
unless they have the token loli-safe provides you with.
|
||||
If it's set to false, then upload will be public for anyone to use.
|
||||
*/
|
||||
private: true,
|
||||
/*
|
||||
If set to true the user will need to specify the auto-generated token
|
||||
on each API call, meaning random strangers wont be able to use the service
|
||||
unless they have the token loli-safe provides you with.
|
||||
If it's set to false, then upload will be public for anyone to use.
|
||||
*/
|
||||
private: true,
|
||||
|
||||
// If true, users will be able to create accounts and access their uploaded files
|
||||
enableUserAccounts: true,
|
||||
// If true, users will be able to create accounts and access their uploaded files
|
||||
enableUserAccounts: true,
|
||||
|
||||
/*
|
||||
Here you can decide if you want lolisafe to serve the files or if you prefer doing so via nginx.
|
||||
The main difference between the two is the ease of use and the chance of analytics in the future.
|
||||
If you set it to `true`, the uploaded files will be located after the host like:
|
||||
https://lolisafe.moe/yourFile.jpg
|
||||
/*
|
||||
Here you can decide if you want lolisafe to serve the files or if you prefer doing so via nginx.
|
||||
The main difference between the two is the ease of use and the chance of analytics in the future.
|
||||
If you set it to `true`, the uploaded files will be located after the host like:
|
||||
https://lolisafe.moe/yourFile.jpg
|
||||
|
||||
If you set it to `false`, you need to set nginx to directly serve whatever folder it is you are serving your
|
||||
downloads in. This also gives you the ability to serve them, for example, like this:
|
||||
https://files.lolisafe.moe/yourFile.jpg
|
||||
If you set it to `false`, you need to set nginx to directly serve whatever folder it is you are serving your
|
||||
downloads in. This also gives you the ability to serve them, for example, like this:
|
||||
https://files.lolisafe.moe/yourFile.jpg
|
||||
|
||||
Both cases require you to type the domain where the files will be served on the `domain` key below.
|
||||
Which one you use is ultimately up to you.
|
||||
*/
|
||||
serveFilesWithNode: false,
|
||||
domain: 'https://lolisafe.moe',
|
||||
Both cases require you to type the domain where the files will be served on the `domain` key below.
|
||||
Which one you use is ultimately up to you.
|
||||
*/
|
||||
serveFilesWithNode: false,
|
||||
domain: 'https://lolisafe.moe',
|
||||
|
||||
// Port on which to run the server
|
||||
port: 9999,
|
||||
// Port on which to run the server
|
||||
port: 9999,
|
||||
|
||||
// Pages to process for the frontend
|
||||
pages: ['home', 'auth', 'dashboard', 'faq'],
|
||||
// Pages to process for the frontend
|
||||
pages: ['home', 'auth', 'dashboard', 'faq'],
|
||||
|
||||
// Add file extensions here which should be blocked
|
||||
blockedExtensions: [
|
||||
'.exe',
|
||||
'.bat',
|
||||
'.cmd',
|
||||
'.msi',
|
||||
'.sh'
|
||||
],
|
||||
// Add file extensions here which should be blocked
|
||||
blockedExtensions: [
|
||||
'.exe',
|
||||
'.bat',
|
||||
'.cmd',
|
||||
'.msi',
|
||||
'.sh'
|
||||
],
|
||||
|
||||
// Uploads config
|
||||
uploads: {
|
||||
// Uploads config
|
||||
uploads: {
|
||||
|
||||
// Folder where images should be stored
|
||||
folder: 'uploads',
|
||||
// Folder where images should be stored
|
||||
folder: 'uploads',
|
||||
|
||||
/*
|
||||
Max file size allowed. Needs to be in MB
|
||||
Note: When maxSize is greater than 1 MiB, you must set the client_max_body_size to the same as maxSize.
|
||||
*/
|
||||
maxSize: '512MB',
|
||||
/*
|
||||
Max file size allowed. Needs to be in MB
|
||||
Note: When maxSize is greater than 1 MiB, you must set the client_max_body_size to the same as maxSize.
|
||||
*/
|
||||
maxSize: '512MB',
|
||||
|
||||
// The length of the random generated name for the uploaded files
|
||||
fileLength: 32,
|
||||
// The length of the random generated name for the uploaded files
|
||||
fileLength: 32,
|
||||
|
||||
/*
|
||||
NOTE: Thumbnails are only for the admin panel and they require you
|
||||
to install a separate binary called graphicsmagick (http://www.graphicsmagick.org)
|
||||
for images and ffmpeg (https://ffmpeg.org/) for video files
|
||||
*/
|
||||
generateThumbnails: false,
|
||||
/*
|
||||
NOTE: Thumbnails are only for the admin panel and they require you
|
||||
to install a separate binary called graphicsmagick (http://www.graphicsmagick.org)
|
||||
for images and ffmpeg (https://ffmpeg.org/) for video files
|
||||
*/
|
||||
generateThumbnails: false,
|
||||
|
||||
/*
|
||||
Allows users to download a .zip file of all files in an album.
|
||||
The file is generated when the user clicks the download button in the view
|
||||
and is re-used if the album has not changed between download requests
|
||||
*/
|
||||
generateZips: true
|
||||
},
|
||||
/*
|
||||
Allows users to download a .zip file of all files in an album.
|
||||
The file is generated when the user clicks the download button in the view
|
||||
and is re-used if the album has not changed between download requests
|
||||
*/
|
||||
generateZips: true
|
||||
},
|
||||
|
||||
// Folder where to store logs
|
||||
logsFolder: 'logs',
|
||||
// Folder where to store logs
|
||||
logsFolder: 'logs',
|
||||
|
||||
// The following values shouldn't be touched
|
||||
database: {
|
||||
client: 'sqlite3',
|
||||
connection: { filename: './database/db' },
|
||||
useNullAsDefault: true
|
||||
}
|
||||
};
|
||||
// The following values shouldn't be touched
|
||||
database: {
|
||||
client: 'sqlite3',
|
||||
connection: { filename: './database/db' },
|
||||
useNullAsDefault: true
|
||||
}
|
||||
}
|
||||
|
@ -1,179 +1,178 @@
|
||||
const config = require('../config.js');
|
||||
const db = require('knex')(config.database);
|
||||
const randomstring = require('randomstring');
|
||||
const utils = require('./utilsController.js');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const Zip = require('jszip');
|
||||
const albumsController = {};
|
||||
const config = require('../config.js')
|
||||
const db = require('knex')(config.database)
|
||||
const randomstring = require('randomstring')
|
||||
const utils = require('./utilsController.js')
|
||||
const path = require('path')
|
||||
const fs = require('fs')
|
||||
const Zip = require('jszip')
|
||||
const albumsController = {}
|
||||
|
||||
albumsController.list = async (req, res, next) => {
|
||||
const user = await utils.authorize(req, res);
|
||||
const user = await utils.authorize(req, res)
|
||||
|
||||
const fields = ['id', 'name'];
|
||||
if (req.params.sidebar === undefined) {
|
||||
fields.push('timestamp');
|
||||
fields.push('identifier');
|
||||
}
|
||||
const fields = ['id', 'name']
|
||||
if (req.params.sidebar === undefined) {
|
||||
fields.push('timestamp')
|
||||
fields.push('identifier')
|
||||
}
|
||||
|
||||
const albums = await db.table('albums').select(fields).where({ enabled: 1, userid: user.id });
|
||||
if (req.params.sidebar !== undefined) {
|
||||
return res.json({ success: true, albums });
|
||||
}
|
||||
const albums = await db.table('albums').select(fields).where({ enabled: 1, userid: user.id })
|
||||
if (req.params.sidebar !== undefined) {
|
||||
return res.json({ success: true, albums })
|
||||
}
|
||||
|
||||
let ids = [];
|
||||
for (let album of albums) {
|
||||
album.date = new Date(album.timestamp * 1000)
|
||||
album.date = utils.getPrettyDate(album.date)
|
||||
let ids = []
|
||||
for (let album of albums) {
|
||||
album.date = new Date(album.timestamp * 1000)
|
||||
album.date = utils.getPrettyDate(album.date)
|
||||
|
||||
album.identifier = `${config.domain}/a/${album.identifier}`;
|
||||
ids.push(album.id);
|
||||
}
|
||||
album.identifier = `${config.domain}/a/${album.identifier}`
|
||||
ids.push(album.id)
|
||||
}
|
||||
|
||||
const files = await db.table('files').whereIn('albumid', ids).select('albumid');
|
||||
const albumsCount = {};
|
||||
const files = await db.table('files').whereIn('albumid', ids).select('albumid')
|
||||
const albumsCount = {}
|
||||
|
||||
for (let id of ids) albumsCount[id] = 0;
|
||||
for (let file of files) albumsCount[file.albumid] += 1;
|
||||
for (let album of albums) album.files = albumsCount[album.id];
|
||||
for (let id of ids) albumsCount[id] = 0
|
||||
for (let file of files) albumsCount[file.albumid] += 1
|
||||
for (let album of albums) album.files = albumsCount[album.id]
|
||||
|
||||
return res.json({ success: true, albums });
|
||||
};
|
||||
return res.json({ success: true, albums })
|
||||
}
|
||||
|
||||
albumsController.create = async (req, res, next) => {
|
||||
const user = await utils.authorize(req, res);
|
||||
const user = await utils.authorize(req, res)
|
||||
|
||||
const name = req.body.name;
|
||||
if (name === undefined || name === '') {
|
||||
return res.json({ success: false, description: 'No album name specified' });
|
||||
}
|
||||
const name = req.body.name
|
||||
if (name === undefined || name === '') {
|
||||
return res.json({ success: false, description: 'No album name specified' })
|
||||
}
|
||||
|
||||
const album = await db.table('albums').where({
|
||||
name: name,
|
||||
enabled: 1,
|
||||
userid: user.id
|
||||
}).first();
|
||||
const album = await db.table('albums').where({
|
||||
name: name,
|
||||
enabled: 1,
|
||||
userid: user.id
|
||||
}).first()
|
||||
|
||||
if (album) {
|
||||
return res.json({ success: false, description: 'There\'s already an album with that name' })
|
||||
}
|
||||
if (album) {
|
||||
return res.json({ success: false, description: 'There\'s already an album with that name' })
|
||||
}
|
||||
|
||||
await db.table('albums').insert({
|
||||
name: name,
|
||||
enabled: 1,
|
||||
userid: user.id,
|
||||
identifier: randomstring.generate(8),
|
||||
timestamp: Math.floor(Date.now() / 1000)
|
||||
});
|
||||
await db.table('albums').insert({
|
||||
name: name,
|
||||
enabled: 1,
|
||||
userid: user.id,
|
||||
identifier: randomstring.generate(8),
|
||||
timestamp: Math.floor(Date.now() / 1000)
|
||||
})
|
||||
|
||||
return res.json({ success: true });
|
||||
};
|
||||
return res.json({ success: true })
|
||||
}
|
||||
|
||||
albumsController.delete = async (req, res, next) => {
|
||||
const user = await utils.authorize(req, res);
|
||||
const user = await utils.authorize(req, res)
|
||||
|
||||
const id = req.body.id;
|
||||
if (id === undefined || id === '') {
|
||||
return res.json({ success: false, description: 'No album specified' });
|
||||
}
|
||||
const id = req.body.id
|
||||
if (id === undefined || id === '') {
|
||||
return res.json({ success: false, description: 'No album specified' })
|
||||
}
|
||||
|
||||
await db.table('albums').where({ id: id, userid: user.id }).update({ enabled: 0 });
|
||||
return res.json({ success: true });
|
||||
};
|
||||
await db.table('albums').where({ id: id, userid: user.id }).update({ enabled: 0 })
|
||||
return res.json({ success: true })
|
||||
}
|
||||
|
||||
albumsController.rename = async (req, res, next) => {
|
||||
const user = await utils.authorize(req, res);
|
||||
const user = await utils.authorize(req, res)
|
||||
|
||||
const id = req.body.id;
|
||||
if (id === undefined || id === '') {
|
||||
return res.json({ success: false, description: 'No album specified' });
|
||||
}
|
||||
const id = req.body.id
|
||||
if (id === undefined || id === '') {
|
||||
return res.json({ success: false, description: 'No album specified' })
|
||||
}
|
||||
|
||||
const name = req.body.name;
|
||||
if (name === undefined || name === '') {
|
||||
return res.json({ success: false, description: 'No name specified' });
|
||||
}
|
||||
const name = req.body.name
|
||||
if (name === undefined || name === '') {
|
||||
return res.json({ success: false, description: 'No name specified' })
|
||||
}
|
||||
|
||||
const album = await db.table('albums').where({ name: name, userid: user.id }).first();
|
||||
if (album) {
|
||||
return res.json({ success: false, description: 'Name already in use' })
|
||||
}
|
||||
const album = await db.table('albums').where({ name: name, userid: user.id }).first()
|
||||
if (album) {
|
||||
return res.json({ success: false, description: 'Name already in use' })
|
||||
}
|
||||
|
||||
await db.table('albums').where({ id: id, userid: user.id }).update({ name: name })
|
||||
return res.json({ success: true });
|
||||
};
|
||||
await db.table('albums').where({ id: id, userid: user.id }).update({ name: name })
|
||||
return res.json({ success: true })
|
||||
}
|
||||
|
||||
albumsController.get = async (req, res, next) => {
|
||||
const identifier = req.params.identifier;
|
||||
if (identifier === undefined) return res.status(401).json({ success: false, description: 'No identifier provided' });
|
||||
const identifier = req.params.identifier
|
||||
if (identifier === undefined) return res.status(401).json({ success: false, description: 'No identifier provided' })
|
||||
|
||||
const album = await db.table('albums').where({ identifier, enabled: 1 }).first();
|
||||
if (!album) return res.json({ success: false, description: 'Album not found' });
|
||||
const album = await db.table('albums').where({ identifier, enabled: 1 }).first()
|
||||
if (!album) return res.json({ success: false, description: 'Album not found' })
|
||||
|
||||
const title = album.name;
|
||||
const files = await db.table('files').select('name').where('albumid', album.id).orderBy('id', 'DESC');
|
||||
const title = album.name
|
||||
const files = await db.table('files').select('name').where('albumid', album.id).orderBy('id', 'DESC')
|
||||
|
||||
for (let file of files) {
|
||||
file.file = `${config.domain}/${file.name}`;
|
||||
for (let file of files) {
|
||||
file.file = `${config.domain}/${file.name}`
|
||||
|
||||
const ext = path.extname(file.name).toLowerCase();
|
||||
if (utils.imageExtensions.includes(ext) || utils.videoExtensions.includes(ext)) {
|
||||
file.thumb = `${config.domain}/thumbs/${file.name.slice(0, -ext.length)}.png`;
|
||||
}
|
||||
}
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
title: title,
|
||||
count: files.length,
|
||||
files
|
||||
});
|
||||
};
|
||||
const ext = path.extname(file.name).toLowerCase()
|
||||
if (utils.imageExtensions.includes(ext) || utils.videoExtensions.includes(ext)) {
|
||||
file.thumb = `${config.domain}/thumbs/${file.name.slice(0, -ext.length)}.png`
|
||||
}
|
||||
}
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
title: title,
|
||||
count: files.length,
|
||||
files
|
||||
})
|
||||
}
|
||||
|
||||
albumsController.generateZip = async (req, res, next) => {
|
||||
const identifier = req.params.identifier;
|
||||
if (identifier === undefined) return res.status(401).json({ success: false, description: 'No identifier provided' });
|
||||
if (!config.uploads.generateZips) return res.status(401).json({ success: false, description: 'Zip generation disabled' });
|
||||
const identifier = req.params.identifier
|
||||
if (identifier === undefined) return res.status(401).json({ success: false, description: 'No identifier provided' })
|
||||
if (!config.uploads.generateZips) return res.status(401).json({ success: false, description: 'Zip generation disabled' })
|
||||
|
||||
const album = await db.table('albums').where({ identifier, enabled: 1 }).first();
|
||||
if (!album) return res.json({ success: false, description: 'Album not found' });
|
||||
const album = await db.table('albums').where({ identifier, enabled: 1 }).first()
|
||||
if (!album) return res.json({ success: false, description: 'Album not found' })
|
||||
|
||||
if (album.zipGeneratedAt > album.editedAt) {
|
||||
const filePath = path.join(config.uploads.folder, 'zips', `${identifier}.zip`);
|
||||
const fileName = `${album.name}.zip`;
|
||||
return res.download(filePath, fileName);
|
||||
} else {
|
||||
console.log(`Generating zip for album identifier: ${identifier}`);
|
||||
const files = await db.table('files').select('name').where('albumid', album.id);
|
||||
if (files.length === 0) return res.json({ success: false, description: 'There are no files in the album' });
|
||||
if (album.zipGeneratedAt > album.editedAt) {
|
||||
const filePath = path.join(config.uploads.folder, 'zips', `${identifier}.zip`)
|
||||
const fileName = `${album.name}.zip`
|
||||
return res.download(filePath, fileName)
|
||||
} else {
|
||||
console.log(`Generating zip for album identifier: ${identifier}`)
|
||||
const files = await db.table('files').select('name').where('albumid', album.id)
|
||||
if (files.length === 0) return res.json({ success: false, description: 'There are no files in the album' })
|
||||
|
||||
const zipPath = path.join(__dirname, '..', config.uploads.folder, 'zips', `${album.identifier}.zip`);
|
||||
let archive = new Zip();
|
||||
const zipPath = path.join(__dirname, '..', config.uploads.folder, 'zips', `${album.identifier}.zip`)
|
||||
let archive = new Zip()
|
||||
|
||||
for (let file of files) {
|
||||
try {
|
||||
const exists = fs.statSync(path.join(__dirname, '..', config.uploads.folder, file.name));
|
||||
archive.file(file.name, fs.readFileSync(path.join(__dirname, '..', config.uploads.folder, file.name)));
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
for (let file of files) {
|
||||
try {
|
||||
// const exists = fs.statSync(path.join(__dirname, '..', config.uploads.folder, file.name))
|
||||
archive.file(file.name, fs.readFileSync(path.join(__dirname, '..', config.uploads.folder, file.name)))
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
}
|
||||
|
||||
archive
|
||||
.generateNodeStream({ type: 'nodebuffer', streamFiles: true })
|
||||
.pipe(fs.createWriteStream(zipPath))
|
||||
.on('finish', async () => {
|
||||
console.log(`Generated zip for album identifier: ${identifier}`);
|
||||
await db.table('albums')
|
||||
.where('id', album.id)
|
||||
.update({ zipGeneratedAt: Math.floor(Date.now() / 1000) });
|
||||
archive
|
||||
.generateNodeStream({ type: 'nodebuffer', streamFiles: true })
|
||||
.pipe(fs.createWriteStream(zipPath))
|
||||
.on('finish', async () => {
|
||||
console.log(`Generated zip for album identifier: ${identifier}`)
|
||||
await db.table('albums')
|
||||
.where('id', album.id)
|
||||
.update({ zipGeneratedAt: Math.floor(Date.now() / 1000) })
|
||||
|
||||
const filePath = path.join(config.uploads.folder, 'zips', `${identifier}.zip`);
|
||||
const fileName = `${album.name}.zip`;
|
||||
return res.download(filePath, fileName);
|
||||
});
|
||||
}
|
||||
};
|
||||
const filePath = path.join(config.uploads.folder, 'zips', `${identifier}.zip`)
|
||||
const fileName = `${album.name}.zip`
|
||||
return res.download(filePath, fileName)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = albumsController;
|
||||
module.exports = albumsController
|
||||
|
@ -1,86 +1,86 @@
|
||||
const config = require('../config.js');
|
||||
const db = require('knex')(config.database);
|
||||
const bcrypt = require('bcrypt');
|
||||
const randomstring = require('randomstring');
|
||||
const utils = require('./utilsController.js');
|
||||
const config = require('../config.js')
|
||||
const db = require('knex')(config.database)
|
||||
const bcrypt = require('bcrypt')
|
||||
const randomstring = require('randomstring')
|
||||
const utils = require('./utilsController.js')
|
||||
|
||||
let authController = {};
|
||||
let authController = {}
|
||||
|
||||
authController.verify = async (req, res, next) => {
|
||||
const username = req.body.username;
|
||||
const password = req.body.password;
|
||||
const username = req.body.username
|
||||
const password = req.body.password
|
||||
|
||||
if (username === undefined) return res.json({ success: false, description: 'No username provided' });
|
||||
if (password === undefined) return res.json({ success: false, description: 'No password provided' });
|
||||
if (username === undefined) return res.json({ success: false, description: 'No username provided' })
|
||||
if (password === undefined) return res.json({ success: false, description: 'No password provided' })
|
||||
|
||||
const user = await db.table('users').where('username', username).first();
|
||||
if (!user) return res.json({ success: false, description: 'Username doesn\'t exist' });
|
||||
const user = await db.table('users').where('username', username).first()
|
||||
if (!user) return res.json({ success: false, description: 'Username doesn\'t exist' })
|
||||
|
||||
bcrypt.compare(password, user.password, (err, result) => {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
return res.json({ success: false, description: 'There was an error' });
|
||||
}
|
||||
if (result === false) return res.json({ success: false, description: 'Wrong password' });
|
||||
return res.json({ success: true, token: user.token });
|
||||
});
|
||||
};
|
||||
bcrypt.compare(password, user.password, (err, result) => {
|
||||
if (err) {
|
||||
console.log(err)
|
||||
return res.json({ success: false, description: 'There was an error' })
|
||||
}
|
||||
if (result === false) return res.json({ success: false, description: 'Wrong password' })
|
||||
return res.json({ success: true, token: user.token })
|
||||
})
|
||||
}
|
||||
|
||||
authController.register = async (req, res, next) => {
|
||||
if (config.enableUserAccounts === false) {
|
||||
return res.json({ success: false, description: 'Register is disabled at the moment' });
|
||||
}
|
||||
if (config.enableUserAccounts === false) {
|
||||
return res.json({ success: false, description: 'Register is disabled at the moment' })
|
||||
}
|
||||
|
||||
const username = req.body.username;
|
||||
const password = req.body.password;
|
||||
const username = req.body.username
|
||||
const password = req.body.password
|
||||
|
||||
if (username === undefined) return res.json({ success: false, description: 'No username provided' });
|
||||
if (password === undefined) return res.json({ success: false, description: 'No password provided' });
|
||||
if (username === undefined) return res.json({ success: false, description: 'No username provided' })
|
||||
if (password === undefined) return res.json({ success: false, description: 'No password provided' })
|
||||
|
||||
if (username.length < 4 || username.length > 32) {
|
||||
return res.json({ success: false, description: 'Username must have 4-32 characters' })
|
||||
}
|
||||
if (password.length < 6 || password.length > 64) {
|
||||
return res.json({ success: false, description: 'Password must have 6-64 characters' })
|
||||
}
|
||||
if (username.length < 4 || username.length > 32) {
|
||||
return res.json({ success: false, description: 'Username must have 4-32 characters' })
|
||||
}
|
||||
if (password.length < 6 || password.length > 64) {
|
||||
return res.json({ success: false, description: 'Password must have 6-64 characters' })
|
||||
}
|
||||
|
||||
const user = await db.table('users').where('username', username).first();
|
||||
if (user) return res.json({ success: false, description: 'Username already exists' });
|
||||
const user = await db.table('users').where('username', username).first()
|
||||
if (user) return res.json({ success: false, description: 'Username already exists' })
|
||||
|
||||
bcrypt.hash(password, 10, async (err, hash) => {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
return res.json({ success: false, description: 'Error generating password hash (╯°□°)╯︵ ┻━┻' });
|
||||
}
|
||||
const token = randomstring.generate(64);
|
||||
await db.table('users').insert({
|
||||
username: username,
|
||||
password: hash,
|
||||
token: token
|
||||
});
|
||||
return res.json({ success: true, token: token })
|
||||
});
|
||||
};
|
||||
bcrypt.hash(password, 10, async (err, hash) => {
|
||||
if (err) {
|
||||
console.log(err)
|
||||
return res.json({ success: false, description: 'Error generating password hash (╯°□°)╯︵ ┻━┻' })
|
||||
}
|
||||
const token = randomstring.generate(64)
|
||||
await db.table('users').insert({
|
||||
username: username,
|
||||
password: hash,
|
||||
token: token
|
||||
})
|
||||
return res.json({ success: true, token: token })
|
||||
})
|
||||
}
|
||||
|
||||
authController.changePassword = async (req, res, next) => {
|
||||
const user = await utils.authorize(req, res);
|
||||
const user = await utils.authorize(req, res)
|
||||
|
||||
let password = req.body.password;
|
||||
if (password === undefined) return res.json({ success: false, description: 'No password provided' });
|
||||
let password = req.body.password
|
||||
if (password === undefined) return res.json({ success: false, description: 'No password provided' })
|
||||
|
||||
if (password.length < 6 || password.length > 64) {
|
||||
return res.json({ success: false, description: 'Password must have 6-64 characters' });
|
||||
}
|
||||
if (password.length < 6 || password.length > 64) {
|
||||
return res.json({ success: false, description: 'Password must have 6-64 characters' })
|
||||
}
|
||||
|
||||
bcrypt.hash(password, 10, async (err, hash) => {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
return res.json({ success: false, description: 'Error generating password hash (╯°□°)╯︵ ┻━┻' });
|
||||
}
|
||||
bcrypt.hash(password, 10, async (err, hash) => {
|
||||
if (err) {
|
||||
console.log(err)
|
||||
return res.json({ success: false, description: 'Error generating password hash (╯°□°)╯︵ ┻━┻' })
|
||||
}
|
||||
|
||||
await db.table('users').where('id', user.id).update({ password: hash });
|
||||
return res.json({ success: true });
|
||||
});
|
||||
};
|
||||
await db.table('users').where('id', user.id).update({ password: hash })
|
||||
return res.json({ success: true })
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = authController;
|
||||
module.exports = authController
|
||||
|
@ -1,34 +1,34 @@
|
||||
const config = require('../config.js');
|
||||
const db = require('knex')(config.database);
|
||||
const randomstring = require('randomstring');
|
||||
const utils = require('./utilsController.js');
|
||||
const config = require('../config.js')
|
||||
const db = require('knex')(config.database)
|
||||
const randomstring = require('randomstring')
|
||||
const utils = require('./utilsController.js')
|
||||
|
||||
const tokenController = {};
|
||||
const tokenController = {}
|
||||
|
||||
tokenController.verify = async (req, res, next) => {
|
||||
const token = req.body.token;
|
||||
if (token === undefined) return res.status(401).json({ success: false, description: 'No token provided' });
|
||||
const token = req.body.token
|
||||
if (token === undefined) return res.status(401).json({ success: false, description: 'No token provided' })
|
||||
|
||||
const user = await db.table('users').where('token', token).first();
|
||||
if (!user) return res.status(401).json({ success: false, description: 'Invalid token' });
|
||||
return res.json({ success: true, username: user.username });
|
||||
};
|
||||
const user = await db.table('users').where('token', token).first()
|
||||
if (!user) return res.status(401).json({ success: false, description: 'Invalid token' })
|
||||
return res.json({ success: true, username: user.username })
|
||||
}
|
||||
|
||||
tokenController.list = async (req, res, next) => {
|
||||
const user = await utils.authorize(req, res);
|
||||
return res.json({ success: true, token: user.token });
|
||||
};
|
||||
const user = await utils.authorize(req, res)
|
||||
return res.json({ success: true, token: user.token })
|
||||
}
|
||||
|
||||
tokenController.change = async (req, res, next) => {
|
||||
const user = await utils.authorize(req, res);
|
||||
const newtoken = randomstring.generate(64);
|
||||
const user = await utils.authorize(req, res)
|
||||
const newtoken = randomstring.generate(64)
|
||||
|
||||
await db.table('users').where('token', user.token).update({
|
||||
token: newtoken,
|
||||
timestamp: Math.floor(Date.now() / 1000)
|
||||
});
|
||||
await db.table('users').where('token', user.token).update({
|
||||
token: newtoken,
|
||||
timestamp: Math.floor(Date.now() / 1000)
|
||||
})
|
||||
|
||||
res.json({ success: true, token: newtoken });
|
||||
};
|
||||
res.json({ success: true, token: newtoken })
|
||||
}
|
||||
|
||||
module.exports = tokenController;
|
||||
module.exports = tokenController
|
||||
|
@ -1,285 +1,285 @@
|
||||
const config = require('../config.js');
|
||||
const path = require('path');
|
||||
const multer = require('multer');
|
||||
const randomstring = require('randomstring');
|
||||
const db = require('knex')(config.database);
|
||||
const crypto = require('crypto');
|
||||
const fs = require('fs');
|
||||
const utils = require('./utilsController.js');
|
||||
const config = require('../config.js')
|
||||
const path = require('path')
|
||||
const multer = require('multer')
|
||||
const randomstring = require('randomstring')
|
||||
const db = require('knex')(config.database)
|
||||
const crypto = require('crypto')
|
||||
const fs = require('fs')
|
||||
const utils = require('./utilsController.js')
|
||||
|
||||
const uploadsController = {};
|
||||
const uploadsController = {}
|
||||
|
||||
const storage = multer.diskStorage({
|
||||
destination: function(req, file, cb) {
|
||||
cb(null, path.join(__dirname, '..', config.uploads.folder));
|
||||
},
|
||||
filename: function(req, file, cb) {
|
||||
cb(null, randomstring.generate(config.uploads.fileLength) + path.extname(file.originalname));
|
||||
}
|
||||
});
|
||||
destination: function (req, file, cb) {
|
||||
cb(null, path.join(__dirname, '..', config.uploads.folder))
|
||||
},
|
||||
filename: function (req, file, cb) {
|
||||
cb(null, randomstring.generate(config.uploads.fileLength) + path.extname(file.originalname))
|
||||
}
|
||||
})
|
||||
|
||||
const upload = multer({
|
||||
storage: storage,
|
||||
limits: { fileSize: config.uploads.maxSize },
|
||||
fileFilter: function(req, file, cb) {
|
||||
if (config.blockedExtensions !== undefined) {
|
||||
if (config.blockedExtensions.some(extension => path.extname(file.originalname).toLowerCase() === extension)) {
|
||||
return cb('This file extension is not allowed');
|
||||
}
|
||||
return cb(null, true);
|
||||
}
|
||||
return cb(null, true);
|
||||
}
|
||||
}).array('files[]');
|
||||
storage: storage,
|
||||
limits: { fileSize: config.uploads.maxSize },
|
||||
fileFilter: function (req, file, cb) {
|
||||
if (config.blockedExtensions !== undefined) {
|
||||
if (config.blockedExtensions.some(extension => path.extname(file.originalname).toLowerCase() === extension)) {
|
||||
return cb('This file extension is not allowed') // eslint-disable-line standard/no-callback-literal
|
||||
}
|
||||
return cb(null, true)
|
||||
}
|
||||
return cb(null, true)
|
||||
}
|
||||
}).array('files[]')
|
||||
|
||||
uploadsController.upload = async (req, res, next) => {
|
||||
if (config.private === true) {
|
||||
await utils.authorize(req, res);
|
||||
}
|
||||
if (config.private === true) {
|
||||
await utils.authorize(req, res)
|
||||
}
|
||||
|
||||
const token = req.headers.token || '';
|
||||
const user = await db.table('users').where('token', token).first();
|
||||
const albumid = req.headers.albumid || req.params.albumid;
|
||||
const token = req.headers.token || ''
|
||||
const user = await db.table('users').where('token', token).first()
|
||||
const albumid = req.headers.albumid || req.params.albumid
|
||||
|
||||
if (albumid && user) {
|
||||
const album = await db.table('albums').where({ id: albumid, userid: user.id }).first();
|
||||
if (!album) {
|
||||
return res.json({
|
||||
success: false,
|
||||
description: 'Album doesn\'t exist or it doesn\'t belong to the user'
|
||||
});
|
||||
}
|
||||
return uploadsController.actuallyUpload(req, res, user, albumid);
|
||||
}
|
||||
return uploadsController.actuallyUpload(req, res, user, albumid);
|
||||
};
|
||||
if (albumid && user) {
|
||||
const album = await db.table('albums').where({ id: albumid, userid: user.id }).first()
|
||||
if (!album) {
|
||||
return res.json({
|
||||
success: false,
|
||||
description: 'Album doesn\'t exist or it doesn\'t belong to the user'
|
||||
})
|
||||
}
|
||||
return uploadsController.actuallyUpload(req, res, user, albumid)
|
||||
}
|
||||
return uploadsController.actuallyUpload(req, res, user, albumid)
|
||||
}
|
||||
|
||||
uploadsController.actuallyUpload = async (req, res, userid, album) => {
|
||||
upload(req, res, async err => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
return res.json({ success: false, description: err });
|
||||
}
|
||||
upload(req, res, async err => {
|
||||
if (err) {
|
||||
console.error(err)
|
||||
return res.json({ success: false, description: err })
|
||||
}
|
||||
|
||||
if (req.files.length === 0) return res.json({ success: false, description: 'no-files' });
|
||||
if (req.files.length === 0) return res.json({ success: false, description: 'no-files' })
|
||||
|
||||
const files = [];
|
||||
const existingFiles = [];
|
||||
let iteration = 1;
|
||||
const files = []
|
||||
const existingFiles = []
|
||||
let iteration = 1
|
||||
|
||||
req.files.forEach(async file => {
|
||||
// Check if the file exists by checking hash and size
|
||||
let hash = crypto.createHash('md5');
|
||||
let stream = fs.createReadStream(path.join(__dirname, '..', config.uploads.folder, file.filename));
|
||||
req.files.forEach(async file => {
|
||||
// Check if the file exists by checking hash and size
|
||||
let hash = crypto.createHash('md5')
|
||||
let stream = fs.createReadStream(path.join(__dirname, '..', config.uploads.folder, file.filename))
|
||||
|
||||
stream.on('data', data => {
|
||||
hash.update(data, 'utf8');
|
||||
});
|
||||
stream.on('data', data => {
|
||||
hash.update(data, 'utf8')
|
||||
})
|
||||
|
||||
stream.on('end', async () => {
|
||||
const fileHash = hash.digest('hex');
|
||||
const dbFile = await db.table('files')
|
||||
.where(function() {
|
||||
if (userid === undefined) this.whereNull('userid');
|
||||
else this.where('userid', userid.id);
|
||||
})
|
||||
.where({
|
||||
hash: fileHash,
|
||||
size: file.size
|
||||
})
|
||||
.first();
|
||||
stream.on('end', async () => {
|
||||
const fileHash = hash.digest('hex')
|
||||
const dbFile = await db.table('files')
|
||||
.where(function () {
|
||||
if (userid === undefined) this.whereNull('userid')
|
||||
else this.where('userid', userid.id)
|
||||
})
|
||||
.where({
|
||||
hash: fileHash,
|
||||
size: file.size
|
||||
})
|
||||
.first()
|
||||
|
||||
if (!dbFile) {
|
||||
files.push({
|
||||
name: file.filename,
|
||||
original: file.originalname,
|
||||
type: file.mimetype,
|
||||
size: file.size,
|
||||
hash: fileHash,
|
||||
ip: req.ip,
|
||||
albumid: album,
|
||||
userid: userid.id,
|
||||
timestamp: Math.floor(Date.now() / 1000)
|
||||
});
|
||||
} else {
|
||||
uploadsController.deleteFile(file.filename).then(() => {}).catch(err => console.error(err));
|
||||
existingFiles.push(dbFile);
|
||||
}
|
||||
if (!dbFile) {
|
||||
files.push({
|
||||
name: file.filename,
|
||||
original: file.originalname,
|
||||
type: file.mimetype,
|
||||
size: file.size,
|
||||
hash: fileHash,
|
||||
ip: req.ip,
|
||||
albumid: album,
|
||||
userid: userid ? userid.id : null,
|
||||
timestamp: Math.floor(Date.now() / 1000)
|
||||
})
|
||||
} else {
|
||||
uploadsController.deleteFile(file.filename).then(() => {}).catch(err => console.error(err))
|
||||
existingFiles.push(dbFile)
|
||||
}
|
||||
|
||||
if (iteration === req.files.length) {
|
||||
return uploadsController.processFilesForDisplay(req, res, files, existingFiles);
|
||||
}
|
||||
iteration++;
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
if (iteration === req.files.length) {
|
||||
return uploadsController.processFilesForDisplay(req, res, files, existingFiles)
|
||||
}
|
||||
iteration++
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
uploadsController.processFilesForDisplay = async (req, res, files, existingFiles) => {
|
||||
let basedomain = config.domain;
|
||||
if (files.length === 0) {
|
||||
return res.json({
|
||||
success: true,
|
||||
files: existingFiles.map(file => {
|
||||
return {
|
||||
name: file.name,
|
||||
size: file.size,
|
||||
url: `${basedomain}/${file.name}`
|
||||
};
|
||||
})
|
||||
});
|
||||
}
|
||||
let basedomain = config.domain
|
||||
if (files.length === 0) {
|
||||
return res.json({
|
||||
success: true,
|
||||
files: existingFiles.map(file => {
|
||||
return {
|
||||
name: file.name,
|
||||
size: file.size,
|
||||
url: `${basedomain}/${file.name}`
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
await db.table('files').insert(files);
|
||||
for (let efile of existingFiles) files.push(efile);
|
||||
await db.table('files').insert(files)
|
||||
for (let efile of existingFiles) files.push(efile)
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
files: files.map(file => {
|
||||
return {
|
||||
name: file.name,
|
||||
size: file.size,
|
||||
url: `${basedomain}/${file.name}`
|
||||
};
|
||||
})
|
||||
});
|
||||
res.json({
|
||||
success: true,
|
||||
files: files.map(file => {
|
||||
return {
|
||||
name: file.name,
|
||||
size: file.size,
|
||||
url: `${basedomain}/${file.name}`
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
for (let file of files) {
|
||||
let ext = path.extname(file.name).toLowerCase();
|
||||
if (utils.imageExtensions.includes(ext) || utils.videoExtensions.includes(ext)) {
|
||||
file.thumb = `${basedomain}/thumbs/${file.name.slice(0, -ext.length)}.png`;
|
||||
utils.generateThumbs(file);
|
||||
}
|
||||
for (let file of files) {
|
||||
let ext = path.extname(file.name).toLowerCase()
|
||||
if (utils.imageExtensions.includes(ext) || utils.videoExtensions.includes(ext)) {
|
||||
file.thumb = `${basedomain}/thumbs/${file.name.slice(0, -ext.length)}.png`
|
||||
utils.generateThumbs(file)
|
||||
}
|
||||
|
||||
if (file.albumid) {
|
||||
db.table('albums').where('id', file.albumid).update('editedAt', file.timestamp).then(() => {})
|
||||
.catch(error => { console.log(error); res.json({ success: false, description: 'Error updating album' }); });
|
||||
}
|
||||
}
|
||||
};
|
||||
if (file.albumid) {
|
||||
db.table('albums').where('id', file.albumid).update('editedAt', file.timestamp).then(() => {})
|
||||
.catch(error => { console.log(error); res.json({ success: false, description: 'Error updating album' }) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uploadsController.delete = async (req, res) => {
|
||||
const user = await utils.authorize(req, res);
|
||||
const id = req.body.id;
|
||||
if (id === undefined || id === '') {
|
||||
return res.json({ success: false, description: 'No file specified' });
|
||||
}
|
||||
const user = await utils.authorize(req, res)
|
||||
const id = req.body.id
|
||||
if (id === undefined || id === '') {
|
||||
return res.json({ success: false, description: 'No file specified' })
|
||||
}
|
||||
|
||||
const file = await db.table('files')
|
||||
.where('id', id)
|
||||
.where(function() {
|
||||
if (user.username !== 'root') {
|
||||
this.where('userid', user.id);
|
||||
}
|
||||
})
|
||||
.first();
|
||||
const file = await db.table('files')
|
||||
.where('id', id)
|
||||
.where(function () {
|
||||
if (user.username !== 'root') {
|
||||
this.where('userid', user.id)
|
||||
}
|
||||
})
|
||||
.first()
|
||||
|
||||
try {
|
||||
await uploadsController.deleteFile(file.name);
|
||||
await db.table('files').where('id', id).del();
|
||||
if (file.albumid) {
|
||||
await db.table('albums').where('id', file.albumid).update('editedAt', Math.floor(Date.now() / 1000));
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
try {
|
||||
await uploadsController.deleteFile(file.name)
|
||||
await db.table('files').where('id', id).del()
|
||||
if (file.albumid) {
|
||||
await db.table('albums').where('id', file.albumid).update('editedAt', Math.floor(Date.now() / 1000))
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
|
||||
return res.json({ success: true });
|
||||
};
|
||||
return res.json({ success: true })
|
||||
}
|
||||
|
||||
uploadsController.deleteFile = function(file) {
|
||||
const ext = path.extname(file).toLowerCase();
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.stat(path.join(__dirname, '..', config.uploads.folder, file), (err, stats) => {
|
||||
if (err) { return reject(err); }
|
||||
fs.unlink(path.join(__dirname, '..', config.uploads.folder, file), err => {
|
||||
if (err) { return reject(err); }
|
||||
if (!utils.imageExtensions.includes(ext) && !utils.videoExtensions.includes(ext)) {
|
||||
return resolve();
|
||||
}
|
||||
file = file.substr(0, file.lastIndexOf('.')) + '.png';
|
||||
fs.stat(path.join(__dirname, '..', config.uploads.folder, 'thumbs/', file), (err, stats) => {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
return resolve();
|
||||
}
|
||||
fs.unlink(path.join(__dirname, '..', config.uploads.folder, 'thumbs/', file), err => {
|
||||
if (err) { return reject(err); }
|
||||
return resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
uploadsController.deleteFile = function (file) {
|
||||
const ext = path.extname(file).toLowerCase()
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.stat(path.join(__dirname, '..', config.uploads.folder, file), (err, stats) => {
|
||||
if (err) { return reject(err) }
|
||||
fs.unlink(path.join(__dirname, '..', config.uploads.folder, file), err => {
|
||||
if (err) { return reject(err) }
|
||||
if (!utils.imageExtensions.includes(ext) && !utils.videoExtensions.includes(ext)) {
|
||||
return resolve()
|
||||
}
|
||||
file = file.substr(0, file.lastIndexOf('.')) + '.png'
|
||||
fs.stat(path.join(__dirname, '..', config.uploads.folder, 'thumbs/', file), (err, stats) => {
|
||||
if (err) {
|
||||
console.log(err)
|
||||
return resolve()
|
||||
}
|
||||
fs.unlink(path.join(__dirname, '..', config.uploads.folder, 'thumbs/', file), err => {
|
||||
if (err) { return reject(err) }
|
||||
return resolve()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
uploadsController.list = async (req, res) => {
|
||||
const user = await utils.authorize(req, res);
|
||||
const user = await utils.authorize(req, res)
|
||||
|
||||
let offset = req.params.page;
|
||||
if (offset === undefined) offset = 0;
|
||||
let offset = req.params.page
|
||||
if (offset === undefined) offset = 0
|
||||
|
||||
const files = await db.table('files')
|
||||
.where(function() {
|
||||
if (req.params.id === undefined) this.where('id', '<>', '');
|
||||
else this.where('albumid', req.params.id);
|
||||
})
|
||||
.where(function() {
|
||||
if (user.username !== 'root') this.where('userid', user.id);
|
||||
})
|
||||
.orderBy('id', 'DESC')
|
||||
.limit(25)
|
||||
.offset(25 * offset)
|
||||
.select('id', 'albumid', 'timestamp', 'name', 'userid');
|
||||
const files = await db.table('files')
|
||||
.where(function () {
|
||||
if (req.params.id === undefined) this.where('id', '<>', '')
|
||||
else this.where('albumid', req.params.id)
|
||||
})
|
||||
.where(function () {
|
||||
if (user.username !== 'root') this.where('userid', user.id)
|
||||
})
|
||||
.orderBy('id', 'DESC')
|
||||
.limit(25)
|
||||
.offset(25 * offset)
|
||||
.select('id', 'albumid', 'timestamp', 'name', 'userid')
|
||||
|
||||
const albums = await db.table('albums');
|
||||
let basedomain = config.domain;
|
||||
let userids = [];
|
||||
const albums = await db.table('albums')
|
||||
let basedomain = config.domain
|
||||
let userids = []
|
||||
|
||||
for (let file of files) {
|
||||
file.file = `${basedomain}/${file.name}`;
|
||||
file.date = new Date(file.timestamp * 1000);
|
||||
file.date = utils.getPrettyDate(file.date);
|
||||
for (let file of files) {
|
||||
file.file = `${basedomain}/${file.name}`
|
||||
file.date = new Date(file.timestamp * 1000)
|
||||
file.date = utils.getPrettyDate(file.date)
|
||||
|
||||
file.album = '';
|
||||
file.album = ''
|
||||
|
||||
if (file.albumid !== undefined) {
|
||||
for (let album of albums) {
|
||||
if (file.albumid === album.id) {
|
||||
file.album = album.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (file.albumid !== undefined) {
|
||||
for (let album of albums) {
|
||||
if (file.albumid === album.id) {
|
||||
file.album = album.name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Only push usernames if we are root
|
||||
if (user.username === 'root') {
|
||||
if (file.userid !== undefined && file.userid !== null && file.userid !== '') {
|
||||
userids.push(file.userid);
|
||||
}
|
||||
}
|
||||
// Only push usernames if we are root
|
||||
if (user.username === 'root') {
|
||||
if (file.userid !== undefined && file.userid !== null && file.userid !== '') {
|
||||
userids.push(file.userid)
|
||||
}
|
||||
}
|
||||
|
||||
let ext = path.extname(file.name).toLowerCase();
|
||||
if (utils.imageExtensions.includes(ext) || utils.videoExtensions.includes(ext)) {
|
||||
file.thumb = `${basedomain}/thumbs/${file.name.slice(0, -ext.length)}.png`;
|
||||
}
|
||||
}
|
||||
let ext = path.extname(file.name).toLowerCase()
|
||||
if (utils.imageExtensions.includes(ext) || utils.videoExtensions.includes(ext)) {
|
||||
file.thumb = `${basedomain}/thumbs/${file.name.slice(0, -ext.length)}.png`
|
||||
}
|
||||
}
|
||||
|
||||
// If we are a normal user, send response
|
||||
if (user.username !== 'root') return res.json({ success: true, files });
|
||||
// If we are a normal user, send response
|
||||
if (user.username !== 'root') return res.json({ success: true, files })
|
||||
|
||||
// If we are root but there are no uploads attached to a user, send response
|
||||
if (userids.length === 0) return res.json({ success: true, files });
|
||||
// If we are root but there are no uploads attached to a user, send response
|
||||
if (userids.length === 0) return res.json({ success: true, files })
|
||||
|
||||
const users = await db.table('users').whereIn('id', userids);
|
||||
for (let dbUser of users) {
|
||||
for (let file of files) {
|
||||
if (file.userid === dbUser.id) {
|
||||
file.username = dbUser.username;
|
||||
}
|
||||
}
|
||||
}
|
||||
const users = await db.table('users').whereIn('id', userids)
|
||||
for (let dbUser of users) {
|
||||
for (let file of files) {
|
||||
if (file.userid === dbUser.id) {
|
||||
file.username = dbUser.username
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res.json({ success: true, files });
|
||||
};
|
||||
return res.json({ success: true, files })
|
||||
}
|
||||
|
||||
module.exports = uploadsController;
|
||||
module.exports = uploadsController
|
||||
|
@ -1,67 +1,67 @@
|
||||
const path = require('path');
|
||||
const config = require('../config.js');
|
||||
const fs = require('fs');
|
||||
const gm = require('gm');
|
||||
const ffmpeg = require('fluent-ffmpeg');
|
||||
const db = require('knex')(config.database);
|
||||
const path = require('path')
|
||||
const config = require('../config.js')
|
||||
const fs = require('fs')
|
||||
const gm = require('gm')
|
||||
const ffmpeg = require('fluent-ffmpeg')
|
||||
const db = require('knex')(config.database)
|
||||
|
||||
const utilsController = {};
|
||||
utilsController.imageExtensions = ['.jpg', '.jpeg', '.bmp', '.gif', '.png'];
|
||||
utilsController.videoExtensions = ['.webm', '.mp4', '.wmv', '.avi', '.mov'];
|
||||
const utilsController = {}
|
||||
utilsController.imageExtensions = ['.jpg', '.jpeg', '.bmp', '.gif', '.png']
|
||||
utilsController.videoExtensions = ['.webm', '.mp4', '.wmv', '.avi', '.mov']
|
||||
|
||||
utilsController.getPrettyDate = function(date) {
|
||||
return date.getFullYear() + '-'
|
||||
+ (date.getMonth() + 1) + '-'
|
||||
+ date.getDate() + ' '
|
||||
+ (date.getHours() < 10 ? '0' : '')
|
||||
+ date.getHours() + ':'
|
||||
+ (date.getMinutes() < 10 ? '0' : '')
|
||||
+ date.getMinutes() + ':'
|
||||
+ (date.getSeconds() < 10 ? '0' : '')
|
||||
+ date.getSeconds();
|
||||
utilsController.getPrettyDate = function (date) {
|
||||
return date.getFullYear() + '-' +
|
||||
(date.getMonth() + 1) + '-' +
|
||||
date.getDate() + ' ' +
|
||||
(date.getHours() < 10 ? '0' : '') +
|
||||
date.getHours() + ':' +
|
||||
(date.getMinutes() < 10 ? '0' : '') +
|
||||
date.getMinutes() + ':' +
|
||||
(date.getSeconds() < 10 ? '0' : '') +
|
||||
date.getSeconds()
|
||||
}
|
||||
|
||||
utilsController.authorize = async (req, res) => {
|
||||
const token = req.headers.token;
|
||||
if (token === undefined) return res.status(401).json({ success: false, description: 'No token provided' });
|
||||
const token = req.headers.token
|
||||
if (token === undefined) return res.status(401).json({ success: false, description: 'No token provided' })
|
||||
|
||||
const user = await db.table('users').where('token', token).first();
|
||||
if (!user) return res.status(401).json({ success: false, description: 'Invalid token' });
|
||||
return user;
|
||||
};
|
||||
const user = await db.table('users').where('token', token).first()
|
||||
if (!user) return res.status(401).json({ success: false, description: 'Invalid token' })
|
||||
return user
|
||||
}
|
||||
|
||||
utilsController.generateThumbs = function(file, basedomain) {
|
||||
if (config.uploads.generateThumbnails !== true) return;
|
||||
const ext = path.extname(file.name).toLowerCase();
|
||||
utilsController.generateThumbs = function (file, basedomain) {
|
||||
if (config.uploads.generateThumbnails !== true) return
|
||||
const ext = path.extname(file.name).toLowerCase()
|
||||
|
||||
let thumbname = path.join(__dirname, '..', config.uploads.folder, 'thumbs', file.name.slice(0, -ext.length) + '.png');
|
||||
fs.access(thumbname, err => {
|
||||
if (err && err.code === 'ENOENT') {
|
||||
if (utilsController.videoExtensions.includes(ext)) {
|
||||
ffmpeg(path.join(__dirname, '..', config.uploads.folder, file.name))
|
||||
.thumbnail({
|
||||
timestamps: [0],
|
||||
filename: '%b.png',
|
||||
folder: path.join(__dirname, '..', config.uploads.folder, 'thumbs'),
|
||||
size: '200x?'
|
||||
})
|
||||
.on('error', error => console.log('Error - ', error.message));
|
||||
} else {
|
||||
let size = {
|
||||
width: 200,
|
||||
height: 200
|
||||
};
|
||||
gm(path.join(__dirname, '..', config.uploads.folder, file.name))
|
||||
.resize(size.width, size.height + '>')
|
||||
.gravity('Center')
|
||||
.extent(size.width, size.height)
|
||||
.background('transparent')
|
||||
.write(thumbname, error => {
|
||||
if (error) console.log('Error - ', error);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
let thumbname = path.join(__dirname, '..', config.uploads.folder, 'thumbs', file.name.slice(0, -ext.length) + '.png')
|
||||
fs.access(thumbname, err => {
|
||||
if (err && err.code === 'ENOENT') {
|
||||
if (utilsController.videoExtensions.includes(ext)) {
|
||||
ffmpeg(path.join(__dirname, '..', config.uploads.folder, file.name))
|
||||
.thumbnail({
|
||||
timestamps: [0],
|
||||
filename: '%b.png',
|
||||
folder: path.join(__dirname, '..', config.uploads.folder, 'thumbs'),
|
||||
size: '200x?'
|
||||
})
|
||||
.on('error', error => console.log('Error - ', error.message))
|
||||
} else {
|
||||
let size = {
|
||||
width: 200,
|
||||
height: 200
|
||||
}
|
||||
gm(path.join(__dirname, '..', config.uploads.folder, file.name))
|
||||
.resize(size.width, size.height + '>')
|
||||
.gravity('Center')
|
||||
.extent(size.width, size.height)
|
||||
.background('transparent')
|
||||
.write(thumbname, error => {
|
||||
if (error) console.log('Error - ', error)
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = utilsController;
|
||||
module.exports = utilsController
|
||||
|
@ -1,50 +1,49 @@
|
||||
let init = function(db){
|
||||
let init = function (db) {
|
||||
// Create the tables we need to store galleries and files
|
||||
db.schema.createTableIfNotExists('albums', function (table) {
|
||||
table.increments()
|
||||
table.integer('userid')
|
||||
table.string('name')
|
||||
table.string('identifier')
|
||||
table.integer('enabled')
|
||||
table.integer('timestamp')
|
||||
}).then(() => {})
|
||||
|
||||
// Create the tables we need to store galleries and files
|
||||
db.schema.createTableIfNotExists('albums', function (table) {
|
||||
table.increments()
|
||||
table.integer('userid')
|
||||
table.string('name')
|
||||
table.string('identifier')
|
||||
table.integer('enabled')
|
||||
table.integer('timestamp')
|
||||
}).then(() => {})
|
||||
db.schema.createTableIfNotExists('files', function (table) {
|
||||
table.increments()
|
||||
table.integer('userid')
|
||||
table.string('name')
|
||||
table.string('original')
|
||||
table.string('type')
|
||||
table.string('size')
|
||||
table.string('hash')
|
||||
table.string('ip')
|
||||
table.integer('albumid')
|
||||
table.integer('timestamp')
|
||||
}).then(() => {})
|
||||
|
||||
db.schema.createTableIfNotExists('files', function (table) {
|
||||
table.increments()
|
||||
table.integer('userid')
|
||||
table.string('name')
|
||||
table.string('original')
|
||||
table.string('type')
|
||||
table.string('size')
|
||||
table.string('hash')
|
||||
table.string('ip')
|
||||
table.integer('albumid')
|
||||
table.integer('timestamp')
|
||||
}).then(() => {})
|
||||
db.schema.createTableIfNotExists('users', function (table) {
|
||||
table.increments()
|
||||
table.string('username')
|
||||
table.string('password')
|
||||
table.string('token')
|
||||
table.integer('timestamp')
|
||||
}).then(() => {
|
||||
db.table('users').where({username: 'root'}).then((user) => {
|
||||
if (user.length > 0) return
|
||||
|
||||
db.schema.createTableIfNotExists('users', function (table) {
|
||||
table.increments()
|
||||
table.string('username')
|
||||
table.string('password')
|
||||
table.string('token')
|
||||
table.integer('timestamp')
|
||||
}).then(() => {
|
||||
db.table('users').where({username: 'root'}).then((user) => {
|
||||
if(user.length > 0) return
|
||||
require('bcrypt').hash('root', 10, function (err, hash) {
|
||||
if (err) console.error('Error generating password hash for root')
|
||||
|
||||
require('bcrypt').hash('root', 10, function(err, hash) {
|
||||
if(err) console.error('Error generating password hash for root')
|
||||
|
||||
db.table('users').insert({
|
||||
username: 'root',
|
||||
password: hash,
|
||||
token: require('randomstring').generate(64),
|
||||
timestamp: Math.floor(Date.now() / 1000)
|
||||
}).then(() => {})
|
||||
})
|
||||
})
|
||||
})
|
||||
db.table('users').insert({
|
||||
username: 'root',
|
||||
password: hash,
|
||||
token: require('randomstring').generate(64),
|
||||
timestamp: Math.floor(Date.now() / 1000)
|
||||
}).then(() => {})
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = init
|
||||
module.exports = init
|
||||
|
@ -1,13 +1,13 @@
|
||||
const config = require('../config.js');
|
||||
const db = require('knex')(config.database);
|
||||
const config = require('../config.js')
|
||||
const db = require('knex')(config.database)
|
||||
|
||||
const migration = {};
|
||||
const migration = {}
|
||||
migration.start = async () => {
|
||||
await db.schema.table('albums', table => {
|
||||
table.dateTime('editedAt');
|
||||
table.dateTime('zipGeneratedAt');
|
||||
});
|
||||
console.log('Migration finished! Now start lolisafe normally');
|
||||
};
|
||||
await db.schema.table('albums', table => {
|
||||
table.dateTime('editedAt')
|
||||
table.dateTime('zipGeneratedAt')
|
||||
})
|
||||
console.log('Migration finished! Now start lolisafe normally')
|
||||
}
|
||||
|
||||
migration.start();
|
||||
migration.start()
|
||||
|
94
lolisafe.js
94
lolisafe.js
@ -1,58 +1,66 @@
|
||||
const config = require('./config.js');
|
||||
const api = require('./routes/api.js');
|
||||
const album = require('./routes/album.js');
|
||||
const express = require('express');
|
||||
const helmet = require('helmet');
|
||||
const bodyParser = require('body-parser');
|
||||
const RateLimit = require('express-rate-limit');
|
||||
const db = require('knex')(config.database);
|
||||
const fs = require('fs');
|
||||
const exphbs = require('express-handlebars');
|
||||
const safe = express();
|
||||
const config = require('./config.js')
|
||||
const api = require('./routes/api.js')
|
||||
const album = require('./routes/album.js')
|
||||
const express = require('express')
|
||||
const helmet = require('helmet')
|
||||
const bodyParser = require('body-parser')
|
||||
const RateLimit = require('express-rate-limit')
|
||||
const db = require('knex')(config.database)
|
||||
const fs = require('fs')
|
||||
const exphbs = require('express-handlebars')
|
||||
const safe = express()
|
||||
|
||||
require('./database/db.js')(db);
|
||||
require('./database/db.js')(db)
|
||||
|
||||
fs.existsSync('./pages/custom') || fs.mkdirSync('./pages/custom');
|
||||
fs.existsSync(`./${config.logsFolder}`) || fs.mkdirSync(`./${ config.logsFolder}`);
|
||||
fs.existsSync(`./${config.uploads.folder}`) || fs.mkdirSync(`./${config.uploads.folder}`);
|
||||
fs.existsSync(`./${config.uploads.folder}/thumbs`) || fs.mkdirSync(`./${config.uploads.folder }/thumbs`);
|
||||
fs.existsSync(`./${config.uploads.folder }/zips`) || fs.mkdirSync(`./${config.uploads.folder}/zips`);
|
||||
fs.existsSync('./pages/custom') || fs.mkdirSync('./pages/custom')
|
||||
fs.existsSync('./' + config.logsFolder) || fs.mkdirSync('./' + config.logsFolder)
|
||||
fs.existsSync('./' + config.uploads.folder) || fs.mkdirSync('./' + config.uploads.folder)
|
||||
fs.existsSync('./' + config.uploads.folder + '/thumbs') || fs.mkdirSync('./' + config.uploads.folder + '/thumbs')
|
||||
fs.existsSync('./' + config.uploads.folder + '/zips') || fs.mkdirSync('./' + config.uploads.folder + '/zips')
|
||||
|
||||
safe.use(helmet());
|
||||
safe.set('trust proxy', 1);
|
||||
safe.use(helmet())
|
||||
safe.set('trust proxy', 1)
|
||||
|
||||
safe.engine('handlebars', exphbs({ defaultLayout: 'main' }));
|
||||
safe.set('view engine', 'handlebars');
|
||||
safe.enable('view cache');
|
||||
safe.engine('handlebars', exphbs({ defaultLayout: 'main' }))
|
||||
safe.set('view engine', 'handlebars')
|
||||
safe.enable('view cache')
|
||||
|
||||
let limiter = new RateLimit({ windowMs: 5000, max: 2 });
|
||||
safe.use('/api/login/', limiter);
|
||||
safe.use('/api/register/', limiter);
|
||||
let limiter = new RateLimit({ windowMs: 5000, max: 2 })
|
||||
safe.use('/api/login/', limiter)
|
||||
safe.use('/api/register/', limiter)
|
||||
|
||||
safe.use(bodyParser.urlencoded({ extended: true }));
|
||||
safe.use(bodyParser.json());
|
||||
safe.use(bodyParser.urlencoded({ extended: true }))
|
||||
safe.use(bodyParser.json())
|
||||
|
||||
if (config.serveFilesWithNode) {
|
||||
safe.use('/', express.static(config.uploads.folder));
|
||||
safe.use('/', express.static(config.uploads.folder))
|
||||
}
|
||||
|
||||
safe.use('/', express.static('./public'));
|
||||
safe.use('/', album);
|
||||
safe.use('/api', api);
|
||||
safe.use('/', express.static('./public'))
|
||||
safe.use('/', album)
|
||||
safe.use('/api', api)
|
||||
|
||||
for (let page of config.pages) {
|
||||
let root = './pages/';
|
||||
if (fs.existsSync(`./pages/custom/${page}.html`)) {
|
||||
root = './pages/custom/';
|
||||
}
|
||||
if (page === 'home') {
|
||||
safe.get('/', (req, res, next) => res.sendFile(`${page}.html`, { root: root }));
|
||||
} else {
|
||||
safe.get(`/${page}`, (req, res, next) => res.sendFile(`${page}.html`, { root: root }));
|
||||
}
|
||||
let root = './pages/'
|
||||
if (fs.existsSync(`./pages/custom/${page}.html`)) {
|
||||
root = './pages/custom/'
|
||||
}
|
||||
if (page === 'home') {
|
||||
safe.get('/', (req, res, next) => res.sendFile(`${page}.html`, { root: root }))
|
||||
} else {
|
||||
safe.get(`/${page}`, (req, res, next) => res.sendFile(`${page}.html`, { root: root }))
|
||||
}
|
||||
}
|
||||
|
||||
safe.use((req, res, next) => res.status(404).sendFile('404.html', { root: './pages/error/' }));
|
||||
safe.use((req, res, next) => res.status(500).sendFile('500.html', { root: './pages/error/' }));
|
||||
safe.use((req, res, next) => res.status(404).sendFile('404.html', { root: './pages/error/' }))
|
||||
safe.use((req, res, next) => res.status(500).sendFile('500.html', { root: './pages/error/' }))
|
||||
|
||||
safe.listen(config.port, () => console.log(`lolisafe started on port ${config.port}`));
|
||||
safe.listen(config.port, () => console.log(`lolisafe started on port ${config.port}`))
|
||||
|
||||
process.on('uncaughtException', err => {
|
||||
console.error(`Uncaught Exception:\n${err.stack}`)
|
||||
})
|
||||
|
||||
process.on('unhandledRejection', err => {
|
||||
console.error(`Unhandled Rejection (Promise):\n${err.stack}`)
|
||||
})
|
||||
|
16
package.json
16
package.json
@ -30,19 +30,9 @@
|
||||
"sqlite3": "^3.1.13"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "^4.4.1",
|
||||
"eslint-config-aqua": "^1.5.0"
|
||||
"standard": "^10.0.3"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"aqua"
|
||||
],
|
||||
"env": {
|
||||
"browser": true,
|
||||
"node": true
|
||||
},
|
||||
"rules": {
|
||||
"func-names": 0
|
||||
}
|
||||
"standard": {
|
||||
"envs": ["browser", "node"]
|
||||
}
|
||||
}
|
||||
|
@ -39,6 +39,7 @@
|
||||
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.15.3/axios.min.js"></script>
|
||||
<script type="text/javascript" src="https://use.fontawesome.com/cd26baa9bd.js"></script>
|
||||
<script type="text/javascript" src="/js/auth.js"></script>
|
||||
|
||||
<style type="text/css">
|
||||
/** Based on KDE Breeze Dark **/
|
||||
|
||||
@ -46,6 +47,7 @@
|
||||
background-color: #232629;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
@ -39,6 +39,7 @@
|
||||
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.15.3/axios.min.js"></script>
|
||||
<script type="text/javascript" src="https://use.fontawesome.com/cd26baa9bd.js"></script>
|
||||
<script type="text/javascript" src="/js/dashboard.js"></script>
|
||||
|
||||
<style type="text/css">
|
||||
/** Based on KDE Breeze Dark **/
|
||||
|
||||
@ -122,6 +123,7 @@
|
||||
border-left-color: #31363b;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<browserconfig>
|
||||
<msapplication>
|
||||
<tile>
|
||||
<square150x150logo src="/images/icons/mstile-150x150.png?v=ZqYs7M3fG4"/>
|
||||
<TileColor>#232629</TileColor>
|
||||
</tile>
|
||||
</msapplication>
|
||||
<msapplication>
|
||||
<tile>
|
||||
<square150x150logo src="/images/icons/mstile-150x150.png?v=ZqYs7M3fG4"/>
|
||||
<TileColor>#232629</TileColor>
|
||||
</tile>
|
||||
</msapplication>
|
||||
</browserconfig>
|
||||
|
@ -1,18 +1,18 @@
|
||||
{
|
||||
"name": "safe.fiery.me",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/images/icons/android-chrome-192x192.png?v=ZqYs7M3fG4",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/images/icons/android-chrome-384x384.png?v=ZqYs7M3fG4",
|
||||
"sizes": "384x384",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"theme_color": "#232629",
|
||||
"background_color": "#232629",
|
||||
"display": "standalone"
|
||||
"name": "safe.fiery.me",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/images/icons/android-chrome-192x192.png?v=ZqYs7M3fG4",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/images/icons/android-chrome-384x384.png?v=ZqYs7M3fG4",
|
||||
"sizes": "384x384",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"theme_color": "#232629",
|
||||
"background_color": "#232629",
|
||||
"display": "standalone"
|
||||
}
|
||||
|
@ -1,44 +1,56 @@
|
||||
var page = {};
|
||||
/* global swal, axios */
|
||||
|
||||
page.do = function(dest) {
|
||||
var user = document.getElementById('user').value;
|
||||
var pass = document.getElementById('pass').value;
|
||||
var page = {}
|
||||
|
||||
if (user === undefined || user === null || user === '') { return swal('Error', 'You need to specify a username', 'error'); }
|
||||
if (pass === undefined || pass === null || pass === '') { return swal('Error', 'You need to specify a username', 'error'); }
|
||||
page.do = function (dest) {
|
||||
var user = document.getElementById('user').value
|
||||
var pass = document.getElementById('pass').value
|
||||
|
||||
axios.post(`/api/${dest}`, {
|
||||
username: user,
|
||||
password: pass
|
||||
})
|
||||
.then(response => {
|
||||
if (response.data.success === false) { return swal('Error', response.data.description, 'error'); }
|
||||
if (user === undefined || user === null || user === '') {
|
||||
return swal('Error', 'You need to specify a username', 'error')
|
||||
}
|
||||
if (pass === undefined || pass === null || pass === '') {
|
||||
return swal('Error', 'You need to specify a username', 'error')
|
||||
}
|
||||
|
||||
localStorage.token = response.data.token;
|
||||
window.location = '/dashboard';
|
||||
})
|
||||
.catch(error => {
|
||||
return swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error');
|
||||
console.log(error);
|
||||
});
|
||||
};
|
||||
axios.post('/api/' + dest, {
|
||||
username: user,
|
||||
password: pass
|
||||
})
|
||||
.then(function (response) {
|
||||
if (response.data.success === false) {
|
||||
return swal('Error', response.data.description, 'error')
|
||||
}
|
||||
|
||||
page.verify = function() {
|
||||
page.token = localStorage.token;
|
||||
if (page.token === undefined) return;
|
||||
localStorage.token = response.data.token
|
||||
window.location = '/dashboard'
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.log(error)
|
||||
return swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error')
|
||||
})
|
||||
}
|
||||
|
||||
axios.post('/api/tokens/verify', { token: page.token })
|
||||
.then(response => {
|
||||
if (response.data.success === false) { return swal('Error', response.data.description, 'error'); }
|
||||
page.verify = function () {
|
||||
page.token = localStorage.token
|
||||
if (page.token === undefined) return
|
||||
|
||||
window.location = '/dashboard';
|
||||
})
|
||||
.catch(error => {
|
||||
return swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error');
|
||||
console.log(error);
|
||||
});
|
||||
};
|
||||
axios.post('/api/tokens/verify', {
|
||||
token: page.token
|
||||
})
|
||||
.then(function (response) {
|
||||
if (response.data.success === false) {
|
||||
return swal('Error', response.data.description, 'error')
|
||||
}
|
||||
|
||||
window.onload = function() {
|
||||
page.verify();
|
||||
};
|
||||
window.location = '/dashboard'
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.log(error)
|
||||
return swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error')
|
||||
})
|
||||
}
|
||||
|
||||
window.onload = function () {
|
||||
page.verify()
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,172 +1,178 @@
|
||||
var upload = {};
|
||||
/* eslint-disable no-unused-expressions */
|
||||
/* global swal, axios, Dropzone */
|
||||
|
||||
upload.isPrivate = true;
|
||||
upload.token = localStorage.token;
|
||||
upload.maxFileSize;
|
||||
var upload = {}
|
||||
|
||||
upload.isPrivate = true
|
||||
upload.token = localStorage.token
|
||||
upload.maxFileSize
|
||||
// Add the album var to the upload so we can store the album id in there
|
||||
upload.album;
|
||||
upload.myDropzone;
|
||||
upload.album
|
||||
upload.myDropzone
|
||||
|
||||
upload.checkIfPublic = function() {
|
||||
axios.get('/api/check')
|
||||
.then(response => {
|
||||
upload.isPrivate = response.data.private;
|
||||
upload.maxFileSize = response.data.maxFileSize;
|
||||
upload.preparePage();
|
||||
})
|
||||
.catch(error => {
|
||||
swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error');
|
||||
return console.log(error);
|
||||
});
|
||||
};
|
||||
upload.checkIfPublic = function () {
|
||||
axios.get('/api/check')
|
||||
.then(response => {
|
||||
upload.isPrivate = response.data.private
|
||||
upload.maxFileSize = response.data.maxFileSize
|
||||
upload.preparePage()
|
||||
})
|
||||
.catch(error => {
|
||||
swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error')
|
||||
return console.log(error)
|
||||
})
|
||||
}
|
||||
|
||||
upload.preparePage = function() {
|
||||
if (!upload.isPrivate) return upload.prepareUpload();
|
||||
if (!upload.token) return document.getElementById('loginToUpload').style.display = 'inline-flex';
|
||||
upload.verifyToken(upload.token, true);
|
||||
};
|
||||
upload.preparePage = function () {
|
||||
if (!upload.isPrivate) return upload.prepareUpload()
|
||||
if (!upload.token) {
|
||||
document.getElementById('loginToUpload').style.display = 'inline-flex'
|
||||
return 'inline-flex'
|
||||
}
|
||||
upload.verifyToken(upload.token, true)
|
||||
}
|
||||
|
||||
upload.verifyToken = function(token, reloadOnError) {
|
||||
if (reloadOnError === undefined) { reloadOnError = false; }
|
||||
upload.verifyToken = function (token, reloadOnError) {
|
||||
if (reloadOnError === undefined) { reloadOnError = false }
|
||||
|
||||
axios.post('/api/tokens/verify', { token: token })
|
||||
.then(response => {
|
||||
if (response.data.success === false) {
|
||||
swal({
|
||||
title: 'An error ocurred',
|
||||
text: response.data.description,
|
||||
type: 'error'
|
||||
}, () => {
|
||||
if (reloadOnError) {
|
||||
localStorage.removeItem('token');
|
||||
location.reload();
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
axios.post('/api/tokens/verify', { token: token })
|
||||
.then(response => {
|
||||
if (response.data.success === false) {
|
||||
swal({
|
||||
title: 'An error ocurred',
|
||||
text: response.data.description,
|
||||
type: 'error'
|
||||
}, () => {
|
||||
if (reloadOnError) {
|
||||
localStorage.removeItem('token')
|
||||
location.reload()
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
localStorage.token = token;
|
||||
upload.token = token;
|
||||
return upload.prepareUpload();
|
||||
})
|
||||
.catch(error => {
|
||||
swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error');
|
||||
return console.log(error);
|
||||
});
|
||||
};
|
||||
localStorage.token = token
|
||||
upload.token = token
|
||||
return upload.prepareUpload()
|
||||
})
|
||||
.catch(error => {
|
||||
swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error')
|
||||
return console.log(error)
|
||||
})
|
||||
}
|
||||
|
||||
upload.prepareUpload = function() {
|
||||
// I think this fits best here because we need to check for a valid token before we can get the albums
|
||||
if (upload.token) {
|
||||
var select = document.getElementById('albumSelect');
|
||||
upload.prepareUpload = function () {
|
||||
// I think this fits best here because we need to check for a valid token before we can get the albums
|
||||
if (upload.token) {
|
||||
var select = document.getElementById('albumSelect')
|
||||
|
||||
select.addEventListener('change', () => {
|
||||
upload.album = select.value;
|
||||
});
|
||||
select.addEventListener('change', () => {
|
||||
upload.album = select.value
|
||||
})
|
||||
|
||||
axios.get('/api/albums', { headers: { token: upload.token } })
|
||||
.then(res => {
|
||||
var albums = res.data.albums;
|
||||
axios.get('/api/albums', { headers: { token: upload.token } })
|
||||
.then(res => {
|
||||
var albums = res.data.albums
|
||||
|
||||
// If the user doesn't have any albums we don't really need to display
|
||||
// an album selection
|
||||
if (albums.length === 0) return;
|
||||
// If the user doesn't have any albums we don't really need to display
|
||||
// an album selection
|
||||
if (albums.length === 0) return
|
||||
|
||||
// Loop through the albums and create an option for each album
|
||||
for (var i = 0; i < albums.length; i++) {
|
||||
var opt = document.createElement('option');
|
||||
opt.value = albums[i].id;
|
||||
opt.innerHTML = albums[i].name;
|
||||
select.appendChild(opt);
|
||||
}
|
||||
// Display the album selection
|
||||
document.getElementById('albumDiv').style.display = 'block';
|
||||
})
|
||||
.catch(e => {
|
||||
swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error');
|
||||
return console.log(e);
|
||||
});
|
||||
}
|
||||
// Loop through the albums and create an option for each album
|
||||
for (var i = 0; i < albums.length; i++) {
|
||||
var opt = document.createElement('option')
|
||||
opt.value = albums[i].id
|
||||
opt.innerHTML = albums[i].name
|
||||
select.appendChild(opt)
|
||||
}
|
||||
// Display the album selection
|
||||
document.getElementById('albumDiv').style.display = 'block'
|
||||
})
|
||||
.catch(e => {
|
||||
swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error')
|
||||
return console.log(e)
|
||||
})
|
||||
}
|
||||
|
||||
div = document.createElement('div');
|
||||
div.id = 'dropzone';
|
||||
div.innerHTML = 'Click here or drag and drop files';
|
||||
div.style.display = 'flex';
|
||||
var div = document.createElement('div')
|
||||
div.id = 'dropzone'
|
||||
div.innerHTML = 'Click here or drag and drop files'
|
||||
div.style.display = 'flex'
|
||||
|
||||
document.getElementById('maxFileSize').innerHTML = `Maximum upload size per file is ${upload.maxFileSize}`;
|
||||
document.getElementById('loginToUpload').style.display = 'none';
|
||||
document.getElementById('maxFileSize').innerHTML = `Maximum upload size per file is ${upload.maxFileSize}`
|
||||
document.getElementById('loginToUpload').style.display = 'none'
|
||||
|
||||
if (upload.token === undefined) { document.getElementById('loginLinkText').innerHTML = 'Create an account and keep track of your uploads'; }
|
||||
if (upload.token === undefined) { document.getElementById('loginLinkText').innerHTML = 'Create an account and keep track of your uploads' }
|
||||
|
||||
document.getElementById('uploadContainer').appendChild(div);
|
||||
document.getElementById('uploadContainer').appendChild(div)
|
||||
|
||||
upload.prepareDropzone();
|
||||
};
|
||||
upload.prepareDropzone()
|
||||
}
|
||||
|
||||
upload.prepareDropzone = function() {
|
||||
var previewNode = document.querySelector('#template');
|
||||
previewNode.id = '';
|
||||
var previewTemplate = previewNode.parentNode.innerHTML;
|
||||
previewNode.parentNode.removeChild(previewNode);
|
||||
upload.prepareDropzone = function () {
|
||||
var previewNode = document.querySelector('#template')
|
||||
previewNode.id = ''
|
||||
var previewTemplate = previewNode.parentNode.innerHTML
|
||||
previewNode.parentNode.removeChild(previewNode)
|
||||
|
||||
var dropzone = new Dropzone('div#dropzone', {
|
||||
url: '/api/upload',
|
||||
paramName: 'files[]',
|
||||
maxFilesize: upload.maxFileSize.slice(0, -2),
|
||||
parallelUploads: 2,
|
||||
uploadMultiple: false,
|
||||
previewsContainer: 'div#uploads',
|
||||
previewTemplate: previewTemplate,
|
||||
createImageThumbnails: false,
|
||||
maxFiles: 1000,
|
||||
autoProcessQueue: true,
|
||||
headers: { token: upload.token },
|
||||
init: function() {
|
||||
upload.myDropzone = this;
|
||||
this.on('addedfile', file => {
|
||||
document.getElementById('uploads').style.display = 'block';
|
||||
});
|
||||
// Add the selected albumid, if an album is selected, as a header
|
||||
this.on('sending', (file, xhr) => {
|
||||
if (upload.album) {
|
||||
xhr.setRequestHeader('albumid', upload.album);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
var dropzone = new Dropzone('div#dropzone', {
|
||||
url: '/api/upload',
|
||||
paramName: 'files[]',
|
||||
maxFilesize: upload.maxFileSize.slice(0, -2),
|
||||
parallelUploads: 2,
|
||||
uploadMultiple: false,
|
||||
previewsContainer: 'div#uploads',
|
||||
previewTemplate: previewTemplate,
|
||||
createImageThumbnails: false,
|
||||
maxFiles: 1000,
|
||||
autoProcessQueue: true,
|
||||
headers: { token: upload.token },
|
||||
init: function () {
|
||||
upload.myDropzone = this
|
||||
this.on('addedfile', file => {
|
||||
document.getElementById('uploads').style.display = 'block'
|
||||
})
|
||||
// Add the selected albumid, if an album is selected, as a header
|
||||
this.on('sending', (file, xhr) => {
|
||||
if (upload.album) {
|
||||
xhr.setRequestHeader('albumid', upload.album)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// Update the total progress bar
|
||||
dropzone.on('uploadprogress', (file, progress) => {
|
||||
file.previewElement.querySelector('.progress').setAttribute('value', progress);
|
||||
file.previewElement.querySelector('.progress').innerHTML = `${progress}%`;
|
||||
});
|
||||
// Update the total progress bar
|
||||
dropzone.on('uploadprogress', (file, progress) => {
|
||||
file.previewElement.querySelector('.progress').setAttribute('value', progress)
|
||||
file.previewElement.querySelector('.progress').innerHTML = `${progress}%`
|
||||
})
|
||||
|
||||
dropzone.on('success', (file, response) => {
|
||||
// Handle the responseText here. For example, add the text to the preview element:
|
||||
dropzone.on('success', (file, response) => {
|
||||
// Handle the responseText here. For example, add the text to the preview element:
|
||||
|
||||
if (response.success === false) {
|
||||
var span = document.createElement('span');
|
||||
span.innerHTML = response.description;
|
||||
file.previewTemplate.querySelector('.link').appendChild(span);
|
||||
return;
|
||||
}
|
||||
if (response.success === false) {
|
||||
var span = document.createElement('span')
|
||||
span.innerHTML = response.description
|
||||
file.previewTemplate.querySelector('.link').appendChild(span)
|
||||
return
|
||||
}
|
||||
|
||||
a = document.createElement('a');
|
||||
a.href = response.files[0].url;
|
||||
a.target = '_blank';
|
||||
a.innerHTML = response.files[0].url;
|
||||
file.previewTemplate.querySelector('.link').appendChild(a);
|
||||
var a = document.createElement('a')
|
||||
a.href = response.files[0].url
|
||||
a.target = '_blank'
|
||||
a.innerHTML = response.files[0].url
|
||||
file.previewTemplate.querySelector('.link').appendChild(a)
|
||||
|
||||
file.previewTemplate.querySelector('.progress').style.display = 'none';
|
||||
});
|
||||
file.previewTemplate.querySelector('.progress').style.display = 'none'
|
||||
})
|
||||
|
||||
upload.prepareShareX();
|
||||
};
|
||||
upload.prepareShareX()
|
||||
}
|
||||
|
||||
upload.prepareShareX = function() {
|
||||
if (upload.token) {
|
||||
var sharex_element = document.getElementById('ShareX');
|
||||
var sharex_file = `{\r\n\
|
||||
upload.prepareShareX = function () {
|
||||
if (upload.token) {
|
||||
var sharexElement = document.getElementById('ShareX')
|
||||
var sharexFile = `{\r\n\
|
||||
"Name": "${location.hostname}",\r\n\
|
||||
"DestinationType": "ImageUploader, FileUploader",\r\n\
|
||||
"RequestType": "POST",\r\n\
|
||||
@ -178,30 +184,29 @@ upload.prepareShareX = function() {
|
||||
"ResponseType": "Text",\r\n\
|
||||
"URL": "$json:files[0].url$",\r\n\
|
||||
"ThumbnailURL": "$json:files[0].url$"\r\n\
|
||||
}`;
|
||||
var sharex_blob = new Blob([sharex_file], { type: 'application/octet-binary' });
|
||||
sharex_element.setAttribute('href', URL.createObjectURL(sharex_blob));
|
||||
sharex_element.setAttribute('download', `${location.hostname}.sxcu`);
|
||||
}
|
||||
};
|
||||
}`
|
||||
var sharexBlob = new Blob([sharexFile], { type: 'application/octet-binary' })
|
||||
sharexElement.setAttribute('href', URL.createObjectURL(sharexBlob))
|
||||
sharexElement.setAttribute('download', `${location.hostname}.sxcu`)
|
||||
}
|
||||
}
|
||||
|
||||
// Handle image paste event
|
||||
window.addEventListener('paste', event => {
|
||||
var items = (event.clipboardData || event.originalEvent.clipboardData).items;
|
||||
for (index in items) {
|
||||
var item = items[index];
|
||||
if (item.kind === 'file') {
|
||||
var blob = item.getAsFile();
|
||||
console.log(blob.type);
|
||||
var file = new File([blob], `pasted-image.${blob.type.match(/(?:[^\/]*\/)([^;]*)/)[1]}`);
|
||||
file.type = blob.type;
|
||||
console.log(file);
|
||||
upload.myDropzone.addFile(file);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
window.onload = function() {
|
||||
upload.checkIfPublic();
|
||||
};
|
||||
var items = (event.clipboardData || event.originalEvent.clipboardData).items
|
||||
for (var index in items) {
|
||||
var item = items[index]
|
||||
if (item.kind === 'file') {
|
||||
var blob = item.getAsFile()
|
||||
console.log(blob.type)
|
||||
var file = new File([blob], `pasted-image.${blob.type.match(/(?:[^/]*\/)([^;]*)/)[1]}`)
|
||||
file.type = blob.type
|
||||
console.log(file)
|
||||
upload.myDropzone.addFile(file)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
window.onload = function () {
|
||||
upload.checkIfPublic()
|
||||
}
|
||||
|
@ -1,56 +1,55 @@
|
||||
const config = require('../config.js');
|
||||
const routes = require('express').Router();
|
||||
const db = require('knex')(config.database);
|
||||
const path = require('path');
|
||||
const utils = require('../controllers/utilsController.js');
|
||||
const config = require('../config.js')
|
||||
const routes = require('express').Router()
|
||||
const db = require('knex')(config.database)
|
||||
const path = require('path')
|
||||
const utils = require('../controllers/utilsController.js')
|
||||
|
||||
routes.get('/a/:identifier', async (req, res, next) => {
|
||||
let identifier = req.params.identifier;
|
||||
if (identifier === undefined) return res.status(401).json({ success: false, description: 'No identifier provided' });
|
||||
let identifier = req.params.identifier
|
||||
if (identifier === undefined) return res.status(401).json({ success: false, description: 'No identifier provided' })
|
||||
|
||||
const album = await db.table('albums').where({ identifier, enabled: 1 }).first();
|
||||
if (!album) return res.status(404).sendFile('404.html', { root: './pages/error/' });
|
||||
const album = await db.table('albums').where({ identifier, enabled: 1 }).first()
|
||||
if (!album) return res.status(404).sendFile('404.html', { root: './pages/error/' })
|
||||
|
||||
const files = await db.table('files').select('name').where('albumid', album.id).orderBy('id', 'DESC');
|
||||
let thumb = '';
|
||||
const basedomain = config.domain;
|
||||
const files = await db.table('files').select('name').where('albumid', album.id).orderBy('id', 'DESC')
|
||||
let thumb = ''
|
||||
const basedomain = config.domain
|
||||
|
||||
for (let file of files) {
|
||||
file.file = `${basedomain}/${file.name}`;
|
||||
for (let file of files) {
|
||||
file.file = `${basedomain}/${file.name}`
|
||||
|
||||
let ext = path.extname(file.name).toLowerCase();
|
||||
if (utils.imageExtensions.includes(ext) || utils.videoExtensions.includes(ext)) {
|
||||
file.thumb = `${basedomain}/thumbs/${file.name.slice(0, -ext.length)}.png`;
|
||||
let ext = path.extname(file.name).toLowerCase()
|
||||
if (utils.imageExtensions.includes(ext) || utils.videoExtensions.includes(ext)) {
|
||||
file.thumb = `${basedomain}/thumbs/${file.name.slice(0, -ext.length)}.png`
|
||||
|
||||
/*
|
||||
If thumbnail for album is still not set, do it.
|
||||
A potential improvement would be to let the user upload a specific image as an album cover
|
||||
since embedding the first image could potentially result in nsfw content when pasting links.
|
||||
*/
|
||||
/*
|
||||
If thumbnail for album is still not set, do it.
|
||||
A potential improvement would be to let the user upload a specific image as an album cover
|
||||
since embedding the first image could potentially result in nsfw content when pasting links.
|
||||
*/
|
||||
|
||||
if (thumb === '') {
|
||||
thumb = file.thumb;
|
||||
}
|
||||
if (thumb === '') {
|
||||
thumb = file.thumb
|
||||
}
|
||||
|
||||
file.thumb = `<img src="${file.thumb}"/>`;
|
||||
} else {
|
||||
file.thumb = `<h1 class="title">.${ext}</h1>`;
|
||||
}
|
||||
}
|
||||
file.thumb = `<img src="${file.thumb}"/>`
|
||||
} else {
|
||||
file.thumb = `<h1 class="title">.${ext}</h1>`
|
||||
}
|
||||
}
|
||||
|
||||
let enableDownload = false
|
||||
if (config.uploads.generateZips) enableDownload = true
|
||||
|
||||
let enableDownload = false;
|
||||
if (config.uploads.generateZips) enableDownload = true;
|
||||
return res.render('album', {
|
||||
layout: false,
|
||||
title: album.name,
|
||||
count: files.length,
|
||||
thumb,
|
||||
files,
|
||||
identifier,
|
||||
enableDownload
|
||||
})
|
||||
})
|
||||
|
||||
return res.render('album', {
|
||||
layout: false,
|
||||
title: album.name,
|
||||
count: files.length,
|
||||
thumb,
|
||||
files,
|
||||
identifier,
|
||||
enableDownload
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = routes;
|
||||
module.exports = routes
|
||||
|
@ -1,37 +1,37 @@
|
||||
const config = require('../config.js');
|
||||
const routes = require('express').Router();
|
||||
const uploadController = require('../controllers/uploadController');
|
||||
const albumsController = require('../controllers/albumsController');
|
||||
const tokenController = require('../controllers/tokenController');
|
||||
const authController = require('../controllers/authController');
|
||||
const config = require('../config.js')
|
||||
const routes = require('express').Router()
|
||||
const uploadController = require('../controllers/uploadController')
|
||||
const albumsController = require('../controllers/albumsController')
|
||||
const tokenController = require('../controllers/tokenController')
|
||||
const authController = require('../controllers/authController')
|
||||
|
||||
routes.get('/check', (req, res, next) => {
|
||||
return res.json({
|
||||
private: config.private,
|
||||
maxFileSize: config.uploads.maxSize
|
||||
});
|
||||
});
|
||||
return res.json({
|
||||
private: config.private,
|
||||
maxFileSize: config.uploads.maxSize
|
||||
})
|
||||
})
|
||||
|
||||
routes.post('/login', (req, res, next) => authController.verify(req, res, next));
|
||||
routes.post('/register', (req, res, next) => authController.register(req, res, next));
|
||||
routes.post('/password/change', (req, res, next) => authController.changePassword(req, res, next));
|
||||
routes.get('/uploads', (req, res, next) => uploadController.list(req, res, next));
|
||||
routes.get('/uploads/:page', (req, res, next) => uploadController.list(req, res, next));
|
||||
routes.post('/upload', (req, res, next) => uploadController.upload(req, res, next));
|
||||
routes.post('/upload/delete', (req, res, next) => uploadController.delete(req, res, next));
|
||||
routes.post('/upload/:albumid', (req, res, next) => uploadController.upload(req, res, next));
|
||||
routes.get('/album/get/:identifier', (req, res, next) => albumsController.get(req, res, next));
|
||||
routes.get('/album/zip/:identifier', (req, res, next) => albumsController.generateZip(req, res, next));
|
||||
routes.get('/album/:id', (req, res, next) => uploadController.list(req, res, next));
|
||||
routes.get('/album/:id/:page', (req, res, next) => uploadController.list(req, res, next));
|
||||
routes.get('/albums', (req, res, next) => albumsController.list(req, res, next));
|
||||
routes.get('/albums/:sidebar', (req, res, next) => albumsController.list(req, res, next));
|
||||
routes.post('/albums', (req, res, next) => albumsController.create(req, res, next));
|
||||
routes.post('/albums/delete', (req, res, next) => albumsController.delete(req, res, next));
|
||||
routes.post('/albums/rename', (req, res, next) => albumsController.rename(req, res, next));
|
||||
routes.get('/albums/test', (req, res, next) => albumsController.test(req, res, next));
|
||||
routes.get('/tokens', (req, res, next) => tokenController.list(req, res, next));
|
||||
routes.post('/tokens/verify', (req, res, next) => tokenController.verify(req, res, next));
|
||||
routes.post('/tokens/change', (req, res, next) => tokenController.change(req, res, next));
|
||||
routes.post('/login', (req, res, next) => authController.verify(req, res, next))
|
||||
routes.post('/register', (req, res, next) => authController.register(req, res, next))
|
||||
routes.post('/password/change', (req, res, next) => authController.changePassword(req, res, next))
|
||||
routes.get('/uploads', (req, res, next) => uploadController.list(req, res, next))
|
||||
routes.get('/uploads/:page', (req, res, next) => uploadController.list(req, res, next))
|
||||
routes.post('/upload', (req, res, next) => uploadController.upload(req, res, next))
|
||||
routes.post('/upload/delete', (req, res, next) => uploadController.delete(req, res, next))
|
||||
routes.post('/upload/:albumid', (req, res, next) => uploadController.upload(req, res, next))
|
||||
routes.get('/album/get/:identifier', (req, res, next) => albumsController.get(req, res, next))
|
||||
routes.get('/album/zip/:identifier', (req, res, next) => albumsController.generateZip(req, res, next))
|
||||
routes.get('/album/:id', (req, res, next) => uploadController.list(req, res, next))
|
||||
routes.get('/album/:id/:page', (req, res, next) => uploadController.list(req, res, next))
|
||||
routes.get('/albums', (req, res, next) => albumsController.list(req, res, next))
|
||||
routes.get('/albums/:sidebar', (req, res, next) => albumsController.list(req, res, next))
|
||||
routes.post('/albums', (req, res, next) => albumsController.create(req, res, next))
|
||||
routes.post('/albums/delete', (req, res, next) => albumsController.delete(req, res, next))
|
||||
routes.post('/albums/rename', (req, res, next) => albumsController.rename(req, res, next))
|
||||
routes.get('/albums/test', (req, res, next) => albumsController.test(req, res, next))
|
||||
routes.get('/tokens', (req, res, next) => tokenController.list(req, res, next))
|
||||
routes.post('/tokens/verify', (req, res, next) => tokenController.verify(req, res, next))
|
||||
routes.post('/tokens/change', (req, res, next) => tokenController.change(req, res, next))
|
||||
|
||||
module.exports = routes;
|
||||
module.exports = routes
|
||||
|
Loading…
Reference in New Issue
Block a user