DELETE a file ? #375

Closed
opened 2026-01-19 18:30:04 +00:00 by michael · 29 comments
Owner

Originally created by @kapouer on GitHub.

curl -X DELETE https://transfer.sh/xf54d/myfile.password
would be awesome.

Originally created by @kapouer on GitHub. `curl -X DELETE https://transfer.sh/xf54d/myfile.password` would be awesome.
Author
Owner

@monkz commented on GitHub:

And if you return two urls - it would break the current API.

@monkz commented on GitHub: And if you return two urls - it would break the current API.
Author
Owner

@monkz commented on GitHub:

I would recommend a second url for deletion (independent of the download link), otherwise the -X DELETE variant would be accessible for annoying people, that delete every transfer.sh hosted file.

@monkz commented on GitHub: I would recommend a second url for deletion (independent of the download link), otherwise the -X DELETE variant would be accessible for annoying people, that delete every transfer.sh hosted file.
Author
Owner

@rdeavila commented on GitHub:

I agree with @monkz. When we send a file, the site returns the file URL like https://transfer.sh/<random_code>/<filename>, right?

Why not return two URLs, one for access, and one for deletion, with the same pattern? The return can be:

DOWNLOAD: https://transfer.sh/<random_code>/<filename>
REMOVE: https://transfer.sh/<another_very_different_random_code>/<filename>

or a JSON:

{
  "download": "https://transfer.sh/<random_code>/<filename>",
  "remove": "https://transfer.sh/<another_very_different_random_code>/<filename>"
}

With that, who upload the file can record the deletion URL, and this second URL will not be guessed by others.

@rdeavila commented on GitHub: I agree with @monkz. When we send a file, the site returns the file URL like `https://transfer.sh/<random_code>/<filename>`, right? Why not return two URLs, one for access, and one for deletion, with the same pattern? The return can be: ``` DOWNLOAD: https://transfer.sh/<random_code>/<filename> REMOVE: https://transfer.sh/<another_very_different_random_code>/<filename> ``` or a JSON: ```javascript { "download": "https://transfer.sh/<random_code>/<filename>", "remove": "https://transfer.sh/<another_very_different_random_code>/<filename>" } ``` With that, who upload the file can record the deletion URL, and this second URL will not be guessed by others.
Author
Owner

@Anachron commented on GitHub:

I am also looking for a way to delete a file.

@Anachron commented on GitHub: I am also looking for a way to delete a file.
Author
Owner

@nl5887 commented on GitHub:

Exactly why we haven't implemented it yet. I can imagine returning an extra delete header, but that won't be visible for most people. Especially not the people that accidently uploaded a file they wanted to delete.

The solution I was thinking of was generating a site secret, hashing that with the hash of the file and returning it as an extra X-Delete-URL http header. That url can be called to delete the file.

@nl5887 commented on GitHub: Exactly why we haven't implemented it yet. I can imagine returning an extra delete header, but that won't be visible for most people. Especially not the people that accidently uploaded a file they wanted to delete. The solution I was thinking of was generating a site secret, hashing that with the hash of the file and returning it as an extra X-Delete-URL http header. That url can be called to delete the file.
Author
Owner

@pepa65 commented on GitHub:

Great idea, but definitely prefer the first form:

https://transfer.sh/<random_code>/<filename>
https://transfer.sh/delete/<another_very_different_random_code>/<filename>
@pepa65 commented on GitHub: Great idea, but definitely prefer the first form: ``` https://transfer.sh/<random_code>/<filename> https://transfer.sh/delete/<another_very_different_random_code>/<filename> ```
Author
Owner

@monkz commented on GitHub:

An attacker has access to multiple IP addresses and introducing ratelimits is the same as introducing a denial-of-service attack vector.
@ribamar-santarosa : so your suggestion is not suitable

@monkz commented on GitHub: An attacker has access to multiple IP addresses and introducing ratelimits is the same as introducing a denial-of-service attack vector. @ribamar-santarosa : so your suggestion is not suitable
Author
Owner

@monkz commented on GitHub:

I would opt for the first as default, and the second may be returned if /json is at the end of the url.
This would be analog to the "Scan for malware"-example.

But back to the first option. I see a possible issue with the prefix "DOWNLOAD: ". If someone tries to use this output in a script, the output has to be piped via head/tail and cut. If we omit the prefixes, we just need head -n 1 and tail -n 1

https://transfer.sh/<random_code>/<filename>
https://transfer.sh/delete/<another_very_different_random_code>/<filename>

