feat: 文件權限檢驗
* 基於讀取 Cookie 中的驗證信息 * 因為 ServiceWorker 需要安全的上下文, 而我想要到處可用, 因此暫時折中使用這個辦法
This commit is contained in:
@@ -1,59 +0,0 @@
|
|||||||
import { Buffer } from "node:buffer"
|
|
||||||
import config from "../config.ts"
|
|
||||||
import User from "../data/User.ts"
|
|
||||||
import crypto from 'node:crypto'
|
|
||||||
import Token from "./Token.ts"
|
|
||||||
|
|
||||||
function normalizeKey(key: string, keyLength = 32) {
|
|
||||||
const hash = crypto.createHash('sha256')
|
|
||||||
hash.update(key)
|
|
||||||
const keyBuffer = hash.digest()
|
|
||||||
return keyLength ? keyBuffer.slice(0, keyLength) : keyBuffer
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class FileTokenManager {
|
|
||||||
static makeAuth(user: User) {
|
|
||||||
return crypto.createHash("sha256").update(user.bean.id + user.getPassword() + config.salt + '_file').digest().toString('hex')
|
|
||||||
}
|
|
||||||
static encode(token: Token) {
|
|
||||||
return crypto.createCipheriv("aes-256-gcm", normalizeKey(config.aes_key + '_file'), '01234567890123456').update(
|
|
||||||
JSON.stringify(token)
|
|
||||||
).toString('hex')
|
|
||||||
}
|
|
||||||
static decode(token: string) {
|
|
||||||
if (token == null) throw new Error('令牌為空!')
|
|
||||||
try {
|
|
||||||
return JSON.parse(crypto.createDecipheriv("aes-256-gcm", normalizeKey(config.aes_key + '_file'), '01234567890123456').update(
|
|
||||||
Buffer.from(token, 'hex')
|
|
||||||
).toString()) as Token
|
|
||||||
} catch(e) {
|
|
||||||
throw new Error('令牌無效!')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 簽發文件令牌
|
|
||||||
*/
|
|
||||||
static make(user: User, device_id: string) {
|
|
||||||
const time = Date.now()
|
|
||||||
return this.encode({
|
|
||||||
author: user.bean.id,
|
|
||||||
auth: this.makeAuth(user),
|
|
||||||
made_time: time,
|
|
||||||
// 過期時間: 2分鐘
|
|
||||||
expired_time: time + (1 * 1000 * 60 * 2),
|
|
||||||
device_id: device_id
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 校驗文件令牌
|
|
||||||
*/
|
|
||||||
static check(user: User, token: string) {
|
|
||||||
const tk = this.decode(token)
|
|
||||||
|
|
||||||
return (
|
|
||||||
this.makeAuth(user) == tk.auth
|
|
||||||
&& tk.expired_time < Date.now()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -11,21 +11,38 @@ import process from "node:process"
|
|||||||
import chalk from "chalk"
|
import chalk from "chalk"
|
||||||
import child_process from "node:child_process"
|
import child_process from "node:child_process"
|
||||||
import FileManager from "./data/FileManager.ts"
|
import FileManager from "./data/FileManager.ts"
|
||||||
|
import TokenManager from "./api/TokenManager.ts"
|
||||||
|
import UserChatLinker from "./data/UserChatLinker.ts"
|
||||||
import path from "node:path"
|
import path from "node:path"
|
||||||
|
import cookieParser from 'cookie-parser'
|
||||||
|
|
||||||
const app = express()
|
const app = express()
|
||||||
app.use('/', express.static(config.data_path + '/page_compiled'))
|
app.use('/', express.static(config.data_path + '/page_compiled'))
|
||||||
|
app.use(cookieParser())
|
||||||
app.get('/uploaded_files/:hash', (req, res) => {
|
app.get('/uploaded_files/:hash', (req, res) => {
|
||||||
const hash = req.params.hash as string
|
const hash = req.params.hash as string
|
||||||
|
res.setHeader('Content-Type', 'text/plain')
|
||||||
if (hash == null) {
|
if (hash == null) {
|
||||||
res.sendStatus(404)
|
res.send("404 Not Found", 404)
|
||||||
res.send("404 Not Found")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const file = FileManager.findByHash(hash)
|
const file = FileManager.findByHash(hash)
|
||||||
|
|
||||||
|
if (file.getChatId() != null) {
|
||||||
|
const userToken = TokenManager.decode(req.cookies.token)
|
||||||
|
console.log(userToken, req.cookies.device_id)
|
||||||
|
if (!TokenManager.checkToken(userToken, req.cookies.device_id)) {
|
||||||
|
res.send("401 UnAuthorized", 401)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!UserChatLinker.checkUserIsLinkedToChat(userToken.author, file.getChatId())) {
|
||||||
|
res.send("403 Forbidden", 403)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (file == null) {
|
if (file == null) {
|
||||||
res.sendStatus(404)
|
res.send("404 Not Found", 404)
|
||||||
res.send("404 Not Found")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user