diff --git a/backend/file.go b/backend/file.go index d45f5d0..5ac3e86 100644 --- a/backend/file.go +++ b/backend/file.go @@ -17,7 +17,7 @@ func FileHandler(w http.ResponseWriter, r *http.Request) { if r.URL.Path[0] != '/' { r.URL.Path = "/" + r.URL.Path } - fn := r.URL.Path[6:] + fn := r.URL.Path[6:] // skip /file/ if fn == "" { http.Error(w, "400 Bad Request: empty path", http.StatusBadRequest) return diff --git a/backend/paper.go b/backend/paper.go index cf0ca22..5a5faa9 100644 --- a/backend/paper.go +++ b/backend/paper.go @@ -22,8 +22,9 @@ const ( var analyzeper = ttl.NewCache[int, uint](time.Hour) var ( - errNoAnalyzePermission = errors.New("no analyze permission") - errNoDeletePermission = errors.New("no delete permission") + errNoAnalyzePermission = errors.New("no analyze permission") + errNoDeletePermission = errors.New("no delete permission") + errNoDownloadPermission = errors.New("no download permission") ) type filelist struct { @@ -229,23 +230,100 @@ func init() { } writeresult(w, codeSuccess, "删除成功", messageOk, typeSuccess) }} + apimap["/api/dlFile"] = &apihandler{"GET", func(w http.ResponseWriter, r *http.Request) { + token := r.Header.Get("Authorization") + user := usertokens.Get(token) + if user == nil { + writeresult(w, codeError, nil, errInvalidToken.Error(), typeError) + return + } + if !user.IsSuper() { + writeresult(w, codeError, nil, errNoDeletePermission.Error(), typeError) + return + } + idstr := r.URL.Query().Get("id") + if idstr == "" { + writeresult(w, codeError, nil, "empty id", typeError) + return + } + id, err := strconv.Atoi(idstr) + if err != nil { + writeresult(w, codeError, nil, err.Error(), typeError) + return + } + lst, err := global.FileDB.GetFileInfo(id) + if err != nil { + writeresult(w, codeError, nil, err.Error(), typeError) + return + } + type message struct { + URL string `json:"url"` + } + if strings.HasPrefix(lst.Path, global.PaperFolder+"tmp/") { + uidstr := lst.Path[17:] + i := strings.Index(uidstr, "/") + if i <= 0 { + writeresult(w, codeError, nil, "extract uid error", typeError) + return + } + uid, err := strconv.Atoi(uidstr[:i]) + if err != nil { + writeresult(w, codeError, nil, err.Error(), typeError) + return + } + if uid != *user.ID { + writeresult(w, codeError, nil, errNoDownloadPermission.Error(), typeError) + return + } + writeresult(w, codeSuccess, &message{URL: lst.Path[6:]}, messageOk, typeSuccess) + return + } + if strings.HasPrefix(lst.Path, global.PaperFolder) { + writeresult(w, codeSuccess, &message{URL: lst.Path[6:]}, messageOk, typeSuccess) + return + } + writeresult(w, codeError, nil, "parse filepath error", typeError) + }} } -// PaperHandler serves protected contents in global.FileFolder +// PaperHandler serves protected contents in global.PaperFolder func PaperHandler(w http.ResponseWriter, r *http.Request) { if !utils.IsMethod("GET", w, r) { return } + token := r.Header.Get("Authorization") + user := usertokens.Get(token) + if user == nil { + writeresult(w, codeError, nil, errInvalidToken.Error(), typeError) + return + } global.UserDB.VisitAPI() if r.URL.Path[0] != '/' { r.URL.Path = "/" + r.URL.Path } - fn := r.URL.Path[6:] + fn := r.URL.Path[7:] // skip /paper/ if fn == "" { http.Error(w, "400 Bad Request: empty path", http.StatusBadRequest) return } - name := global.FileFolder + fn - logrus.Infoln("[file.FileHandler] serve", name) + if strings.HasPrefix(fn, "tmp/") { + uidstr := fn[4:] + i := strings.Index(uidstr, "/") + if i <= 0 { + writeresult(w, codeError, nil, "extract uid error", typeError) + return + } + uid, err := strconv.Atoi(uidstr[:i]) + if err != nil { + writeresult(w, codeError, nil, err.Error(), typeError) + return + } + if uid != *user.ID { + writeresult(w, codeError, nil, errNoDownloadPermission.Error(), typeError) + return + } + } + name := global.PaperFolder + fn + logrus.Infoln("[file.PaperHandler] serve", name) http.ServeFile(w, r, name) } diff --git a/frontend/vben/.env.development b/frontend/vben/.env.development index ae9eea9..f2925ba 100644 --- a/frontend/vben/.env.development +++ b/frontend/vben/.env.development @@ -6,7 +6,7 @@ VITE_PUBLIC_PATH = / # Cross-domain proxy, you can configure multiple # Please note that no line breaks -VITE_PROXY = [["/api","http://localhost:3000/api"],["/file","http://localhost:3000/file"],["/upload","http://localhost:3000/upload"]] +VITE_PROXY = [["/api","http://localhost:3000/api"],["/file","http://localhost:3000/file"],["/upload","http://localhost:3000/upload"],["/paper","http://localhost:3000/paper"]] # VITE_PROXY=[["/api","https://vvbin.cn/test"]] # Delete console diff --git a/frontend/vben/mock/page/file.ts b/frontend/vben/mock/page/file.ts index 8aaa4f5..0588d9f 100644 --- a/frontend/vben/mock/page/file.ts +++ b/frontend/vben/mock/page/file.ts @@ -2,7 +2,7 @@ import { MockMethod } from 'vite-plugin-mock' import { resultError, resultSuccess, getRequestToken, requestParams } from '../_util' export default [ - { + /*{ url: '/api/dlFile', timeout: 1000, method: 'get', @@ -15,7 +15,7 @@ export default [ url: '/file/' + id + '.docx', }) }, - }, + },*/ { url: '/api/getFileStatus', timeout: 500, diff --git a/frontend/vben/mock/page/filelist.ts b/frontend/vben/mock/page/filelist.ts index 4dd2576..ea7962c 100644 --- a/frontend/vben/mock/page/filelist.ts +++ b/frontend/vben/mock/page/filelist.ts @@ -1,7 +1,7 @@ import { MockMethod } from 'vite-plugin-mock' -import { resultError, resultSuccess, getRequestToken, requestParams } from '../_util' +// import { resultError, resultSuccess, getRequestToken, requestParams } from '../_util' -const deletedIDs: number[] = [] +// const deletedIDs: number[] = [] // const analyzingIDs: { id: number; per: number }[] = [] diff --git a/frontend/vben/src/views/page/file/index.vue b/frontend/vben/src/views/page/file/index.vue index eefcdb9..95234ff 100644 --- a/frontend/vben/src/views/page/file/index.vue +++ b/frontend/vben/src/views/page/file/index.vue @@ -22,6 +22,7 @@ import { PageEnum } from '/@/enums/pageEnum' import { useI18n } from '/@/hooks/web/useI18n' import { downloadByData } from '/@/utils/file/download' + import { getToken } from '/@/utils/auth' import axios from 'axios' const { t } = useI18n() @@ -85,10 +86,12 @@ try { const ret = await downloadFile(Number(params.value.id)) if (ret && ret.url) { + const token = getToken() as string const { data } = await axios({ method: 'get', responseType: 'blob', url: ret.url, + headers: { Authorization: token }, }) if (data) { loadDocx(data)