Initial scaffold: blob store server, CLI scripts, and PWA share target
Clipboard/screenshot sync across own devices via a single DEVICE_TOKEN-gated blob store, plus a small installable web app so a phone can push/pull clips and share screenshots via the OS share sheet.
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
import { Router } from 'express'
|
||||
import fs from 'node:fs'
|
||||
import multer from 'multer'
|
||||
import { config } from './config.js'
|
||||
import { blobPath } from './db.js'
|
||||
import { newBlobId } from './ids.js'
|
||||
import { insertBlobRecord } from './blobs.js'
|
||||
import { timingSafeStringEqual } from './auth.js'
|
||||
|
||||
// Separate from routes.ts: the OS share sheet POSTs here directly (no
|
||||
// custom headers possible), so auth rides in the query string instead of
|
||||
// X-Device-Token — see manifest.ts for where that URL gets the token baked
|
||||
// in. Same trust level as the token in ~/.config/scrot/env: not a secret
|
||||
// from the machine it's on, just from the network.
|
||||
export const shareRouter = Router()
|
||||
|
||||
const upload = multer({ storage: multer.memoryStorage(), limits: { fileSize: config.maxUploadBytes } })
|
||||
|
||||
shareRouter.post('/share', upload.any(), (req, res) => {
|
||||
const token = typeof req.query.t === 'string' ? req.query.t : ''
|
||||
if (!timingSafeStringEqual(token, config.deviceToken)) {
|
||||
res.status(401).send('bad or missing device token — re-add scrot to your home screen to re-onboard')
|
||||
return
|
||||
}
|
||||
|
||||
const files = (req.files as Express.Multer.File[] | undefined) ?? []
|
||||
const image = files.find((f) => f.mimetype.startsWith('image/'))
|
||||
|
||||
if (image) {
|
||||
const id = newBlobId()
|
||||
fs.writeFileSync(blobPath(id), image.buffer)
|
||||
insertBlobRecord(id, 'shot', image.mimetype, image.buffer.length)
|
||||
res.redirect(303, `/?shared=shot&id=${id}`)
|
||||
return
|
||||
}
|
||||
|
||||
const body = req.body as Record<string, string>
|
||||
const text = (body.text || body.url || body.title || '').trim()
|
||||
if (text) {
|
||||
const id = newBlobId()
|
||||
const buf = Buffer.from(text, 'utf8')
|
||||
fs.writeFileSync(blobPath(id), buf)
|
||||
insertBlobRecord(id, 'clip', 'text/plain; charset=utf-8', buf.length)
|
||||
res.redirect(303, '/?shared=clip')
|
||||
return
|
||||
}
|
||||
|
||||
res.redirect(303, '/?shared=empty')
|
||||
})
|
||||
Reference in New Issue
Block a user