-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.js
More file actions
142 lines (113 loc) · 3.89 KB
/
Copy pathserver.js
File metadata and controls
142 lines (113 loc) · 3.89 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
require("dotenv").config()
const crypto = require("crypto")
const express = require("express")
const fileUpload = require("express-fileupload")
const fs = require("fs")
const nanoid = require("nanoid")
const path = require("path")
const app = express()
const algorithm = "aes-256-ctr"
const key = crypto.createHash("sha256").update(process.env.KEY).digest("base64").substr(0, 32)
// Set file upload limits
app.use(fileUpload({
limits: { fileSize: process.env.MAX_FILESIZE * 1024 * 1024, files: 1 },
}))
// Serve the public directory to page index
app.use(express.static("public"))
// receive uploaded files
app.post("/upload", async (req, res) => {
// if no files were uploaded, respond with "Invalid Request"
if (req.files == null || Object.keys(req.files).length === 0) {
return res.status(400).json({ error: "No file uploaded" })
}
let file = req.files.file
// check wether file was too big (user bypassed client validation)
// if it was too big, respond with "Invalid Request"
if (file.truncated) {
return res.status(400).json({ error: "File too big" })
}
// encrypt uploaded file
const encryptedBuffer = encryptFile(file.data)
// generate unique file name based on original file name
const uniqueFileName = nanoid(10)
// write encrypted file to disk
await writeFileToDisk(encryptedBuffer, uniqueFileName).catch(err => {
console.log(err)
return res.status(500).json({ error: "Internal server error" })
})
// respond with success and download url
res.status(200).json({ url: uniqueFileName })
})
app.get("/:id", async (req, res) => {
const id = req.params.id
let finish = true
// read encrypted file from disk
const encrypted = await readFileFromDisk(id).catch(err => {
console.log(err)
res.status(400).send()
finish = false
})
if (!finish) return
// TODO Read file info from database
const filename = "testfile.name"
const mimetype = "image.png"
// decrypt file
const decrypted = decryptFile(encrypted)
// set filename via content disposition header and send the file on its way
// set mimetype
res.status(200)
.set({
"Content-Disposition": `attatchment; filename="${filename}"`,
mimetype
})
.end(decrypted)
await deleteFileFromDisk(filename)
})
// encrypts a buffer using the aes256 algorithm
const encryptFile = buffer => {
// initializer
const init = crypto.randomBytes(16)
const cipher = crypto.createCipheriv(algorithm, key, init)
const result = Buffer.concat([init, cipher.update(buffer), cipher.final()])
return result
}
const decryptFile = buffer => {
// prep file
const init = buffer.slice(0, 16)
buffer = buffer.slice(16)
const decipher = crypto.createDecipheriv(algorithm, key, init)
const result = Buffer.concat([decipher.update(buffer), decipher.final()])
return result
}
const writeFileToDisk = (buffer, name) => {
return new Promise((resolve, reject) => {
fs.writeFile(path.join(process.env.FILEPATH, name), buffer, err => {
if (err != null) reject(err)
resolve()
})
})
}
const readFileFromDisk = name => {
return new Promise((resolve, reject) => {
fs.readFile(path.join(process.env.FILEPATH, name), (err, data) => {
if (err) reject(err)
resolve(data)
})
})
}
const deleteFileFromDisk = name => {
return new Promise((resolve) => {
fs.unlink(path.join(process.env.FILEPATH, name), () => {
resolve()
})
})
}
// create directory to upload files to if it doesn't exist
fs.mkdir(process.env.FILEPATH, err => {
if (err != null) {
console.error(`Did not create directory ${process.env.FILEPATH}. Directory already exists`)
}
})
app.listen(3000, () => {
console.log("Started webserver on port 3000")
})