From cf9903e500592e85a16b57b244dda271d223a1f4 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Sat, 26 Jul 2025 15:17:01 +0800 Subject: [PATCH] :sparkles: Sharable file --- DysonNetwork.Drive/Client/.gitignore | 2 +- DysonNetwork.Drive/Client/index.html | 2 +- DysonNetwork.Drive/Client/public/favicon.png | Bin 0 -> 71375 bytes DysonNetwork.Drive/Client/src/views/files.vue | 38 ++++++- DysonNetwork.Drive/Client/src/views/index.vue | 19 +++- DysonNetwork.Drive/Client/src/views/secure.ts | 102 +++++++++--------- DysonNetwork.Drive/Storage/FileService.cs | 31 ++++-- DysonNetwork.Drive/package.json | 5 - 8 files changed, 127 insertions(+), 72 deletions(-) create mode 100755 DysonNetwork.Drive/Client/public/favicon.png delete mode 100644 DysonNetwork.Drive/package.json diff --git a/DysonNetwork.Drive/Client/.gitignore b/DysonNetwork.Drive/Client/.gitignore index f6ab678..20c3f25 100644 --- a/DysonNetwork.Drive/Client/.gitignore +++ b/DysonNetwork.Drive/Client/.gitignore @@ -8,7 +8,7 @@ pnpm-debug.log* lerna-debug.log* node_modules -node_modules/highlight.js +**/node_modules/highlight.js/ .DS_Store dist dist-ssr diff --git a/DysonNetwork.Drive/Client/index.html b/DysonNetwork.Drive/Client/index.html index 0b35782..29edca9 100644 --- a/DysonNetwork.Drive/Client/index.html +++ b/DysonNetwork.Drive/Client/index.html @@ -2,7 +2,7 @@ - + Solar Network Drive diff --git a/DysonNetwork.Drive/Client/public/favicon.png b/DysonNetwork.Drive/Client/public/favicon.png new file mode 100755 index 0000000000000000000000000000000000000000..0eeb8c11185064aeed6a0a0696e691d3ea92530a GIT binary patch literal 71375 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
- + +
@@ -83,7 +84,25 @@ v-model:value="filePass" type="password" /> - Download +
+ Download + + + + +
@@ -109,9 +128,17 @@ import { NCode, NGrid, NGi, + NPopover, + NQrCode, useMessage, } from 'naive-ui' -import { DataUsageRound, InfoRound, DetailsRound, FileUploadOutlined } from '@vicons/material' +import { + DataUsageRound, + InfoRound, + DetailsRound, + FileUploadOutlined, + QrCodeRound, +} from '@vicons/material' import { useRoute } from 'vue-router' import { computed, onMounted, ref } from 'vue' @@ -135,6 +162,8 @@ const showTechDetails = ref(false) const messageDisplay = useMessage() +const currentUrl = window.location.href + const fileInfo = ref(null) async function fetchFileInfo() { try { @@ -161,10 +190,11 @@ function downloadFile() { return } if (fileInfo.value.is_encrypted) { - downloadAndDecryptFile(fileSource.value, filePass.value, (p: number) => { + downloadAndDecryptFile(fileSource.value, filePass.value, fileInfo.value.name, (p: number) => { progress.value = p * 100 }).catch((err) => { messageDisplay.error('Download failed: ' + err.message, { closable: true, duration: 10000 }) + progress.value = undefined }) } else { window.open(fileSource.value, '_blank') diff --git a/DysonNetwork.Drive/Client/src/views/index.vue b/DysonNetwork.Drive/Client/src/views/index.vue index 6d694ab..fd02bf1 100644 --- a/DysonNetwork.Drive/Client/src/views/index.vue +++ b/DysonNetwork.Drive/Client/src/views/index.vue @@ -60,8 +60,11 @@ with-credentials show-preview-button list-type="image" + show-download-button :custom-request="customRequest" + :custom-download="customDownload" :create-thumbnail-url="createThumbnailUrl" + @preview="customPreview" >
@@ -102,11 +105,11 @@ import { NSelect, NTag, NCollapseTransition, - NFormItem, type UploadCustomRequestOptions, type UploadSettledFileInfo, type SelectOption, type SelectRenderTag, + type UploadFileInfo, } from 'naive-ui' import { computed, h, onMounted, ref } from 'vue' import { CloudUploadRound } from '@vicons/material' @@ -283,4 +286,18 @@ function createThumbnailUrl( if (!fileInfo) return undefined return fileInfo.url ?? undefined } + +function customDownload(file: UploadFileInfo) { + const { url, name } = file + if (!url) + return + window.open(url.replace('/api', ''), '_blank') +} + +function customPreview(file: UploadFileInfo, detail: { event: MouseEvent }) { + detail.event.preventDefault() + const { url, type } = file + if (!url) return + window.open(url.replace('/api', ''), '_blank') +} diff --git a/DysonNetwork.Drive/Client/src/views/secure.ts b/DysonNetwork.Drive/Client/src/views/secure.ts index 5a4109c..1d8a352 100644 --- a/DysonNetwork.Drive/Client/src/views/secure.ts +++ b/DysonNetwork.Drive/Client/src/views/secure.ts @@ -1,92 +1,94 @@ export async function downloadAndDecryptFile( url: string, password: string, - onProgress?: (progress: number) => void + fileName: string, + onProgress?: (progress: number) => void, ): Promise { - const response = await fetch(url); - if (!response.ok) throw new Error(`Failed to fetch: ${response.status}`); + const response = await fetch(url) + if (!response.ok) throw new Error(`Failed to fetch: ${response.status}`) - const contentLength = +(response.headers.get('Content-Length') || 0); - const reader = response.body!.getReader(); - const chunks: Uint8Array[] = []; - let received = 0; + const contentLength = +(response.headers.get('Content-Length') || 0) + const reader = response.body!.getReader() + const chunks: Uint8Array[] = [] + let received = 0 while (true) { - const { done, value } = await reader.read(); - if (done) break; + const { done, value } = await reader.read() + if (done) break if (value) { - chunks.push(value); - received += value.length; + chunks.push(value) + received += value.length if (contentLength && onProgress) { - onProgress(received / contentLength); + onProgress(received / contentLength) } } } - const fullBuffer = new Uint8Array(received); - let offset = 0; + const fullBuffer = new Uint8Array(received) + let offset = 0 for (const chunk of chunks) { - fullBuffer.set(chunk, offset); - offset += chunk.length; + fullBuffer.set(chunk, offset) + offset += chunk.length } - const decryptedBytes = await decryptFile(fullBuffer, password); + const decryptedBytes = await decryptFile(fullBuffer, password) // Create a blob and trigger a download - const blob = new Blob([decryptedBytes]); - const downloadUrl = URL.createObjectURL(blob); - const a = document.createElement('a'); - a.href = downloadUrl; - a.download = 'decrypted_file'; // You may allow customization - document.body.appendChild(a); - a.click(); - a.remove(); - URL.revokeObjectURL(downloadUrl); + const blob = new Blob([decryptedBytes]) + const downloadUrl = URL.createObjectURL(blob) + const a = document.createElement('a') + a.href = downloadUrl + a.download = fileName + document.body.appendChild(a) + a.click() + a.remove() + URL.revokeObjectURL(downloadUrl) } -export async function decryptFile( - fileBuffer: Uint8Array, - password: string -): Promise { - const salt = fileBuffer.slice(0, 16); - const nonce = fileBuffer.slice(16, 28); - const tag = fileBuffer.slice(28, 44); - const ciphertext = fileBuffer.slice(44); +export async function decryptFile(fileBuffer: Uint8Array, password: string): Promise { + const salt = fileBuffer.slice(0, 16) + const nonce = fileBuffer.slice(16, 28) + const tag = fileBuffer.slice(28, 44) + const ciphertext = fileBuffer.slice(44) - const enc = new TextEncoder(); + const enc = new TextEncoder() const keyMaterial = await crypto.subtle.importKey( - 'raw', enc.encode(password), { name: 'PBKDF2' }, false, ['deriveKey'] - ); + 'raw', + enc.encode(password), + { name: 'PBKDF2' }, + false, + ['deriveKey'], + ) const key = await crypto.subtle.deriveKey( { name: 'PBKDF2', salt, iterations: 100000, hash: 'SHA-256' }, keyMaterial, { name: 'AES-GCM', length: 256 }, false, - ['decrypt'] - ); + ['decrypt'], + ) - const fullCiphertext = new Uint8Array(ciphertext.length + tag.length); - fullCiphertext.set(ciphertext); - fullCiphertext.set(tag, ciphertext.length); + const fullCiphertext = new Uint8Array(ciphertext.length + tag.length) + fullCiphertext.set(ciphertext) + fullCiphertext.set(tag, ciphertext.length) - let decrypted: ArrayBuffer; + let decrypted: ArrayBuffer try { decrypted = await crypto.subtle.decrypt( { name: 'AES-GCM', iv: nonce, tagLength: 128 }, key, - fullCiphertext - ); + fullCiphertext, + ) } catch { - throw new Error("Incorrect password or corrupted file."); + throw new Error('Incorrect password or corrupted file.') } - const magic = new TextEncoder().encode("DYSON1"); - const decryptedBytes = new Uint8Array(decrypted); + const magic = new TextEncoder().encode('DYSON1') + const decryptedBytes = new Uint8Array(decrypted) for (let i = 0; i < magic.length; i++) { if (decryptedBytes[i] !== magic[i]) { - throw new Error("Incorrect password or corrupted file."); + throw new Error('Incorrect password or corrupted file.') } } - return decryptedBytes.slice(magic.length); + return decryptedBytes.slice(magic.length) } diff --git a/DysonNetwork.Drive/Storage/FileService.cs b/DysonNetwork.Drive/Storage/FileService.cs index 2c28282..a0b01bf 100644 --- a/DysonNetwork.Drive/Storage/FileService.cs +++ b/DysonNetwork.Drive/Storage/FileService.cs @@ -126,7 +126,7 @@ public class FileService( contentType = "application/octet-stream"; } - var hash = await HashFileAsync(stream, fileSize: fileSize); + var hash = await HashFileAsync(ogFilePath); var file = new CloudFile { @@ -136,7 +136,7 @@ public class FileService( Size = fileSize, Hash = hash, AccountId = Guid.Parse(account.Id), - IsEncrypted = !string.IsNullOrWhiteSpace(encryptPassword) + IsEncrypted = !string.IsNullOrWhiteSpace(encryptPassword) && pool.AllowEncryption }; var existingFile = await db.Files.AsNoTracking().FirstOrDefaultAsync(f => f.Hash == hash); @@ -274,7 +274,7 @@ public class FileService( } /// - /// Handles file optimization (image compression, video thumbnailing) and uploads to remote storage in the background. + /// Handles file optimization (image compression, video thumbnail) and uploads to remote storage in the background. /// private async Task ProcessAndUploadInBackgroundAsync( string fileId, @@ -350,15 +350,23 @@ public class FileService( var snapshotTime = mediaInfo.Duration > TimeSpan.FromSeconds(5) ? TimeSpan.FromSeconds(5) : TimeSpan.FromSeconds(1); + await FFMpeg.SnapshotAsync(originalFilePath, thumbnailPath, captureTime: snapshotTime); - uploads.Add((thumbnailPath, ".thumbnail.webp", "image/webp", true)); - hasThumbnail = true; + + if (File.Exists(thumbnailPath)) + { + uploads.Add((thumbnailPath, ".thumbnail.webp", "image/webp", true)); + hasThumbnail = true; + } + else + { + logger.LogWarning("FFMpeg did not produce thumbnail for video {FileId}", fileId); + } } catch (Exception ex) { logger.LogError(ex, "Failed to generate thumbnail for video {FileId}", fileId); } - break; default: @@ -405,11 +413,12 @@ public class FileService( } } - private static async Task HashFileAsync(Stream stream, int chunkSize = 1024 * 1024, long? fileSize = null) + private static async Task HashFileAsync(string filePath, int chunkSize = 1024 * 1024) { - fileSize ??= stream.Length; + using var stream = File.OpenRead(filePath); + var fileSize = stream.Length; if (fileSize > chunkSize * 1024 * 5) - return await HashFastApproximateAsync(stream, chunkSize); + return await HashFastApproximateAsync(filePath, chunkSize); using var md5 = MD5.Create(); var hashBytes = await md5.ComputeHashAsync(stream); @@ -417,8 +426,10 @@ public class FileService( return Convert.ToHexString(hashBytes).ToLowerInvariant(); } - private static async Task HashFastApproximateAsync(Stream stream, int chunkSize = 1024 * 1024) + private static async Task HashFastApproximateAsync(string filePath, int chunkSize = 1024 * 1024) { + await using var stream = File.OpenRead(filePath); + // Scale the chunk size to kB level chunkSize *= 1024; diff --git a/DysonNetwork.Drive/package.json b/DysonNetwork.Drive/package.json deleted file mode 100644 index 318dde6..0000000 --- a/DysonNetwork.Drive/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "dependencies": { - "highlight.js": "^11.11.1" - } -} \ No newline at end of file