1
0
Fork 0
mirror of https://github.com/alangrainger/immich-public-proxy.git synced 2025-01-15 04:26:45 +01:00

Expire asset decryption tokens

This commit is contained in:
Alan Grainger 2024-11-03 19:48:32 +01:00
parent f445844766
commit f78a02bb8d
4 changed files with 29 additions and 10 deletions

View file

@ -53,7 +53,7 @@ jobs:
build-args: |
PACKAGE_VERSION=${{ env.PACKAGE_VERSION }}
tags: |
${{ github.repository }}:latest
${{ github.repository }}:${{ env.PACKAGE_VERSION }}
ghcr.io/${{ github.repository }}:latest
${{ github.repository }}:latest
ghcr.io/${{ github.repository }}:${{ env.PACKAGE_VERSION }}
ghcr.io/${{ github.repository }}:latest

View file

@ -1,6 +1,6 @@
{
"name": "immich-public-proxy",
"version": "1.3.5",
"version": "1.3.6",
"scripts": {
"dev": "ts-node src/index.ts",
"build": "npx tsc",

View file

@ -187,7 +187,7 @@ class Immich {
photoUrl (key: string, id: string, size?: ImageSize, password?: string) {
const params = { key, size }
if (password) {
Object.assign(params, encrypt(password))
Object.assign(params, this.encryptPassword(password))
}
return this.buildUrl(`/photo/${key}/${id}`, params)
}
@ -196,7 +196,7 @@ class Immich {
* Return the video data URL for a video
*/
videoUrl (key: string, id: string, password?: string) {
const params = password ? encrypt(password) : {}
const params = password ? this.encryptPassword(password) : {}
return this.buildUrl(`/video/${key}/${id}`, params)
}
@ -215,6 +215,18 @@ class Immich {
isKey (key: string) {
return !!key.match(/^[\w-]+$/)
}
/**
* When loading assets from a password-protected link, make the decryption key valid for a
* short time. If the visitor loads the share link again, it will renew that expiry time.
* This prevents people from sharing the image links and bypassing password protection.
*/
encryptPassword (password: string) {
return encrypt(JSON.stringify({
password,
expires: dayjs().add(1, 'hour').format()
}))
}
}
const immich = new Immich()

View file

@ -37,13 +37,20 @@ app.get('/:type(photo|video)/:key/:id', async (req, res) => {
res.set('Cache-Control', 'public, max-age=' + process.env.CACHE_AGE)
// Check for valid key and ID
if (immich.isKey(req.params.key) && immich.isId(req.params.id)) {
// Decrypt the password, if one was provided
let password
// Validate the password payload, if one was provided
if (req.query?.cr && req.query?.iv) {
password = decrypt({
iv: toString(req.query.iv),
cr: toString(req.query.cr)
})
try {
const payload = JSON.parse(decrypt({
iv: toString(req.query.iv),
cr: toString(req.query.cr)
}))
if (payload?.expires && dayjs(payload.expires) > dayjs()) {
password = payload.password
} else {
log(`Attempted to load assets from ${req.params.key} with an expired decryption token`)
}
} catch (e) { }
}
// Check if the key is a valid share link
const sharedLink = (await immich.getShareByKey(req.params.key, password))?.link