Files
FileShare/server/web/dist/assets/HomeView-D38U_AAJ.js
T
SKYMirror 7f060dd0e4 26.9(安全审计修复版)
Go 1.27.1 (Gin+GORM) + Vue 3 文件快传服务:

- 安全审计全部修复(docs/security-audit-2026-09-05.md):
  bcrypt 密码哈希与自动升级、presign 直传服务端大小/内容校验、
  全局请求体上限、依赖升级(govulncheck 0 命中)、janitor 后台清理、
  管理端审计动作落库、/admin CORS 收紧、通知内容白名单净化、
  会话默认 7 天、限流缓存故障降级、robots.txt 端点等
- 前端:取件链接复制修复(不再重复拼接提取码)、markdown 净化器加固
- Redis 支持库号(FCB_REDIS_DB / redis://…/db URL)
- 文档:docs/api/* 与 openapi.yaml 同步最新行为(robots.txt、
  提码 5 位起、chunk 32MiB 上限、admin 审计动作等)

验证:gofmt/go vet/go test 全绿;二进制端到端冒烟通过
2026-09-05 04:22:41 +08:00

2 lines
15 KiB
JavaScript

import{d as W,u as Y,a as G,o as m,c as h,b as t,n as L,e as K,t as i,f as n,g as B,F as H,r as ne,h as $,E as q,_ as Z,i as ee,j as w,k as le,p as ae,l as se,w as O,m as ie,q as P,s as R,v as I,x as A,y as ue,z as re,A as ce,B as de,C as N,D as j,G as X,H as ve}from"./index-DYsKpclu.js";import{P as pe}from"./PageShell-D87JkPkG.js";import{s as me,a as he}from"./share-CqDDLJWI.js";import"./SiteNav.vue_vue_type_script_setup_true_lang-CwaEJKIZ.js";const fe={class:"field-row"},ye={class:"field-sub"},xe=["max","value"],be={class:"field-sub"},ke=["value"],_e=["value"],Se={key:0,class:"hint",style:{color:"var(--c-warn)"}},ge={key:1,class:"hint"},Ce={key:2,class:"hint"},$e={key:3,class:"hint"},ze=W({__name:"ExpirePicker",props:{value:{},style:{},compact:{type:Boolean}},emits:["update:value","update:style"],setup(a,{emit:e}){const o=a,c=e,{t:r,te:C}=Y(),f=G(),z=$(()=>{const g=f.expireStyle.length?f.expireStyle:["day","hour","minute","forever","count"],d=q.filter(x=>g.includes(x.value)),v=g.filter(x=>!q.some(E=>E.value===x)).map(x=>({value:x,label:x}));return[...d,...v]}),S=$(()=>o.style==="forever"),y=$(()=>o.style==="count"),p=$(()=>f.maxSaveCount>0?f.maxSaveCount:9999),b=$(()=>f.maxSaveSeconds>0?f.maxSaveSeconds:0),V={day:86400,hour:3600,minute:60};function u(g){const d=b.value,v=V[g];return v?d<=0?9999:Math.max(1,Math.floor(d/v)):g==="count"?p.value:9999}const l=$(()=>{if(y.value&&f.maxSaveCount>0&&o.value>f.maxSaveCount)return r("expire.maxCountHint",{n:f.maxSaveCount});if(!S.value&&!y.value&&b.value>0){const g=u(o.style);if(o.value>g){const d=q.find(v=>v.value===o.style)?.label??o.style;return r("expire.maxSecondsHint",{value:`${g} ${d}`})}}return""}),T=$(()=>q.find(g=>g.value===o.style)?.label??o.style);function M(g,d){const v=`expireStyle.${g}`;return C(v)?r(v):d}function F(g){const d=g.target.value;c("update:style",d),d==="count"&&o.value>p.value&&c("update:value",1),d==="minute"&&o.value<1&&c("update:value",10)}return(g,d)=>(m(),h(H,null,[t("div",fe,[S.value?B("",!0):(m(),h("label",{key:0,class:K(["expire-value",{compact:a.compact}]),style:L(a.compact?"flex:0 0 110px":"")},[t("span",ye,i(n(r)("expire.value")),1),t("input",{class:"input",type:"number",min:1,max:u(a.style),value:a.value,onInput:d[0]||(d[0]=v=>c("update:value",Math.max(1,Number(v.target.value)||1)))},null,40,xe)],6)),t("label",{style:L(S.value?"flex:1":"")},[t("span",be,i(n(r)("expire.label")),1),t("select",{class:"select",value:a.style,onChange:F},[(m(!0),h(H,null,ne(z.value,v=>(m(),h("option",{key:v.value,value:v.value},i(S.value&&v.value==="forever"?n(r)("expire.foreverOption"):v.value==="count"?n(r)("expire.countOption"):M(v.value,v.label)),9,_e))),128))],40,ke)],4)]),l.value?(m(),h("p",Se,i(l.value),1)):a.style==="count"?(m(),h("p",ge,i(n(r)("expire.countHint")),1)):S.value?(m(),h("p",$e,i(n(r)("expire.foreverHint")),1)):(m(),h("p",Ce,i(n(r)("expire.timeHint",{value:a.value,unit:T.value})),1))],64))}}),Q=Z(ze,[["__scopeId","data-v-d049fcf9"]]),we={class:"card result-card"},Te={class:"result-head"},Ve={class:"badge badge-success"},Ee={key:0,class:"result-name"},Me={class:"field"},Be=["title"],De={class:"field"},Fe={class:"link-row"},Pe=["value"],Ue={class:"result-meta"},Le={key:0},He={class:"hint",style:{"margin-top":"10px"}},Oe=W({__name:"ResultCard",props:{code:{},name:{},expireValue:{},expireStyle:{}},setup(a){const e=a,{t:o}=Y(),c=ee(),r=G(),C=w(null),f=$(()=>ae(e.code,r.shareLinkBase));async function z(y){const p=y==="link"?f.value:e.code;await le(p)?(C.value=y,c.success(o(y==="link"?"result.linkCopied":"result.codeCopied")),setTimeout(()=>C.value=null,1600)):c.error(o("result.copyFailed"))}const S=$(()=>e.expireStyle==="forever"?o("result.forever"):`${e.expireValue??"-"} ${se(e.expireStyle??"")}`);return(y,p)=>(m(),h("div",we,[t("div",Te,[t("span",Ve,i(n(o)("result.badge")),1),a.name?(m(),h("span",Ee,i(a.name),1)):B("",!0)]),t("div",Me,[t("label",null,i(n(o)("result.code")),1),t("button",{class:"code-display code-copy",type:"button",title:n(o)("result.clickCopyCode"),onClick:p[0]||(p[0]=b=>z("code"))},i(a.code),9,Be)]),t("div",De,[t("label",null,i(n(o)("result.link")),1),t("div",Fe,[t("input",{class:"input input-mono",value:f.value,readonly:"",onFocus:p[1]||(p[1]=b=>b.target.select())},null,40,Pe),t("button",{class:"btn btn-ghost",type:"button",onClick:p[2]||(p[2]=b=>z("link"))},i(C.value==="link"?n(o)("common.copied"):n(o)("result.copyLink")),1)])]),t("div",Ue,[a.expireStyle?(m(),h("span",Le,i(n(o)("result.expires",{value:S.value})),1)):B("",!0)]),t("p",He,i(n(o)("result.hint")),1)]))}}),Re=Z(Oe,[["__scopeId","data-v-8bebf3d9"]]),Ie=["aria-label"],Ae={class:"dz-main"},qe={class:"dz-sub"},Ne={key:1,class:"file-chip"},je={class:"fc-name"},Xe={class:"fc-size"},Ke=["title"],We={key:2,class:"hint",style:{color:"var(--c-danger)"}},Ye=["accept"],Ge=W({__name:"FileDrop",props:{modelValue:{},maxSize:{},disabled:{type:Boolean},acceptTypes:{}},emits:["update:modelValue"],setup(a,{emit:e}){const o=a,c=e,{t:r}=Y(),C=w(null),f=w(!1),z=w(""),S=$(()=>{const u=(o.acceptTypes??[]).map(l=>l.trim()).filter(Boolean);return!u.length||u.some(l=>l==="*"||l==="*/*")?"":u.map(l=>l.includes("/")||l.startsWith(".")?l:`.${l.toLowerCase()}`).join(",")}),y=$(()=>{const u=(o.acceptTypes??[]).filter(l=>l&&l!=="*"&&l!=="*/*");return u.length?r("drop.typeHint",{types:u.join(", ")}):""});function p(u){if(z.value="",!!u){if(o.maxSize&&u.size>o.maxSize){z.value=r("drop.tooLarge",{size:R(u.size),limit:R(o.maxSize)}),c("update:modelValue",null);return}c("update:modelValue",u)}}function b(u){f.value=!1,!o.disabled&&p(u.dataTransfer?.files?.[0])}function V(u){const l=u.target;p(l.files?.[0]),l.value=""}return(u,l)=>(m(),h("div",null,[a.modelValue?(m(),h("div",Ne,[l[6]||(l[6]=t("span",{"aria-hidden":"true"},"📄",-1)),t("span",je,i(a.modelValue.name),1),t("span",Xe,i(n(R)(a.modelValue.size)),1),t("button",{class:"fc-remove",type:"button",title:n(r)("drop.remove"),onClick:l[4]||(l[4]=T=>c("update:modelValue",null))},"✕",8,Ke)])):(m(),h("div",{key:0,class:K(["dropzone",{dragover:f.value,disabled:a.disabled}]),role:"button",tabindex:"0","aria-label":n(r)("drop.aria"),onClick:l[0]||(l[0]=T=>!a.disabled&&C.value?.click()),onKeydown:l[1]||(l[1]=ie(O(T=>!a.disabled&&C.value?.click(),["prevent"]),["enter"])),onDragover:l[2]||(l[2]=O(T=>f.value=!0,["prevent"])),onDragleave:l[3]||(l[3]=T=>f.value=!1),onDrop:O(b,["prevent"])},[l[5]||(l[5]=t("div",{class:"dz-icon","aria-hidden":"true"},"📦",-1)),t("div",Ae,i(n(r)("drop.zone")),1),t("div",qe,[a.maxSize?(m(),h(H,{key:0},[P(i(n(r)("drop.maxSize",{size:n(R)(a.maxSize)})),1)],64)):(m(),h(H,{key:1},[P(i(n(r)("drop.noLimit")),1)],64)),y.value?(m(),h(H,{key:2},[P(" · "+i(y.value),1)],64)):B("",!0)])],42,Ie)),z.value?(m(),h("p",We,i(z.value),1)):B("",!0),t("input",{ref_key:"inputRef",ref:C,type:"file",hidden:"",accept:S.value,onChange:V},null,40,Ye)]))}}),Ze=Z(Ge,[["__scopeId","data-v-1b57fe5c"]]);function Je(a,e,o,c){return I(A.chunkInit,{method:"POST",json:{file_name:a,file_size:e,chunk_size:o,file_hash:c},timeout:6e4})}async function Qe(a,e,o){const c=new FormData;c.append("upload_id",a),c.append("chunk_index",String(e)),c.append("chunk",o,`chunk-${e}`),await I(A.chunkUpload(a,e),{method:"POST",formData:c,timeout:12e4})}function et(a){return I(A.chunkStatus(a),{timeout:6e4})}function tt(a,e,o,c=""){return I(A.chunkFinish(a),{method:"POST",json:{expire_value:e,expire_style:o,code:c},timeout:3e5})}async function ot(a){await I(A.chunkCancel(a),{method:"DELETE",timeout:6e4})}function nt(a){return a<=10*1024*1024?{chunkSize:1*1024*1024,concurrency:3}:a<=100*1024*1024?{chunkSize:5*1024*1024,concurrency:3}:a<=512*1024*1024?{chunkSize:10*1024*1024,concurrency:2}:{chunkSize:20*1024*1024,concurrency:2}}function lt(a,e){const{file:o,expireValue:c,expireStyle:r,customCode:C,onProgress:f}=a;let z=!1;return{promise:(async()=>{const y=nt(o.size),p=Math.max(1,Math.ceil(o.size/y.chunkSize));let b;try{b=await ue(await o.arrayBuffer())}catch{b=`nofp-${o.size}-${o.lastModified}`}const V=await e.init(o.name,o.size,y.chunkSize,b),u=V.upload_id,l=V.chunk_size||y.chunkSize,T=V.total_chunks||p,M=new Set(V.uploaded_chunks??[]),F=()=>{if(!f)return;let x=0;for(const E of M){const D=E*l;x+=Math.max(0,Math.min(l,o.size-D))}f(Math.min(100,Math.round(x/o.size*100)),x,o.size)};F();const g=async x=>{for(let E=0;E<2;E++)try{const D=x*l,U=o.slice(D,Math.min(D+l,o.size));await e.uploadOne(u,x,U),M.add(x),F();return}catch(D){if(E===1)throw D}};let d=0;const v=async()=>{for(;!z;){const x=d++;if(x>=T)return;M.has(x)||await g(x)}};if(await Promise.all(Array.from({length:y.concurrency},()=>v())),z)throw await e.cancel(u).catch(()=>{}),new DOMException("上传已取消","AbortError");if(M.size<T){const x=await e.status(u);for(const E of x.uploaded_chunks??[])M.add(E)}return e.finish(u,c,r,C)})(),cancel:()=>z=!0}}const at={class:"hero"},st=["placeholder"],it={class:"btn",type:"submit"},ut={class:"card share-card"},rt={class:"tabs",role:"tablist"},ct={class:"field"},dt=["placeholder"],vt={class:"field"},pt={for:"share-custom-code"},mt=["placeholder"],ht={class:"field"},ft=["disabled"],yt={key:0,class:"spin","aria-hidden":"true"},xt={class:"field"},bt={class:"field"},kt={class:"field"},_t={for:"share-custom-code-file"},St=["placeholder"],gt={key:0,class:"field"},Ct={class:"progress"},$t={class:"hint"},zt=["disabled"],wt={key:0,class:"spin","aria-hidden":"true"},Tt={key:1,class:"empty"},Vt={key:2,style:{"margin-top":"18px"}},Et=222*1024,Pt=W({__name:"HomeView",setup(a){const{t:e}=Y(),o=de(),c=G(),r=ee(),C=w("text"),f=w("");function z(){const k=f.value.trim();if(!k){r.error(e("home.pickupRequired"));return}o.push({name:"pickup",params:{code:k}})}const S=w(1),y=w("day"),p=w(!1),b=w(null);function V(k,s){return k instanceof ve?k.code===423?e("home.rateLimited"):k.code===428?e("home.notInitialized"):k.msg||s:s}const u=w(""),l=/^[A-Za-z0-9]{4,8}$/,T=w(""),M=$(()=>new TextEncoder().encode(T.value).length),F=$(()=>M.value>Et);async function g(){const k=T.value;if(!k.trim()){r.error(e("home.textRequired"));return}if(F.value){r.error(e("home.textTooLong"));return}if(u.value.trim()&&!l.test(u.value.trim())){r.error(e("home.customCodeInvalid"));return}p.value=!0;try{const s=await me(k,S.value,y.value,u.value.trim());b.value={code:s.code},r.success(e("home.textShared"))}catch(s){r.error(V(s,e("home.shareFailed")))}finally{p.value=!1}}const d=w(null),v=w(null),x=w(null),E=$(()=>c.openUpload),D=$(()=>!!(d.value&&c.enableChunk&&d.value.size>8*1024*1024)),U=$(()=>c.effectiveMaxFileSize);async function te(){if(!d.value){r.error(e("home.fileRequired"));return}if(U.value&&d.value.size>U.value){r.error(e("home.fileTooLarge",{size:R(U.value)}));return}p.value=!0,v.value=0,b.value=null;try{if(u.value.trim()&&!l.test(u.value.trim())){r.error(e("home.customCodeInvalid"));return}if(D.value){const k=lt({file:d.value,expireValue:S.value,expireStyle:y.value,customCode:u.value.trim(),onProgress:_=>v.value=_},{init:Je,uploadOne:Qe,status:et,finish:tt,cancel:ot});x.value=k;const s=await k.promise;b.value={code:s.code,name:s.name}}else{const k=await he(d.value,S.value,y.value,s=>v.value=s,u.value.trim());b.value={code:k.code,name:k.name||d.value.name}}r.success(e("home.fileShared")),d.value=null}catch(k){k instanceof DOMException&&k.name==="AbortError"?r.info(e("home.uploadCancelled")):r.error(V(k,e("home.uploadFailed")))}finally{p.value=!1,v.value=null,x.value=null}}function oe(){x.value?.cancel()}function J(k){C.value=k,b.value=null,v.value=null}return(k,s)=>(m(),re(pe,null,{default:ce(()=>[t("section",at,[t("h1",null,i(n(e)("home.heroTitle",{name:n(c).displayName})),1),t("p",null,i(n(c).description||n(e)("home.heroDesc")),1),t("form",{class:"quick-pickup",onSubmit:O(z,["prevent"])},[N(t("input",{"onUpdate:modelValue":s[0]||(s[0]=_=>f.value=_),class:"input",placeholder:n(e)("home.pickupPlaceholder"),maxlength:"32",autocomplete:"off"},null,8,st),[[j,f.value]]),t("button",it,i(n(e)("home.pickupButton")),1)],32)]),t("section",ut,[t("div",rt,[t("button",{class:K(["tab",{active:C.value==="text"}]),type:"button",role:"tab",onClick:s[1]||(s[1]=_=>J("text"))},i(n(e)("home.tabText")),3),t("button",{class:K(["tab",{active:C.value==="file"}]),type:"button",role:"tab",onClick:s[2]||(s[2]=_=>J("file"))},i(n(e)("home.tabFile")),3)]),C.value==="text"?(m(),h("form",{key:0,style:{"margin-top":"18px"},onSubmit:O(g,["prevent"])},[t("div",ct,[t("label",null,i(n(e)("home.textContent")),1),N(t("textarea",{"onUpdate:modelValue":s[3]||(s[3]=_=>T.value=_),class:"textarea",placeholder:n(e)("home.textPlaceholder"),spellcheck:"false"},null,8,dt),[[j,T.value]]),t("p",{class:"hint",style:L(F.value?"color: var(--c-danger)":"")},i(n(e)("home.textBytes",{bytes:M.value.toLocaleString()})),5)]),t("div",vt,[t("label",pt,i(n(e)("home.customCode")),1),N(t("input",{id:"share-custom-code","onUpdate:modelValue":s[4]||(s[4]=_=>u.value=_),class:"input input-mono",placeholder:n(e)("home.customCodeHint"),maxlength:"8",autocomplete:"off"},null,8,mt),[[j,u.value]])]),t("div",ht,[X(Q,{value:S.value,"onUpdate:value":s[5]||(s[5]=_=>S.value=_),style:L(y.value),"onUpdate:style":s[6]||(s[6]=_=>y.value=_)},null,8,["value","style"])]),t("button",{class:"btn btn-block",type:"submit",disabled:p.value||F.value},[p.value?(m(),h("span",yt)):B("",!0),P(" "+i(n(e)("home.generateCode")),1)],8,ft)],32)):(m(),h("form",{key:1,style:{"margin-top":"18px"},onSubmit:O(te,["prevent"])},[E.value?(m(),h(H,{key:0},[t("div",xt,[X(Ze,{modelValue:d.value,"onUpdate:modelValue":s[7]||(s[7]=_=>d.value=_),"max-size":U.value||void 0,"accept-types":n(c).allowedFileTypes,disabled:p.value},null,8,["modelValue","max-size","accept-types","disabled"])]),t("div",bt,[t("div",kt,[t("label",_t,i(n(e)("home.customCode")),1),N(t("input",{id:"share-custom-code-file","onUpdate:modelValue":s[8]||(s[8]=_=>u.value=_),class:"input input-mono",placeholder:n(e)("home.customCodeHint"),maxlength:"8",autocomplete:"off"},null,8,St),[[j,u.value]])]),X(Q,{value:S.value,"onUpdate:value":s[9]||(s[9]=_=>S.value=_),style:L(y.value),"onUpdate:style":s[10]||(s[10]=_=>y.value=_)},null,8,["value","style"])]),v.value!==null?(m(),h("div",gt,[t("div",Ct,[t("i",{style:L({width:`${v.value}%`})},null,4)]),t("p",$t,[P(i(D.value?n(e)("home.chunkedUploading"):n(e)("home.uploading"))+" "+i(v.value)+"% ",1),p.value?(m(),h("button",{key:0,class:"btn btn-ghost btn-sm",type:"button",style:{"margin-left":"8px"},onClick:oe},i(n(e)("common.cancel")),1)):B("",!0)])])):B("",!0),t("button",{class:"btn btn-block",type:"submit",disabled:p.value||!d.value},[p.value?(m(),h("span",wt)):B("",!0),P(" "+i(p.value?n(e)("home.uploadingDots"):n(e)("home.uploadAndShare")),1)],8,zt)],64)):(m(),h("div",Tt,[s[12]||(s[12]=t("div",{class:"empty-icon"},"🚫",-1)),P(" "+i(n(e)("home.uploadDisabled")),1)]))],32)),b.value?(m(),h("div",Vt,[X(Re,{code:b.value.code,name:b.value.name,"expire-value":S.value,"expire-style":y.value},null,8,["code","name","expire-value","expire-style"]),t("button",{class:"btn btn-ghost btn-block",type:"button",style:{"margin-top":"12px"},onClick:s[11]||(s[11]=_=>b.value=null)},i(n(e)("home.shareAnother")),1)])):B("",!0)])]),_:1}))}});export{Pt as default};