new random key method
This commit is contained in:
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
<div class="center">
|
<div class="center">
|
||||||
Unique key:
|
Unique key:
|
||||||
<output id="key">- - - -</output>
|
<div id="key">- - - -</div>
|
||||||
<br/>
|
<br/>
|
||||||
<button id="keygen">Generate new key</button>
|
<button id="keygen">Generate new key</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
43
index.js
43
index.js
@@ -9,14 +9,20 @@ const mkdirp = require('mkdirp')
|
|||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const { spawn } = require('child_process')
|
const { spawn } = require('child_process')
|
||||||
|
|
||||||
const expireDelay = 20
|
|
||||||
const port = 3001
|
const port = 3001
|
||||||
|
const expireDelay = 20
|
||||||
const maxFileSize = 1024 * 1024 * 400
|
const maxFileSize = 1024 * 1024 * 400
|
||||||
const keyMin = 1000
|
|
||||||
const keyMax = 9999
|
|
||||||
|
|
||||||
function random(minimum, maximum) {
|
const keyChars = "123456789ACEFGHKLMNPRSTUVXYZ"
|
||||||
return Math.floor((Math.random() * (maximum - minimum + 1)) + minimum)
|
const keyLength = 4
|
||||||
|
|
||||||
|
function randomKey () {
|
||||||
|
const choices = Math.pow(keyChars.length, keyLength)
|
||||||
|
const rnd = Math.floor(Math.random() * choices)
|
||||||
|
|
||||||
|
return rnd.toString(keyChars.length).padStart(keyLength, '0').split('').map((chr) => {
|
||||||
|
return keyChars[parseInt(chr, keyChars.length)]
|
||||||
|
}).join('')
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeKey (key) {
|
function removeKey (key) {
|
||||||
@@ -49,14 +55,17 @@ function expireKey (key) {
|
|||||||
|
|
||||||
const app = new Koa()
|
const app = new Koa()
|
||||||
app.context.keys = new Map()
|
app.context.keys = new Map()
|
||||||
|
app.use(logger())
|
||||||
|
|
||||||
const router = new Router()
|
const router = new Router()
|
||||||
|
|
||||||
const upload = multer({
|
const upload = multer({
|
||||||
storage: multer.diskStorage({
|
storage: multer.diskStorage({
|
||||||
destination: function (req, file, cb) {
|
destination: function (req, file, cb) {
|
||||||
cb(null, 'uploads')
|
cb(null, 'uploads')
|
||||||
},
|
},
|
||||||
filename: function (req, file, cb) {
|
filename: function (req, file, cb) {
|
||||||
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9)
|
const uniqueSuffix = Date.now() + '-' + Math.floor(Math.random() * 1E9)
|
||||||
console.log(file)
|
console.log(file)
|
||||||
cb(null, file.fieldname + '-' + uniqueSuffix + '.epub')
|
cb(null, file.fieldname + '-' + uniqueSuffix + '.epub')
|
||||||
}
|
}
|
||||||
@@ -66,7 +75,7 @@ const upload = multer({
|
|||||||
files: 1
|
files: 1
|
||||||
},
|
},
|
||||||
fileFilter: (req, file, cb) => {
|
fileFilter: (req, file, cb) => {
|
||||||
const key = req.body.key
|
const key = req.body.key.toUpperCase()
|
||||||
if (!app.context.keys.has(key)) {
|
if (!app.context.keys.has(key)) {
|
||||||
console.error('FileFilter: Unknown key: ' + key)
|
console.error('FileFilter: Unknown key: ' + key)
|
||||||
cb(null, false)
|
cb(null, false)
|
||||||
@@ -90,7 +99,7 @@ router.get('/generate', async ctx => {
|
|||||||
let key = null
|
let key = null
|
||||||
let attempts = 0
|
let attempts = 0
|
||||||
do {
|
do {
|
||||||
key = random(keyMin, keyMax).toString()
|
key = randomKey()
|
||||||
console.log(attempts, ctx.keys.size, key)
|
console.log(attempts, ctx.keys.size, key)
|
||||||
if (attempts > ctx.keys.size) {
|
if (attempts > ctx.keys.size) {
|
||||||
console.error('Can\'t generate more keys, map is full.')
|
console.error('Can\'t generate more keys, map is full.')
|
||||||
@@ -113,7 +122,7 @@ router.get('/generate', async ctx => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
router.get('/download/:key', async ctx => {
|
router.get('/download/:key', async ctx => {
|
||||||
const key = ctx.params.key
|
const key = ctx.params.key.toUpperCase()
|
||||||
const info = ctx.keys.get(key)
|
const info = ctx.keys.get(key)
|
||||||
if (!info || !info.file) {
|
if (!info || !info.file) {
|
||||||
return
|
return
|
||||||
@@ -129,19 +138,19 @@ router.get('/download/:key', async ctx => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
router.post('/upload', upload.single('file'), async ctx => {
|
router.post('/upload', upload.single('file'), async ctx => {
|
||||||
const key = ctx.request.body.key
|
const key = ctx.request.body.key.toUpperCase()
|
||||||
|
|
||||||
if (!ctx.keys.has(key)) {
|
if (!ctx.keys.has(key)) {
|
||||||
ctx.throw(400, 'Unknown key: ' + key)
|
ctx.throw(400, 'Unknown key: ' + key)
|
||||||
}
|
}
|
||||||
|
if (!ctx.request.file || ctx.request.file.size === 0) {
|
||||||
|
console.error(ctx.request.file)
|
||||||
|
ctx.throw(400, 'Invalid or no file submitted')
|
||||||
|
}
|
||||||
if (!ctx.request.file.originalname.toLowerCase().endsWith('.epub')) {
|
if (!ctx.request.file.originalname.toLowerCase().endsWith('.epub')) {
|
||||||
ctx.throw(400, 'Uploaded file does not end with .epub ' + ctx.request.file.originalname)
|
ctx.throw(400, 'Uploaded file does not end with .epub ' + ctx.request.file.originalname)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ctx.request.file || ctx.request.file.size === 0) {
|
|
||||||
ctx.throw(400, 'Invalid or no file submitted')
|
|
||||||
}
|
|
||||||
|
|
||||||
let data = null
|
let data = null
|
||||||
let filename = ctx.request.file.originalname
|
let filename = ctx.request.file.originalname
|
||||||
|
|
||||||
@@ -189,7 +198,7 @@ router.post('/upload', upload.single('file'), async ctx => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
router.delete('/file/:key', async ctx => {
|
router.delete('/file/:key', async ctx => {
|
||||||
const key = ctx.params.key
|
const key = ctx.params.key.toUpperCase()
|
||||||
const info = ctx.keys.get(key)
|
const info = ctx.keys.get(key)
|
||||||
if (!info) {
|
if (!info) {
|
||||||
ctx.throw(400, 'Unknown key: ' + key)
|
ctx.throw(400, 'Unknown key: ' + key)
|
||||||
@@ -199,7 +208,7 @@ router.delete('/file/:key', async ctx => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
router.get('/status/:key', async ctx => {
|
router.get('/status/:key', async ctx => {
|
||||||
const key = ctx.params.key
|
const key = ctx.params.key.toUpperCase()
|
||||||
const info = ctx.keys.get(key)
|
const info = ctx.keys.get(key)
|
||||||
if (!info) {
|
if (!info) {
|
||||||
ctx.body = {error: 'Unknown key'}
|
ctx.body = {error: 'Unknown key'}
|
||||||
@@ -230,7 +239,7 @@ router.get('/', async ctx => {
|
|||||||
await sendfile(ctx, agent.includes('Kobo') ? 'download.html' : 'upload.html')
|
await sendfile(ctx, agent.includes('Kobo') ? 'download.html' : 'upload.html')
|
||||||
})
|
})
|
||||||
|
|
||||||
app.use(logger())
|
|
||||||
app.use(router.routes())
|
app.use(router.routes())
|
||||||
app.use(router.allowedMethods())
|
app.use(router.allowedMethods())
|
||||||
|
|
||||||
|
|||||||
12
style.css
12
style.css
@@ -9,10 +9,11 @@ h1 {
|
|||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
#key {
|
#key {
|
||||||
font-size: 3.5em;
|
font-size: 4.5em;
|
||||||
display: block;
|
display: block;
|
||||||
letter-spacing: 0.1em;
|
letter-spacing: 0.1em;
|
||||||
margin: 10px 0;
|
margin: 5px 0;
|
||||||
|
font-family: monospace;
|
||||||
}
|
}
|
||||||
.center {
|
.center {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@@ -41,8 +42,9 @@ h1 {
|
|||||||
|
|
||||||
|
|
||||||
#keyinput {
|
#keyinput {
|
||||||
font-size: 3.5em;
|
font-size: 4em;
|
||||||
width: 4em;
|
width: 3.5em;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-family: serif;
|
font-family: monospace;
|
||||||
|
letter-spacing: 0.1em;
|
||||||
}
|
}
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
<form action="/upload" method="post" enctype="multipart/form-data">
|
<form action="/upload" method="post" enctype="multipart/form-data">
|
||||||
<table style="margin: 0 auto;" cellpadding=10 cellspacing=0>
|
<table style="margin: 0 auto;" cellpadding=10 cellspacing=0>
|
||||||
<tr><td class="right">Unique key</td><td><input type="text" name="key" id="keyinput" autocomplete="off" inputmode="numeric" pattern="\d\d\d\d" placeholder="- - - -" required /></td></tr>
|
<tr><td class="right">Unique key</td><td><input type="text" name="key" id="keyinput" autocomplete="off" pattern="...." placeholder="----" required style="text-transform: uppercase;" maxlength=4/></td></tr>
|
||||||
<tr><td class="right">EPUB file</td><td><input type="file" name="file" accept=".epub,application/epub+zip" required /></td></tr>
|
<tr><td class="right">EPUB file</td><td><input type="file" name="file" accept=".epub,application/epub+zip" required /></td></tr>
|
||||||
<tr><td class="right"><label for="kepubify">Kepubify</label></td><td><input type="checkbox" name="kepubify" id="kepubify" checked /></td></tr>
|
<tr><td class="right"><label for="kepubify">Kepubify</label></td><td><input type="checkbox" name="kepubify" id="kepubify" checked /></td></tr>
|
||||||
<tr><td></td><td><input type="submit" value="Upload" /></td></tr>
|
<tr><td></td><td><input type="submit" value="Upload" /></td></tr>
|
||||||
@@ -21,7 +21,8 @@
|
|||||||
</form>
|
</form>
|
||||||
<br/>
|
<br/>
|
||||||
<div style="padding: 15px; text-align: justify;">
|
<div style="padding: 15px; text-align: justify;">
|
||||||
<p>Go this this page on your Kobo ereader and you see a unique key. Enter it in this form and upload an ebook and it will appear as a download link on the ereader. Your ebook will be stored on the server as long as the Kobo is viewing the unique key and is connected to wifi. It will be deleted when the key expires about 30 seconds after you close the browser/generate a new key/disable wifi on your Kobo.</p>
|
<p>Go this this page on your Kobo ereader and you see a unique key. Enter it in this form and upload an ebook and it will appear as a download link on the ereader.</p>
|
||||||
|
<p>Your ebook will be stored on the server as long as the Kobo is viewing the unique key and is connected to wifi. It will be deleted irrevocably when the key expires about 30 seconds after you close the browser, generate a new key or disable wifi on your Kobo.</p>
|
||||||
<p>By using this tool you agree that the ebook you upload is processed on the server and stored for a short time.</p>
|
<p>By using this tool you agree that the ebook you upload is processed on the server and stored for a short time.</p>
|
||||||
</div>
|
</div>
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|||||||
Reference in New Issue
Block a user