This would split the namespaces for <random_code> and the urls are selfdescribing.

What about:

https://transfer.sh/<random_code>/<filename>
^^ Download ^^
vv Delete vv
https://transfer.sh/delete/<another_very_different_random_code>/<filename>

Optional: between ^^ Download ^^ and vv Delete vv a configurable string, for the hoster to use.
With Quota, Filehashes or even a motd (maybe used for advertisements)

https://transfer.sh/<random_code>/<filename>
^^ Download ^^
Hosted on transfer.sh (5% of quota used)
Donate Bitcoins: ....
vv Delete vv
https://transfer.sh/delete/<another_very_different_random_code>/<filename>
@monkz commented on GitHub: I would opt for the first as default, and the second may be returned if `/json` is at the end of the url. This would be analog to the "Scan for malware"-example. But back to the first option. I see a possible issue with the prefix "DOWNLOAD: ". If someone tries to use this output in a script, the output has to be piped via `head/tail` and `cut`. If we omit the prefixes, we just need `head -n 1` and `tail -n 1` ``` https://transfer.sh/<random_code>/<filename> https://transfer.sh/delete/<another_very_different_random_code>/<filename> ``` This would split the namespaces for <random_code> and the urls are selfdescribing. What about: ``` https://transfer.sh/<random_code>/<filename> ^^ Download ^^ vv Delete vv https://transfer.sh/delete/<another_very_different_random_code>/<filename> ``` Optional: between `^^ Download ^^` and `vv Delete vv` a configurable string, for the hoster to use. With Quota, Filehashes or even a motd (maybe used for advertisements) ``` https://transfer.sh/<random_code>/<filename> ^^ Download ^^ Hosted on transfer.sh (5% of quota used) Donate Bitcoins: .... vv Delete vv https://transfer.sh/delete/<another_very_different_random_code>/<filename> ```
Author
Owner

@ribamar-santarosa commented on GitHub:

how did you get to that conclusion? how can they take advantage of having multiple IPs to change or fake the IP of the creation of the file? And how about the time of creation? I am very curious to see how such presumptions can be use simply discard a whole proposal @monkz.

@ribamar-santarosa commented on GitHub: how did you get to that conclusion? how can they take advantage of having multiple IPs to change or fake the IP of the creation of the file? And how about the time of creation? I am very curious to see how such presumptions can be use simply discard a whole proposal @monkz.
Author
Owner

@ribamar-santarosa commented on GitHub:

Can't you use the creation time (or another file attribute, or another creation attribute, like IP of upload ) as a simple pin code to delete the file? 3 attempts from the same IP unable to hit the code at least with hour precision -- functionality ban. This way there is no API break.

@ribamar-santarosa commented on GitHub: Can't you use the creation time (or another file attribute, or another creation attribute, like IP of upload ) as a simple pin code to delete the file? 3 attempts from the same IP unable to hit the code at least with hour precision -- functionality ban. This way there is no API break.
Author
Owner

@monkz commented on GitHub:

3 attempts from the same IP unable to hit the code at least with hour precision -- functionality ban.

You can use arbitrary numbers of IP addresses. This allows you to have arbitrary numbers of 3 guesses.
If the rate limit is over all IP addresses, is he process vulnerable to ddos.

Can't you use the creation time as a simple pin code to delete the file?

As the file remains just a certain time on the server the number of creationhours is limited

or another file attribute

There are no other attributes to that data than name, creation time, IP address and the download hash.

like IP of upload

This is difficult to implement as there are multiple technologies that change the IP address the server sees. Like proxies, like reverse proxies, like NATs, like IP multihoming...

If the URL stays the same for deletion, the process is maybe vulnerable to CSRF and so on...

@monkz commented on GitHub: > 3 attempts from the same IP unable to hit the code at least with hour precision -- functionality ban. You can use arbitrary numbers of IP addresses. This allows you to have arbitrary numbers of 3 guesses. If the rate limit is over all IP addresses, is he process vulnerable to ddos. > Can't you use the creation time as a simple pin code to delete the file? As the file remains just a certain time on the server the number of creationhours is limited > or another file attribute There are no other attributes to that data than name, creation time, IP address and the download hash. > like IP of upload This is difficult to implement as there are multiple technologies that change the IP address the server sees. Like proxies, like reverse proxies, like NATs, like IP multihoming... If the URL stays the same for deletion, the process is maybe vulnerable to CSRF and so on...
Author
Owner

@Anachron commented on GitHub:

