diff --git a/event/common.go b/event/common.go index 2fed68e..5ccf72b 100644 --- a/event/common.go +++ b/event/common.go @@ -257,6 +257,7 @@ const ( ManifestSaved = Type("ManifestSaved") FileDownloadProgressUpdate = Type("FileDownloadProgressUpdate") FileDownloaded = Type("FileDownloaded") + FileVerificationFailed = Type("FileVerificationFailed") ) // Field defines common event attributes diff --git a/protocol/connections/engine.go b/protocol/connections/engine.go index d1ab595..417daf4 100644 --- a/protocol/connections/engine.go +++ b/protocol/connections/engine.go @@ -540,13 +540,18 @@ func (e *engine) handlePeerMessage(hostname string, eventID string, context stri } } } else if context == event.ContextSendFile { - fileKey, downloaded, progress, totalChunks, _ := e.filesharingSubSystem.ProcessChunk(eventID, message) + fileKey, progress, totalChunks, _ := e.filesharingSubSystem.ProcessChunk(eventID, message) if len(fileKey) != 0 { - if downloaded { - log.Debugf("file verified and downloaded!") - e.eventManager.Publish(event.NewEvent(event.FileDownloaded, map[event.Field]string{event.FileKey: fileKey})) - } e.eventManager.Publish(event.NewEvent(event.FileDownloadProgressUpdate, map[event.Field]string{event.FileKey: fileKey, event.Progress: strconv.Itoa(int(progress)), event.FileSizeInChunks: strconv.Itoa(int(totalChunks))})) + if progress == totalChunks { + if e.filesharingSubSystem.VerifyFile(fileKey) { + log.Debugf("file verified and downloaded!") + e.eventManager.Publish(event.NewEvent(event.FileDownloaded, map[event.Field]string{event.FileKey: fileKey})) + } else { + log.Debugf("file failed to verify!") + e.eventManager.Publish(event.NewEvent(event.FileVerificationFailed, map[event.Field]string{event.FileKey: fileKey})) + } + } } } else { // Fall through handler for the default text conversation. diff --git a/protocol/files/filesharing_subsystem.go b/protocol/files/filesharing_subsystem.go index 61c46be..f22d684 100644 --- a/protocol/files/filesharing_subsystem.go +++ b/protocol/files/filesharing_subsystem.go @@ -169,9 +169,8 @@ func (fsss *FileSharingSubSystem) ProcessChunkRequest(fileKey string, serialized // Always return the progress of a matched download if it exists along with the total number of chunks and the // given chunk ID // If not such active download exists then return an empty file key and ignore all further processing. -func (fsss *FileSharingSubSystem) ProcessChunk(chunkKey string, chunk []byte) (fileKey string, downloaded bool, progress uint64, totalChunks uint64, chunkID uint64) { +func (fsss *FileSharingSubSystem) ProcessChunk(chunkKey string, chunk []byte) (fileKey string, progress uint64, totalChunks uint64, chunkID uint64) { fileKeyParts := strings.Split(chunkKey, ".") - downloaded = false log.Debugf("got chunk for %s", fileKeyParts) if len(fileKeyParts) == 3 { // fileKey is rootHash.nonce.chunk // recalculate file key @@ -187,23 +186,30 @@ func (fsss *FileSharingSubSystem) ProcessChunk(chunkKey string, chunk []byte) (f log.Debugf("found active manifest %v", manifest) progress, err = manifest.StoreChunk(chunkID, chunk) log.Debugf("attempts to store chunk %v %v", progress, err) - // malicious contacts who share conversations can share random chunks - // these will not match the chunk hash and as such will fail. - // at this point we can't differentiate between a malicious chunk and failure to store a - // legitimate chunk, so if there is an error we silently drop it and expect the higher level callers (e.g. the ui) - //to detect and respond to missing chunks if it detects them.. - if err == nil { - if progress == totalChunks { - if manifest.VerifyFile() == nil { - manifest.Close() - fsss.activeDownloads.Delete(fileKey) - log.Debugf("file verified and downloaded!") - downloaded = true - } - } + if err != nil { + // malicious contacts who share conversations can share random chunks + // these will not match the chunk hash and as such will fail. + // at this point we can't differentiate between a malicious chunk and failure to store a + // legitimate chunk, so if there is an error we silently drop it and expect the higher level callers (e.g. the ui) + //to detect and respond to missing chunks if it detects them.. } } } } return } + + +func (fsss *FileSharingSubSystem) VerifyFile(fileKey string) (downloaded bool) { + manifestI, exists := fsss.activeDownloads.Load(fileKey) + if exists { + manifest := manifestI.(*Manifest) + if manifest.VerifyFile() == nil { + manifest.Close() + fsss.activeDownloads.Delete(fileKey) + log.Debugf("file verified and downloaded!") + return true + } + } + return false +} \ No newline at end of file