Skip to content
Permalink
Browse files
Merge pull request #8 from georgiak/hashing-username-and-filename
Include hashed filename in download link
  • Loading branch information
czarniek committed Nov 27, 2019
2 parents 9e69b69 + 7cf99a8 commit e21ec17dae0158487f38f34801c4bd0e47ef3235
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 73 deletions.
@@ -37,7 +37,6 @@ app.use(views(`${__dirname}/views`, { extension: 'handlebars' }, {map: { handleb
const defaultPort = 8080
const port = process.env.PORT || defaultPort
const dbName = 'website.db'
const saltRounds = 10

/**
* The secure home page.
@@ -61,7 +60,7 @@ router.get('/', async ctx => {
// eslint-disable-next-line max-lines-per-function
router.get('/myfiles', async ctx => {
try {
if(ctx.session.authorised !== true) return ctx.redirect('/login?msg=you need to log in')
if(ctx.session.authorised !== true) return ctx.redirect('/login?msg=You need to log in')

await new File(dbName)
// await ctx.render('myfiles')
@@ -81,18 +80,13 @@ router.post('/myfiles', koaBody, async ctx => {
// extract the data from the request
const { path, type } = ctx.request.files._file
const extension = mime.extension(type)
const nameExt = ctx.request.files._file.name
const nameClean = nameExt.replace(`.${extension}`, '')
let name = ctx.request.files._file.name
name = name.replace(`.${extension}`, '')
const size = ctx.request.files._file.size
const date = ctx.request.files._file.lastModifiedDate
// eslint-disable-next-line prefer-template
const targetPath = '/' + userName + '/' + nameExt

const file = await new File(dbName)
await file.upload(extension, targetPath, nameClean, size, date)

//save to directory on server
await file.saveToDir(path, targetPath)
await file.upload(extension, name, size, date, userName, path)

ctx.redirect('/myfiles?msg=Your file has been uploaded!')
} catch (err) {
@@ -109,26 +103,6 @@ router.get('/shared', async ctx => {
}
})

router.get('/hashes', async ctx => {
try {
let hashed = ''
let query = undefined
if (ctx.query !== undefined && ctx.query.q !== undefined) {
query = ctx.query.q
hashed = Mailer.createHash(query)
}
let address = undefined
if (ctx.query !== undefined && ctx.query.a !== undefined) {
address = ctx.query.a
Mailer.sendMail(address, 'link')
}

await ctx.render('hashes', {text: hashed, query: query})
} catch (err) {
await ctx.render('error', { message: err.message })
}
})

router.get('/about', async ctx => {
try {
await ctx.render('AboutUs')
@@ -230,28 +204,34 @@ router.post('/transfer', koaBody, async ctx => {
const file = await new File(dbName)
//Generate the link to download page
const link = await file.generateLink(filename, userName, true)
console.log(`Download link: ${{link}}`)
console.log(`Download link: ${link}`)

//TODO: username passed in email
//Send the link in email
// await Mailer.sendMail(email, link, userMessage)

ctx.redirect('/myfiles?msg=Your file has been transfered!')

// return ctx.redirect('/?msg=you are now logged in...')
} catch (err) {
await ctx.render('error', { message: err.message })
}
})

router.get('/download/:usrName/:name', async ctx => {
try {
const fileName = ctx.params.name
let fileName = ctx.params.name
const userName = ctx.params.usrName

const file = await new File(dbName)

const fileData = await file.getFileInfo(fileName, userName)
console.log(fileData)
//generate link with a direct path to file
const link = await file.generateLink(fileName, userName, false)

await ctx.render('download', { link: link, name: userName, file: fileName})
fileName = `${fileData[0]['FileName']}.${fileData[0]['FileType']}`

await ctx.render('download', { link: link, file: fileName })
} catch (err) {
await ctx.render('error', { message: err.message })
}
@@ -16,7 +16,8 @@ const createHash = function(userString) {
}

const sendMail = function(toAddress, link, userMessage) {
const mailText = `A user decided to share a file with you! Here is the link: ${link}\n\nUser message: ${userMessage}`
const mailText = `A user decided to share a file with you!
Here is the link: ${link}\n\nUser message: ${userMessage}`

const transporter = nodemailer.createTransport({
service: 'gmail',
@@ -45,6 +46,6 @@ const sendMail = function(toAddress, link, userMessage) {

module.exports = {
sendMail,
createHash,
createHash
}

@@ -1,8 +1,8 @@

'use strict'
const fs = require('fs-extra')
const mime = require('mime-types')
const sqlite = require('sqlite-async')
const Mailer = require('./mailer')


module.exports = class File {
@@ -16,7 +16,7 @@ module.exports = class File {
}
const sql = `CREATE TABLE IF NOT EXISTS Files (
id INTEGER PRIMARY KEY AUTOINCREMENT, FileName TEXT, FileType BLOB,
FilePath TEXT, Size INT, Date TEXT);`
FilePath TEXT, Size INT, Date TEXT, FileHash TEXT);`
try{
await this.db.run(sql)
}catch(err) {
@@ -26,56 +26,66 @@ module.exports = class File {
})()
}


async upload(extension,filePath,_name,_size,_date) {
async upload(extension, _name,_size,_date, _userName, path) {
try{
// const extension = mime.extension(mimeType)
/* console.log(`path: ${path}`)
console.log(`extension: ${extension}`) */

const size = _size/1000
//_name = _name.replace(`.${extension}`, '')
// console.log(_name)

_date = _date.toString().slice(0,24)

const nameHash = Mailer.createHash(_name)

const nameExt = nameHash + '.' +extension

const sql = `INSERT INTO Files(Filename,FileType,FilePath,Size,Date)
VALUES( "${_name}","${extension}", "${filePath}", "${size}","${_date}")`

let targetPath = `/${ _userName }/${ nameExt}`

const sql = `INSERT INTO Files(FileName,FileType,FilePath,Size,Date,FileHash)
VALUES( "${_name}","${extension}", "${targetPath}", "${size}","${_date}","${nameHash}")`
await this.db.run(sql)

//save to directory on server
targetPath = 'private' + targetPath
await fs.copy(path, targetPath)
console.log('File saved on server')

return true
}catch(err) {
throw err
}

}

async saveToDir(path, targetPath) {

async generateLink(_fileName, username, fullLink) {
try {
// eslint-disable-next-line prefer-template
targetPath = 'private/' + targetPath
await fs.copy(path, targetPath)
console.log('File saved on server')
} catch(err) {
//TODO: Only search table belonging to specific user
const sql = `SELECT FilePath, FileHash FROM Files
WHERE FileName LIKE '${_fileName}' OR
FileHash LIKE '${_fileName}'`

const data = await this.db.all(sql)
let link = data[0]['FilePath']

if (fullLink) {
link = `http://localhost:8080/download/${ username}/${data[0]['FileHash']}`
}
return link

} catch (err) {
throw err
}
}

async generateLink(filename, username, fullLink) {
async getFileInfo(_fileName, _userName) {
try {
fullLink = false

//TODO: Only search table belonging to specific user
const sql = `SELECT FilePath FROM Files
WHERE FileName LIKE '${filename}'`
const sql = `SELECT * FROM Files
WHERE FileHash LIKE '${_fileName}'`

const data = await this.db.all(sql)
console.log(data)
let link = data[0]['FilePath']
console.log(link)

// eslint-disable-next-line prefer-template
if (fullLink) link = 'http://localhost:8080/download' + link

return link

return data

} catch (err) {
throw err
@@ -2,18 +2,20 @@
'use strict'

const bcrypt = require('bcrypt-promise')
const fs = require('fs-extra')
const mime = require('mime-types')
const sqlite = require('sqlite-async')
const saltRounds = 10
const Mailer = require('./mailer')


module.exports = class User {

constructor(dbName = ':memory:') {
return (async() => {
this.db = await sqlite.open(dbName)
// we need this table to store the user accounts
const sql = 'CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT, user TEXT, pass TEXT);'
const sql = `CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT,
user TEXT, userHash TEXT, pass TEXT);`
await this.db.run(sql)
return this
})()
@@ -27,7 +29,8 @@ module.exports = class User {
const data = await this.db.get(sql)
if(data.records !== 0) throw new Error(`username "${user}" already in use`)
pass = await bcrypt.hash(pass, saltRounds)
sql = `INSERT INTO users(user, pass) VALUES("${user}", "${pass}")`
const userHash = Mailer.createHash(user)
sql = `INSERT INTO users(user, userHash, pass) VALUES("${user}","${userHash}", "${pass}")`
await this.db.run(sql)
return true
} catch(err) {
@@ -48,10 +51,10 @@ module.exports = class User {
const records = await this.db.get(sql)
//TODO: redirect to login page with message and not error
if(!records.count) throw new Error(`username "${username}" not found`)
sql = `SELECT user, pass FROM users WHERE user = "${username}";`
sql = `SELECT user, userHash, pass FROM users WHERE user = "${username}";`
const record = await this.db.get(sql)
const valid = await bcrypt.compare(password, record.pass)
const userName = record.user
const userName = record.userHash
if(valid === false) throw new Error(`invalid password for account "${username}"`)
return userName

@@ -29,7 +29,7 @@

{{#if link}}
<p id='filename'>{{file}}</p>
<a href='{{link}}' class='bigButton' id='downloadButton' download>Download</a>
<a href='{{link}}' class='bigButton' id='downloadButton' download="{{file}}">Download</a>
{{else}}
<p>Something went wrong. Sorry!</p>
{{/if}}
@@ -5,7 +5,7 @@
<title>ERROR</title>
<meta name="description" content="The HTML5 Template">
<meta name="author" content="Joe Bloggs">
<link href="style.css" type="text/css" rel="stylesheet" />
<link href="login.css" type="text/css" rel="stylesheet" />
</head>
<body>
<h1>An Error Has Occurred</h1>

0 comments on commit e21ec17

Please sign in to comment.