@monkz why not let the user specify a deletion secret himself (which is optional) and can be passed as POST param?

@Anachron commented on GitHub: @monkz why not let the user specify a deletion secret himself (which is optional) and can be passed as POST param?
Author
Owner

@monkz commented on GitHub:

Usability thoughts about my post above:

Hosters should've the possibility to set defaults and limitations to parameters that are available in request headers, that should help generate a hoster controlled behaviour - like always enabling deletion-urls.

Users who will upload files are mostly comfortable around a console. So setting request methods or additional headers and reacting on different output should come easy.
But we don't know if the person uploading the file is the person downloading and deleting the file.
A person who has only the competence (sorry this may sound a little bit harsher than intended) to click on a link in a email, won't be able to set a request method or a header.
So a deletion url should be requested via GET without additional headers.

curl -H "Deletion-URL: true" --upload-file ./hello.txt https://transfer.sh/hello.txt
https://transfer.sh/66nb8/hello.txt
https://transfer.sh/delete/66nb8/m0s9ui2

Header Deletion-URL: true would generate a password and a deletion url (with the password). So we are getting a two line output (the delete string in the URL is for identification/grep purposes). As we defined the parameter ourselves we can expect a different looking output - not breaking any old API.
I included the identifier in the deletion url, as a random generated password could have collisions.

Header Deletion-Password: lkjhnoiehb87t3 would implicate Deletion-URL: true and set the password.

curl -H "Deletion-Password: lkjhnoiehb87t3" --upload-file ./hello.txt https://transfer.sh/hello.txt
https://transfer.sh/66nb8/hello.txt
https://transfer.sh/delete/66nb8/lkjhnoiehb87t3

The database of transfer.sh would just store this password hashed - as it might contain private information or a reused password.

If somebody complains that the just wants one output line, we might add a second header Extensions-In-Response-Header: true that suppresses a second line and send the rest in a response header.

And for formatting questions like @rdeavila a header Format: plain or Format: json or Format: xml or ...

@monkz commented on GitHub: Usability thoughts about my post above: Hosters should've the possibility to set defaults and limitations to parameters that are available in request headers, that should help generate a hoster controlled behaviour - like always enabling deletion-urls. Users who will upload files are mostly comfortable around a console. So setting request methods or additional headers and reacting on different output should come easy. But we don't know if the person uploading the file is the person downloading and deleting the file. A person who has only the competence (sorry this may sound a little bit harsher than intended) to click on a link in a email, won't be able to set a request method or a header. So a deletion url should be requested via GET without additional headers. ``` curl -H "Deletion-URL: true" --upload-file ./hello.txt https://transfer.sh/hello.txt https://transfer.sh/66nb8/hello.txt https://transfer.sh/delete/66nb8/m0s9ui2 ``` Header `Deletion-URL: true` would generate a password and a deletion url (with the password). So we are getting a two line output (the delete string in the URL is for identification/grep purposes). As we defined the parameter ourselves we can expect a different looking output - not breaking any old API. I included the identifier in the deletion url, as a random generated password could have collisions. Header `Deletion-Password: lkjhnoiehb87t3` would implicate `Deletion-URL: true` and set the password. ``` curl -H "Deletion-Password: lkjhnoiehb87t3" --upload-file ./hello.txt https://transfer.sh/hello.txt https://transfer.sh/66nb8/hello.txt https://transfer.sh/delete/66nb8/lkjhnoiehb87t3 ``` The database of transfer.sh would just store this password hashed - as it might contain private information or a reused password. If somebody complains that the just wants one output line, we might add a second header `Extensions-In-Response-Header: true` that suppresses a second line and send the rest in a response header. And for formatting questions like @rdeavila a header `Format: plain` or `Format: json` or `Format: xml` or ...
Author
Owner

@Anachron commented on GitHub:

Bump. Still looking forward to this feature.

@Anachron commented on GitHub: Bump. Still looking forward to this feature.
Author
Owner

@monkz commented on GitHub:

@Anachron: interesting approach - making the API enhancement optional! I was total fix on default API behaviour - my bad.

We've already parameters for max downloads and days (see examples)

curl -H "Max-Downloads: 1" -H "Max-Days: 5" --upload-file ./hello.txt https://transfer.sh/hello.txt
https://transfer.sh/66nb8/hello.txt 

why not (yeah i know the filename is not important)

curl -H "Deletable: true" --upload-file ./hello.txt https://transfer.sh/hello.txt
https://transfer.sh/66nb8/hello.txt
https://transfer.sh/delete/m0s9ui2/hello.txt

