Merge pull request #56 from fossyy/staging
Add hash check for file upload
This commit is contained in:
@ -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 {
|
||||||
|
@ -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`);
|
||||||
|
@ -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;"`
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user