-
Notifications
You must be signed in to change notification settings - Fork 1
Add s3 #96
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add s3 #96
Changes from all commits
2d43e53
6738d8d
db73305
8592baa
be0c366
76f59f1
ec8907c
5f27d8a
d94d695
52476d3
7fe2a3a
4d5527b
b7d6b9d
e53459a
9102cb4
5a7367f
4e68b7f
2fa8835
e4405b1
dc3a765
6c8d855
8f37956
b9f31aa
a559496
f82eb34
637b8b1
5981090
8060e86
7658b5c
546c773
7b6aa83
badbb16
1011198
a87123f
1eb193d
e54624d
3149998
bdda8a2
a34d966
a85b80d
55cf60c
9028f8c
6aff3cf
cd25eae
109691b
af15a97
1540595
3aa2a5f
166a026
d698f08
cdd3c79
9425cf7
7e7822e
1745ceb
1e7ca35
2d34fb9
e245c01
d5f3a3e
1331ac2
9e79c58
dd31d93
1448a4c
45838b7
b0a3195
1546e77
778a2de
7dbbbe5
9c07f53
49c79bc
732fda8
90724af
3e22c41
caa44e7
e9c7d76
f762f4c
4f5c55a
354aa35
dbbcb9a
7963303
e3a681a
07c5fd5
74cdaf0
69f2998
1bd1c6e
27fe515
13f46ca
1db68a4
64324dc
3b0e239
7d52d82
57ab437
a89a44f
7436aff
6544595
075771d
041ee3d
91055dd
824547c
34c7087
6a71c2c
c4c9038
f196cb4
73eb368
0adbe11
51873f0
5ccefd5
7880d5a
e7a409b
5edf84c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| | ||
| <script src="~/lib/jquery/dist/jquery.min.js"></script> | ||
|
|
||
| <script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script> | ||
| <script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script> |
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,10 +1,16 @@ | ||||||||||||||||
| using Microsoft.AspNetCore.Authorization; | ||||||||||||||||
| using Amazon.S3; | ||||||||||||||||
| using Microsoft.AspNetCore.Authorization; | ||||||||||||||||
| using Microsoft.AspNetCore.Mvc; | ||||||||||||||||
| using Microsoft.AspNetCore.StaticFiles; | ||||||||||||||||
| using Refhub.Models.Enums; | ||||||||||||||||
| using Refhub.Service.Implement; | ||||||||||||||||
| using Refhub.Service.Interface; | ||||||||||||||||
| using Refhub.Tools.Exceptions; | ||||||||||||||||
| using Refhub.Tools.Static; | ||||||||||||||||
|
|
||||||||||||||||
| namespace Refhub.Controllers; | ||||||||||||||||
|
|
||||||||||||||||
| public class BookController(IBookService bookService) : Controller | ||||||||||||||||
| public class BookController(IBookService bookService, IFileUploaderService s3FileUploaderService, ILogger<BookController> logger, IMessageService messageService) : Controller | ||||||||||||||||
| { | ||||||||||||||||
| [HttpGet("BookDetails/{slug}")] | ||||||||||||||||
| public async Task<IActionResult> BookDetails(string slug, CancellationToken ct) | ||||||||||||||||
|
|
@@ -19,18 +25,49 @@ public async Task<IActionResult> BookDetails(string slug, CancellationToken ct) | |||||||||||||||
|
|
||||||||||||||||
| return bookDetails == null ? NotFound() : View(bookDetails); | ||||||||||||||||
| } | ||||||||||||||||
| private bool IsValidFileUrl(string fileUrl) | ||||||||||||||||
| { | ||||||||||||||||
| return !string.IsNullOrWhiteSpace(fileUrl) && Uri.TryCreate(fileUrl, UriKind.Absolute, out _); | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| [Authorize] | ||||||||||||||||
| [HttpGet] | ||||||||||||||||
| public async Task<IActionResult> DownloadFile(string filePath, CancellationToken ct) | ||||||||||||||||
| [HttpGet("download")] | ||||||||||||||||
| public async Task<IActionResult> DownloadFile([FromQuery] string fileUrl, CancellationToken ct) | ||||||||||||||||
| { | ||||||||||||||||
| filePath = Path.Combine(Directory.GetCurrentDirectory(), $"wwwroot{filePath}"); | ||||||||||||||||
| if (string.IsNullOrEmpty(filePath) || !System.IO.File.Exists(filePath)) | ||||||||||||||||
| try | ||||||||||||||||
| { | ||||||||||||||||
| return NotFound(); | ||||||||||||||||
| if (!IsValidFileUrl(fileUrl)) | ||||||||||||||||
| { | ||||||||||||||||
| return NotFound(messageService.Get("InvalidFileName")); | ||||||||||||||||
| } | ||||||||||||||||
|
Comment on lines
+39
to
+42
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||||||||||||
|
|
||||||||||||||||
|
|
||||||||||||||||
| // دریافت فایل از S3 | ||||||||||||||||
| var stream = await s3FileUploaderService.DownloadFileAsync(fileUrl, ct, BucketNameStatic.GetName(BucketNames.BookPdf)); | ||||||||||||||||
|
|
||||||||||||||||
| // The file name for the user should be extracted from the URL | ||||||||||||||||
| var fileName = Path.GetFileName(new Uri(fileUrl).AbsolutePath); | ||||||||||||||||
|
|
||||||||||||||||
| // تعیین نوع فایل با توجه به پسوند | ||||||||||||||||
| var contentTypeProvider = new FileExtensionContentTypeProvider(); | ||||||||||||||||
| if (!contentTypeProvider.TryGetContentType(fileName, out string contentType)) | ||||||||||||||||
| { | ||||||||||||||||
| contentType = "application/octet-stream"; // پیشفرض اگر پسوند ناشناس باشد | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| return File(stream, contentType, fileName); | ||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainVerify stream disposal behavior with File() method. The 🏁 Script executed: #!/bin/bash
# Description: Check if the S3FileUploaderService properly handles stream disposal
# Expected: The service should return a stream that can be safely disposed by the File() method
# Search for the S3FileUploaderService implementation
ast-grep --pattern 'class S3FileUploaderService {
$$$
DownloadFileAsync($$$) {
$$$
}
$$$
}'Length of output: 105 🏁 Script executed: #!/bin/bash
# Locate the S3FileUploaderService class and its DownloadFileAsync method
rg -n "class S3FileUploaderService"
rg -n "DownloadFileAsync" -C3Length of output: 2664 🏁 Script executed: #!/bin/bash
# Show the DownloadFileAsync method implementation for inspection
rg -n "public async Task<Stream> DownloadFileAsync" -C20 Refhub/Service/Implement/S3FileUploaderService.csLength of output: 1456 Ensure S3 response stream isn’t disposed before use The current code wraps the • Location: Refhub/Service/Implement/S3FileUploaderService.cs, DownloadFileAsync (lines 96–114) using var response = await _s3Client.GetObjectAsync(request, ct);
return response.ResponseStream;• Suggested fix: - using var response = await _s3Client.GetObjectAsync(request, ct);
- return response.ResponseStream;
+ var response = await _s3Client.GetObjectAsync(request, ct);
+ var ms = new MemoryStream();
+ await response.ResponseStream.CopyToAsync(ms, ct);
+ ms.Position = 0;
+ return ms;This ensures the returned stream remains valid when 🤖 Prompt for AI Agents |
||||||||||||||||
| } | ||||||||||||||||
|
||||||||||||||||
| } | |
| } | |
| catch (FileDownloadException fileEx) | |
| { | |
| _logger.LogError(fileEx, "خطا در دانلود فایل: {Message}", fileEx.Message); | |
| return NotFound(_messageService.Get("FileNotFound")); | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Validate or sanitize the 'fileName' input to prevent path traversal or unauthorized access when fetching files from S3.