If a hoster wants to set this behavior as default he can configure his service this way. So if the hoster decides to break the frontend api, he can do it. But it brings at least the possibility to generate a second url.

Or like @Anachron suggested with selfdefined password (where the random code + password is important)

curl -H "Deletion-Password: nhjdol9itzso9l87t8wq.lnsd.o" --upload-file ./hello.txt https://transfer.sh/hello.txt
https://transfer.sh/66nb8/hello.txt

The corresponding deletion method could be like @kapouer suggested or like a mix of the URL schema I suggested or or or.

@monkz commented on GitHub: @Anachron: interesting approach - making the API enhancement optional! I was total fix on default API behaviour - my bad. We've already parameters for max downloads and days (see examples) ``` curl -H "Max-Downloads: 1" -H "Max-Days: 5" --upload-file ./hello.txt https://transfer.sh/hello.txt https://transfer.sh/66nb8/hello.txt ``` why not (yeah i know the filename is not important) ``` curl -H "Deletable: true" --upload-file ./hello.txt https://transfer.sh/hello.txt https://transfer.sh/66nb8/hello.txt https://transfer.sh/delete/m0s9ui2/hello.txt ``` If a hoster wants to set this behavior as default he can configure his service this way. So if the hoster decides to break the frontend api, he can do it. But it brings at least the possibility to generate a second url. Or like @Anachron suggested with selfdefined password (where the random code + password is important) ``` curl -H "Deletion-Password: nhjdol9itzso9l87t8wq.lnsd.o" --upload-file ./hello.txt https://transfer.sh/hello.txt https://transfer.sh/66nb8/hello.txt ``` The corresponding deletion method could be like @kapouer suggested or like a mix of the URL schema I suggested or or or.
Author
Owner

@monkz commented on GitHub:

