-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
.ocTransferIDXXXXX.part makes filename too long #25425 #26978
Conversation
@IljaN, thanks for your PR! By analyzing the history of the files in this pull request, we identified @DeepDiver1975 to be a potential reviewer. |
@PVince81 I used the the built-in hash function because the hashing and crypto classes only contain password-hashing/encryption stuff. |
@@ -111,7 +111,7 @@ public function put($data) { | |||
|
|||
if ($needsPartFile) { | |||
// mark file as partial while uploading (ignored by the scanner) | |||
$partFilePath = $this->getPartFileBasePath($this->path) . '.ocTransferId' . rand() . '.part'; | |||
$partFilePath = sha1($this->getPartFileBasePath($this->path)) . '.part'; |
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.
Please keep the octransferid part. This is to avoid collisions in case of concurrent uploads.
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.
You need to only encode $this->path
, not the full path
@IljaN there's another code path where the part file name is generated (remember I mentionned some duplicate code). The encoding needs to be done there as well. |
It would also be good to add a unit test for that. Let me know if you need help there, might be a bit tricky. |
@PVince81 Added hashing to second code-path (chunking), added tests which check if part-file is created on both code-paths. |
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.
Code looks good except for once piece, see comments
@@ -111,7 +111,7 @@ public function put($data) { | |||
|
|||
if ($needsPartFile) { | |||
// mark file as partial while uploading (ignored by the scanner) | |||
$partFilePath = $this->getPartFileBasePath($this->path) . '.ocTransferId' . rand() . '.part'; | |||
$partFilePath = sha1($this->getPartFileBasePath($this->path)) . '.ocTransferId' . rand() . '.part'; |
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.
Split the $this->path
and use the sha1
of its basename because we don't want to hash the whole path
|
||
$storage->expects($this->atLeastOnce()) | ||
->method('fopen') | ||
->with($this->matchesRegularExpression('/^(\/[0-9a-f]{40})(.ocTransferId)([0-9]+)(.part)$/i')) |
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.
a hard-coded result would have been fine too and easier to understand, considering that the input is also hard-coded
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.
@PVince81 The result isn't entirely static because .ocTransferID is internally generated by rand() but I could still simplify the regex by making the hash-part static.
@PVince81 I am also kind of blocked here because the test which fails in Jenkins seems to run locally (with or without encryption). I will Investigate it with @DeepDiver1975 |
Hmm, weird. I might be able to help you as I'm likely more familiar with encryption |
…me + simplified unit-tests owncloud#25425
// we first assembly the target file as a part file | ||
$partFile = $this->getPartFileBasePath($path . '/' . $info['name']) . '.ocTransferId' . $info['transferid'] . '.part'; | ||
// we first assemble the target file as a part file | ||
$partFile = $this->getPartFileBasePath($path . '/' . sha1($info['name'])) . '.ocTransferId' . $info['transferid'] . '.part'; |
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.
so up there you use dirname
but not here ? would be good to have consistent approaches to avoid potential forgotten side-effects
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.
@PVince81 I use dirname/basename up there because I can't see another method or context trough which I can obtaine filename and path in seperated form.
On the chunked codepath there is decodeName method which returns a info array wihich contains the filename only.
Posting unit test failure for future reference:
|
Looks like these tests are somehow using Webdav to test upload. In the future we should remove these and resort to integration tests instead. I've added "upload+overwrite" to this list: owncloud/QA#297 (comment) |
Oh no... crap... I think I know what's happening: the encryption code is trying to find the matching keys for the part file by stripping the original file name from the part file. Now that the part file contains a hash, there is no way for encryption to resolve the file name back... So this will need a more extensive fix deep into the encryption code 😦 |
here is this ugly magic: https://github.com/owncloud/core/blob/master/lib/private/Encryption/Util.php#L259 |
there is no easy solution, might need a completely different approach in the encryption code, maybe new hooks... |
The reason for encryption is as follows: at the time of the To find out the file name, the encryption code grabs the part file name passed to The challenge here is to find a way to tell encryption about the original file name at the time of Also note that this one |
One thing that actually came to mind is to use the stream_context of the fopen and set the final file name in there, then let encryption use that name if it is set. Else fallback to stripping the name of the part file. In general I think third party apps usually do not use part files and use the PHP node API directly |
|
Raised #27142 to make encryption use another way to find the encryption keys and not rely on the part file. |
One idea would be to add a switch to only change the part file name to a shorted version if encryption is disabled... It's more of a hack and wouldn't solve the problem for encrypted setups. |
blocked by the encryption part file thing which itself is a big beast to resolve |
Any update here, can I review? |
closing as #25425 was closed as well. no good solution now that doesn't require reworking many parts of the storage layer and encryption |
Description
Fixing an error where file-uploads with long filenames failed because a .part suffix was attached to the filename during the upload thus exceeding the max allowed filename limit.
Related Issue
#25425
How Has This Been Tested?
Types of changes
Checklist: