File upload frontpage and download decryption

This commit is contained in:
2025-07-26 03:11:42 +08:00
parent 0486c0d0e5
commit f1867e7916
19 changed files with 1051 additions and 229 deletions

View File

@@ -14,29 +14,78 @@
</span>
</p>
</n-card>
<n-card class="max-w-2xl" v-else>
<dashboard
:uppy="uppy"
:props="{ theme: 'auto', height: '28rem', proudlyDisplayPoweredByUppy: false }"
/>
<n-card class="max-w-2xl" title="Upload to Solar Network" v-else>
<template #header-extra>
<div class="flex gap-2 items-center">
<p>Advance Mode</p>
<n-switch v-model:value="modeAdvanced" size="small" />
</div>
</template>
<div class="mb-3" v-if="modeAdvanced">
<n-input
v-model:value="filePass"
placeholder="Enter password to protect the file"
clearable
size="large"
type="password"
class="mb-2"
/>
</div>
<n-upload
multiple
directory-dnd
with-credentials
show-preview-button
list-type="image"
:custom-request="customRequest"
:create-thumbnail-url="createThumbnailUrl"
>
<n-upload-dragger>
<div style="margin-bottom: 12px">
<n-icon size="48" :depth="3">
<upload-outlined />
</n-icon>
</div>
<n-text style="font-size: 16px"> Click or drag a file to this area to upload </n-text>
<n-p depth="3" style="margin: 8px 0 0 0">
Strictly prohibit from uploading sensitive information. For example, your bank card PIN
or your credit card expiry date.
</n-p>
</n-upload-dragger>
</n-upload>
<p class="mt-4 opacity-75 text-xs">
<span v-if="version == null">Loading...</span>
<span v-else>
v{{ version.version }} @
{{ version.commit.substring(0, 6) }}
{{ version.updatedAt }}
</span>
</p>
</n-card>
</section>
</template>
<script setup lang="ts">
import { useUserStore } from '@/stores/user'
import { NCard } from 'naive-ui'
import {
NCard,
NUpload,
NUploadDragger,
NIcon,
NText,
NP,
NInput,
NSwitch,
type UploadCustomRequestOptions,
type UploadSettledFileInfo,
} from 'naive-ui'
import { onMounted, ref } from 'vue'
import { Dashboard } from '@uppy/vue'
import { UploadOutlined } from '@vicons/material'
import { useUserStore } from '@/stores/user'
import Uppy from '@uppy/core'
import Tus from '@uppy/tus'
import '@uppy/core/dist/style.min.css'
import '@uppy/dashboard/dist/style.min.css'
const uppy = new Uppy()
uppy.use(Tus, { endpoint: '/api/tus' })
import * as tus from 'tus-js-client'
const userStore = useUserStore()
@@ -48,8 +97,62 @@ async function fetchVersion() {
}
onMounted(() => fetchVersion())
</script>
<style scoped>
/* Add any specific styles here if needed, though Tailwind should handle most. */
</style>
const modeAdvanced = ref(false)
const filePass = ref<string>('')
function customRequest({
file,
data,
headers,
withCredentials,
action,
onFinish,
onError,
onProgress,
}: UploadCustomRequestOptions) {
const upload = new tus.Upload(file.file, {
endpoint: '/api/tus',
retryDelays: [0, 3000, 5000, 10000, 20000],
metadata: {
filename: file.name,
filetype: file.type ?? 'application/octet-stream',
},
headers: {
'X-FilePass': filePass.value,
...headers,
},
onError: function (error) {
console.error('[DRIVE] Upload failed:', error)
onError()
},
onProgress: function (bytesUploaded, bytesTotal) {
onProgress({ percent: (bytesUploaded / bytesTotal) * 100 })
},
onSuccess: function (payload) {
const rawInfo = payload.lastResponse.getHeader('x-fileinfo')
const jsonInfo = JSON.parse(rawInfo as string)
console.log('[DRIVE] Upload successful: ', jsonInfo)
file.url = `/api/files/${jsonInfo.id}`
file.type = jsonInfo.mime_type
onFinish()
},
onBeforeRequest: function (req) {
const xhr = req.getUnderlyingObject()
xhr.withCredentials = withCredentials
},
})
upload.findPreviousUploads().then(function (previousUploads) {
if (previousUploads.length) {
upload.resumeFromPreviousUpload(previousUploads[0])
}
upload.start()
})
}
function createThumbnailUrl(_file: File | null, fileInfo: UploadSettledFileInfo): string | undefined {
if (!fileInfo) return undefined
return fileInfo.url ?? undefined
}
</script>