I've to extend/amend my former comments:
The deletion shouldn't be executed on a GET request - as it might result in deletion by crawlers (there were some image hosters that got mass deletions via this way)
The GET method request on the "deletion url" should present a page with a button/form that sends a PUT or DELETE method request to that same "deletion url". The second request would finally execute the deletion.
The reason for accepting both, PUT and DELETE, as request method is the limitation of HTML forms to GET und PUT methods (until http://amundsen.com/examples/put-delete-forms/ gets widely implemented)

So
curl -X DELETE https://transfer.sh/delete/66nb8/lkjhnoiehb87t3
would be the effective line in my example above.

The "deletion url" should be in the default output of an upload nevertheless (not hidden in a header).

@monkz commented on GitHub: I've to extend/amend my former comments: The deletion shouldn't be executed on a GET request - as it might result in deletion by crawlers (there were some image hosters that got mass deletions via this way) The GET method request on the "deletion url" should present a page with a button/form that sends a PUT or DELETE method request to that same "deletion url". The second request would finally execute the deletion. The reason for accepting both, PUT and DELETE, as request method is the limitation of HTML forms to GET und PUT methods (until http://amundsen.com/examples/put-delete-forms/ gets widely implemented) So `curl -X DELETE https://transfer.sh/delete/66nb8/lkjhnoiehb87t3` would be the effective line in my example above. The "deletion url" should be in the default output of an upload nevertheless (not hidden in a header).
Author
Owner

@Anachron commented on GitHub:

Ping @aspacca I've heard that you are the new owner of this repo.

@Anachron commented on GitHub: Ping @aspacca I've heard that you are the new owner of this repo.
Author
Owner

@Anachron commented on GitHub:

I mostly use transfer.sh to upload logs/config files to share them temporarly. (like for debugging or help a user out)

Now I was thinking about generating a little script that automatically cleans my uploads on the next day since I don't like my stuff to rot on some public server. (Sometimes I upload password-protected files that include sensible data)

So for me it's also a bit about a security aspect.

@Anachron commented on GitHub: I mostly use transfer.sh to upload logs/config files to share them temporarly. (like for debugging or help a user out) Now I was thinking about generating a little script that automatically cleans my uploads on the next day since I don't like my stuff to rot on some public server. (Sometimes I upload password-protected files that include sensible data) So for me it's also a bit about a security aspect.
Author
Owner

@pepa65 commented on GitHub:

I think it is best to just always require a password in the url that crawlers could "never" guess right.

@pepa65 commented on GitHub: I think it is best to just always require a password in the url that crawlers could "never" guess right.
Author
Owner

@paolafrancesca commented on GitHub:

@Anachron I'm indeed now an admin of the repo.
I want to understand what's the needing behind the option to delete a file: I can see two:

  • purge storage space
  • amend an upload

the different solutions proposed in the thread are some flows for both of them, but I want to understand clearly what the users need to find the proper solution

@paolafrancesca commented on GitHub: @Anachron I'm indeed now an admin of the repo. I want to understand what's the needing behind the option to delete a file: I can see two: - purge storage space - amend an upload the different solutions proposed in the thread are some flows for both of them, but I want to understand clearly what the users need to find the proper solution
Author
Owner

@nl5887 commented on GitHub:

I have thought before about this issue, and thought about returning an extra X-Url-Delete header, which would not interfere with current api / scripts and could be used in case people want to.

@nl5887 commented on GitHub: I have thought before about this issue, and thought about returning an extra X-Url-Delete header, which would not interfere with current api / scripts and could be used in case people want to.
Author
Owner

@paolafrancesca commented on GitHub:

@pepa65 the problem is that I don't find any proper solution to provide the ability for the uploader to delete the file in a way that others cannot without having either the uploader to forecast he will want to delete the file (adding upfront some delete token to match) or breaking the current output (providing two links: one for the download, one for the delete)

the solution may come with #105 : we just put the delete url behind authentication as for the upload ones. that's the one I like most but won't apply to the hosting part of transfer.sh

@paolafrancesca commented on GitHub: @pepa65 the problem is that I don't find any proper solution to provide the ability for the uploader to delete the file in a way that others cannot without having either the uploader to forecast he will want to delete the file (adding upfront some delete token to match) or breaking the current output (providing two links: one for the download, one for the delete) the solution may come with #105 : we just put the delete url behind authentication as for the upload ones. that's the one I like most but won't apply to the hosting part of transfer.sh
Author
Owner

@pepa65 commented on GitHub:

Using the Max-Days header is a good idea. But sometimes if you change your mind, it is good to have the option to delete a file (in a way that others can't delete your file).

@pepa65 commented on GitHub: Using the Max-Days header is a good idea. But sometimes if you change your mind, it is good to have the option to delete a file (in a way that others can't delete your file).
Author
Owner

@pepa65 commented on GitHub:

I think having the uploader specify a secret at upload-time is best. Uploaders that think they might want to delete a file at some point need to do that. If it was an option, I would always provide a secret in the upload-URL.

@pepa65 commented on GitHub: I think having the uploader specify a secret at upload-time is best. Uploaders that think they might want to delete a file at some point need to do that. If it was an option, I would always provide a secret in the upload-URL.
Author
Owner

@paolafrancesca commented on GitHub:

I think that if you have such security concerns you should not upload data on some public server in the first place. you can run your own instance of the server (now it supports also gdrive a storage provider)

said this, I guess that the data can be purged once they expire (default expiration: 1 year, you can change it with Max-Days header). I have to think a smart way how to manage it.

will this solution address your problem?

@paolafrancesca commented on GitHub: I think that if you have such security concerns you should not upload data on some public server in the first place. you can run your own instance of the server (now it supports also gdrive a storage provider) said this, I guess that the data can be purged once they expire (default expiration: 1 year, you can change it with `Max-Days` header). I have to think a smart way how to manage it. will this solution address your problem?
Author
Owner

@pepa65 commented on GitHub:

Anything that is workable and doesn't interfere with current functioning is great!

@pepa65 commented on GitHub: Anything that is workable and doesn't interfere with current functioning is great!
Author
Owner

@paolafrancesca commented on GitHub:

@pepa65 , @Anachron , the PR is ready, just needing to find a smart way to dump the X-Url-Delete header with curl

@paolafrancesca commented on GitHub: @pepa65 , @Anachron , the PR is ready, just needing to find a smart way to dump the `X-Url-Delete` header with curl
Author
Owner

@paolafrancesca commented on GitHub:

@nl5887 I will implement delete with X-Url-Delete header, anyway I'd need #125 to be merged before

@paolafrancesca commented on GitHub: @nl5887 I will implement delete with `X-Url-Delete` header, anyway I'd need #125 to be merged before
Author
Owner

@paolafrancesca commented on GitHub:

I've created #128 with X-Url-Delete added to every upload. can someone please help with updating the README.md with a proper curl call that will print/save the header?

@paolafrancesca commented on GitHub: I've created #128 with `X-Url-Delete` added to every upload. can someone please help with updating the `README.md` with a proper curl call that will print/save the header?
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dutchcoders/transfer.sh#375