Add hash check for file upload

This commit is contained in:
2024-09-14 17:28:09 +07:00
parent 0772d07fb8
commit 846db5fe0b
3 changed files with 52 additions and 14 deletions

View File

@ -45,6 +45,8 @@ type ActionUploadNewFile struct {
Name string `json:"name"` Name string `json:"name"`
Size uint64 `json:"size"` Size uint64 `json:"size"`
Chunk uint64 `json:"chunk"` Chunk uint64 `json:"chunk"`
StartHash string `json:"startHash"`
EndHash string `json:"endHash"`
RequestID string `json:"requestID"` RequestID string `json:"requestID"`
} }
@ -127,7 +129,7 @@ func handlerWS(conn *websocket.Conn, userSession types.User) {
err = json.Unmarshal(message, &action) err = json.Unmarshal(message, &action)
if err != nil { if err != nil {
app.Server.Logger.Error("Error unmarshalling WebsocketAction:", err) app.Server.Logger.Error("Error unmarshalling WebsocketAction:", err)
sendErrorResponse(conn, action.Action) sendErrorResponse(conn, action.Action, "Internal Server Error")
continue continue
} }
@ -137,7 +139,7 @@ func handlerWS(conn *websocket.Conn, userSession types.User) {
err = json.Unmarshal(message, &uploadNewFile) err = json.Unmarshal(message, &uploadNewFile)
if err != nil { if err != nil {
app.Server.Logger.Error("Error unmarshalling ActionUploadNewFile:", err) app.Server.Logger.Error("Error unmarshalling ActionUploadNewFile:", err)
sendErrorResponse(conn, action.Action) sendErrorResponse(conn, action.Action, "Internal Server Error")
continue continue
} }
var file *models.File var file *models.File
@ -149,12 +151,14 @@ func handlerWS(conn *websocket.Conn, userSession types.User) {
OwnerID: userSession.UserID, OwnerID: userSession.UserID,
Name: uploadNewFile.Name, Name: uploadNewFile.Name,
Size: uploadNewFile.Size, Size: uploadNewFile.Size,
StartHash: uploadNewFile.StartHash,
EndHash: uploadNewFile.EndHash,
TotalChunk: uploadNewFile.Chunk, TotalChunk: uploadNewFile.Chunk,
Downloaded: 0, Downloaded: 0,
} }
err := app.Server.Database.CreateFile(&newFile) err := app.Server.Database.CreateFile(&newFile)
if err != nil { if err != nil {
sendErrorResponse(conn, action.Action) sendErrorResponse(conn, action.Action, "Error Creating File")
continue continue
} }
fileData := &types.FileWithDetail{ fileData := &types.FileWithDetail{
@ -179,10 +183,14 @@ func handlerWS(conn *websocket.Conn, userSession types.User) {
sendSuccessResponseWithID(conn, action.Action, fileData, uploadNewFile.RequestID) sendSuccessResponseWithID(conn, action.Action, fileData, uploadNewFile.RequestID)
continue continue
} else { } else {
sendErrorResponse(conn, action.Action) sendErrorResponse(conn, action.Action, "Unknown error")
continue continue
} }
} }
if uploadNewFile.StartHash != file.StartHash || uploadNewFile.EndHash != file.EndHash {
sendErrorResponse(conn, action.Action, "File Is Different")
continue
}
fileData := &types.FileWithDetail{ fileData := &types.FileWithDetail{
ID: file.ID, ID: file.ID,
OwnerID: file.OwnerID, OwnerID: file.OwnerID,
@ -213,10 +221,11 @@ func handlerWS(conn *websocket.Conn, userSession types.User) {
} }
} }
func sendErrorResponse(conn *websocket.Conn, action ActionType) { func sendErrorResponse(conn *websocket.Conn, action ActionType, message string) {
response := map[string]interface{}{ response := map[string]interface{}{
"action": action, "action": action,
"status": "error", "status": "error",
"message": message,
} }
marshal, err := json.Marshal(response) marshal, err := json.Marshal(response)
if err != nil { if err != nil {

View File

@ -9,14 +9,25 @@ if (!window.mySocket) {
window.mySocket.onmessage = async function(event) { window.mySocket.onmessage = async function(event) {
try { try {
const data = JSON.parse(event.data); const data = JSON.parse(event.data);
if (data.action === "UploadNewFile") { if (data.status === "error") {
if (data.response.Done === false) { if (data.message === "File Is Different") {
const file = window.fileIdMap[data.responseID]; ChangeModal("Error", "A file with the same name already exists but has a different hash value. This may indicate that the file is different, despite having the same name. Please verify the file or consider renaming it before proceeding.")
addNewUploadElement(file); toggleModal();
const fileChunks = await splitFile(file, file.chunkSize);
await uploadChunks(file.name, file.size, fileChunks, data.response.Chunk, data.response.ID);
} else { } else {
alert("File already uploaded."); ChangeModal("Error", "There was an issue with your upload. Please try again later or contact support if the problem persists.")
toggleModal();
}
} else {
if (data.action === "UploadNewFile") {
if (data.response.Done === false) {
const file = window.fileIdMap[data.responseID];
addNewUploadElement(file);
const fileChunks = await splitFile(file, file.chunkSize);
await uploadChunks(file.name, file.size, fileChunks, data.response.Chunk, data.response.ID);
} else {
ChangeModal("Error", "File already uploaded.")
toggleModal();
}
} }
} }
} catch (error) { } catch (error) {
@ -44,11 +55,17 @@ async function handleFile(file){
const chunkSize = 2 * 1024 * 1024; const chunkSize = 2 * 1024 * 1024;
const chunks = Math.ceil(file.size / chunkSize); const chunks = Math.ceil(file.size / chunkSize);
const fileId = generateUniqueId(); const fileId = generateUniqueId();
const startChunk = await file.slice(0, chunkSize).arrayBuffer();
const endChunk = await file.slice((chunks-1) * chunkSize, file.size).arrayBuffer();
const startChunkHash = await hash(startChunk)
const endChunkHash = await hash(endChunk)
const data = JSON.stringify({ const data = JSON.stringify({
"action": "UploadNewFile", "action": "UploadNewFile",
"name": file.name, "name": file.name,
"size": file.size, "size": file.size,
"chunk": chunks, "chunk": chunks,
"startHash": startChunkHash,
"endHash": endChunkHash,
"requestID": fileId, "requestID": fileId,
}); });
file.chunkSize = chunkSize; file.chunkSize = chunkSize;
@ -133,12 +150,22 @@ async function splitFile(file, chunkSize) {
const start = i * chunkSize; const start = i * chunkSize;
const end = Math.min(fileSize, start + chunkSize); const end = Math.min(fileSize, start + chunkSize);
const chunk = file.slice(start, end); const chunk = file.slice(start, end);
chunk.hash = "test"
fileChunks.push(chunk); fileChunks.push(chunk);
} }
return fileChunks; return fileChunks;
} }
async function hash(arrayBuffer) {
const hashBuffer = await crypto.subtle.digest('SHA-256', arrayBuffer);
const hashArray = Array.from(new Uint8Array(hashBuffer));
const hashHex = hashArray
.map((bytes) => bytes.toString(16).padStart(2, '0'))
.join('');
return hashHex;
}
async function uploadChunks(name, size, chunks, chunkArray, FileID) { async function uploadChunks(name, size, chunks, chunkArray, FileID) {
let byteUploaded = 0 let byteUploaded = 0
let progress1 = document.getElementById(`progress-${name}-1`); let progress1 = document.getElementById(`progress-${name}-1`);

View File

@ -16,6 +16,8 @@ type File struct {
Name string `gorm:"type:text;not null"` Name string `gorm:"type:text;not null"`
Size uint64 `gorm:"not null"` Size uint64 `gorm:"not null"`
TotalChunk uint64 `gorm:"not null"` TotalChunk uint64 `gorm:"not null"`
StartHash string `gorm:"type:text;not null"`
EndHash string `gorm:"type:text;not null"`
Downloaded uint64 `gorm:"not null;default:0"` Downloaded uint64 `gorm:"not null;default:0"`
Owner *User `gorm:"foreignKey:OwnerID;constraint:OnDelete:CASCADE;"` Owner *User `gorm:"foreignKey:OwnerID;constraint:OnDelete:CASCADE;"`
} }