{"html_url": "https://github.com/simonw/datasette/issues/1036#issuecomment-762391426", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1036", "id": 762391426, "node_id": "MDEyOklzc3VlQ29tbWVudDc2MjM5MTQyNg==", "user": {"value": 4997607, "label": "philshem"}, "created_at": "2021-01-18T17:45:00Z", "updated_at": "2021-01-18T17:45:00Z", "author_association": "NONE", "body": "It might be possible with this library: https://docs.python.org/3/library/imghdr.html\r\n\r\nquick test of the downloaded blob:\r\n\r\n```\r\n>>> import imghdr\r\n>>> imghdr.what('material_culture-1-image.blob')\r\n'jpeg'\r\n```\r\n\r\nThe output plugin would be cool. I'll look into making my first datasette plugin. I'm also imagining displaying the image in the browser -- but that would be a step 2.\r\n\r\n", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 725996507, "label": "Make it possible to download BLOB data from the Datasette UI"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1036#issuecomment-762387875", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1036", "id": 762387875, "node_id": "MDEyOklzc3VlQ29tbWVudDc2MjM4Nzg3NQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2021-01-18T17:36:36Z", "updated_at": "2021-01-18T17:36:36Z", "author_association": "OWNER", "body": "As you can see, I'm pretty paranoid about serving content with `Content-Type` HTTP headers because I'm so worried about execution vulnerabilities. I'm much more comfortable exploring that kind of thing in plugins, since that way people can opt-in to riskier features.\r\n\r\nYou found `datasette-media` which is my most comprehensive exploration of that idea so far - but there's definitely lots of room for more plugins along those lines.\r\n\r\nMaybe even an output plugin? `.jpg` as an export format which returns the `BLOB` column for a row as a JPEG image with the correct `content-type` header (but first verifies that the binary content does indeed look like a real JPEG) could be interesting.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 725996507, "label": "Make it possible to download BLOB data from the Datasette UI"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1036#issuecomment-762385981", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1036", "id": 762385981, "node_id": "MDEyOklzc3VlQ29tbWVudDc2MjM4NTk4MQ==", "user": {"value": 4997607, "label": "philshem"}, "created_at": "2021-01-18T17:32:13Z", "updated_at": "2021-01-18T17:34:50Z", "author_association": "NONE", "body": "Hi Simon\r\n\r\nJust finding this old issue regarding downloading blobs. Nice work!\r\n\r\n\"image\"\r\n\r\nAs a feature request, maybe it would be possible to assign a blob column as a certain data type (e.g. `.jpg`) and then each blob could be downloaded as that type of file (perhaps if the file types were constrained to normal blobs that people store in sqlite databases, this could avoid the execution stuff mentioned above).\r\n\r\nI guess the column blob-type definition could fit into this dropdown selection:\r\n\r\n\"image\"\r\n\r\nLet me know if I should open a new issue with a feature request. (This could slowly go in the direction of displaying image blob-types in the browser.)\r\n\r\nThanks for the great tool!\r\n\r\n\r\n---\r\n\r\nedit: just reading the rest of the twitter thread: https://twitter.com/simonw/status/1318685933256855552\r\n\r\nperhaps this is already possible in some form with the plugin datasette-media: https://github.com/simonw/datasette-media", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 725996507, "label": "Make it possible to download BLOB data from the Datasette UI"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1036#issuecomment-713899530", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1036", "id": 713899530, "node_id": "MDEyOklzc3VlQ29tbWVudDcxMzg5OTUzMA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-10-21T21:55:00Z", "updated_at": "2020-10-21T21:55:00Z", "author_association": "OWNER", "body": "This code needs these permission checks:\r\nhttps://github.com/simonw/datasette/blob/bf82b3d6a605c9ddadd5fb739249dfe6defaf635/datasette/views/table.py#L911-L913", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 725996507, "label": "Make it possible to download BLOB data from the Datasette UI"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1036#issuecomment-713821656", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1036", "id": 713821656, "node_id": "MDEyOklzc3VlQ29tbWVudDcxMzgyMTY1Ng==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-10-21T19:22:45Z", "updated_at": "2020-10-21T19:41:48Z", "author_association": "OWNER", "body": "So for https://latest.datasette.io/fixtures/binary_data the BLOB download URLs would be:\r\n\r\n`https://latest.datasette.io/fixtures/-/blob/binary_data/1/data.blob` - that last bit after the primary key is to indicate the `data` column\r\n\r\nWith these headers:\r\n\r\n- `Content-Disposition: attachment; filename=\"binary_data-1-data.blob\"`\r\n- `X-Content-Type-Options: nosniff`\r\n- `Content-Type: application/binary`", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 725996507, "label": "Make it possible to download BLOB data from the Datasette UI"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1036#issuecomment-713830842", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1036", "id": 713830842, "node_id": "MDEyOklzc3VlQ29tbWVudDcxMzgzMDg0Mg==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-10-21T19:41:20Z", "updated_at": "2020-10-21T19:41:20Z", "author_association": "OWNER", "body": "Another useful demo database: https://datasette-render-images-demo.datasette.io/favicons/favicons - see https://datasette-render-images-demo.datasette.io/favicons/favicons.csv", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 725996507, "label": "Make it possible to download BLOB data from the Datasette UI"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1036#issuecomment-713829629", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1036", "id": 713829629, "node_id": "MDEyOklzc3VlQ29tbWVudDcxMzgyOTYyOQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-10-21T19:38:43Z", "updated_at": "2020-10-21T19:38:43Z", "author_association": "OWNER", "body": "Should this work just for BLOB columns, or should it work for other columns too?\r\n\r\nFor the moment I'm going to restrict it to BLOBs, since data from other columns is available through the UI whereas BLOB columns are not.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 725996507, "label": "Make it possible to download BLOB data from the Datasette UI"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1036#issuecomment-713818817", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1036", "id": 713818817, "node_id": "MDEyOklzc3VlQ29tbWVudDcxMzgxODgxNw==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-10-21T19:17:01Z", "updated_at": "2020-10-21T19:17:01Z", "author_association": "OWNER", "body": "Actually I like `.blob`", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 725996507, "label": "Make it possible to download BLOB data from the Datasette UI"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1036#issuecomment-713818178", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1036", "id": 713818178, "node_id": "MDEyOklzc3VlQ29tbWVudDcxMzgxODE3OA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-10-21T19:15:38Z", "updated_at": "2020-10-21T19:16:34Z", "author_association": "OWNER", "body": "What should the suggested filename be?\r\n\r\nI think something that includes the table name, primary key and the name of the column would work.\r\n\r\nHow about a file extension? I guess `.binary`, then let the user rename it? Or `.raw`.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 725996507, "label": "Make it possible to download BLOB data from the Datasette UI"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1036#issuecomment-713278349", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1036", "id": 713278349, "node_id": "MDEyOklzc3VlQ29tbWVudDcxMzI3ODM0OQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-10-21T03:42:29Z", "updated_at": "2020-10-21T03:42:29Z", "author_association": "OWNER", "body": "Possible URL for this: `/db/table/-/blob/primary-keys` - this would use the `/db/table/-/` namespace proposed in #296.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 725996507, "label": "Make it possible to download BLOB data from the Datasette UI"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1036#issuecomment-713226726", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1036", "id": 713226726, "node_id": "MDEyOklzc3VlQ29tbWVudDcxMzIyNjcyNg==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-10-21T01:04:25Z", "updated_at": "2020-10-21T01:04:25Z", "author_association": "OWNER", "body": "Extra security idea: a `blob_download_host` setting which can be used to indicate a host that should be used for downloads - for example `datasettestatic.com`. If this setting is populated then binary downloads are served from paths on that host only, and no other Datasette URLs from that host will be served.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 725996507, "label": "Make it possible to download BLOB data from the Datasette UI"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1036#issuecomment-713186189", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1036", "id": 713186189, "node_id": "MDEyOklzc3VlQ29tbWVudDcxMzE4NjE4OQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-10-20T22:56:33Z", "updated_at": "2020-10-20T22:56:33Z", "author_association": "OWNER", "body": "I think this plus the binary-CSV stuff in #1034 will justify a dedicated section of the documentation to talk about how Datasette handles binary BLOB columns.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 725996507, "label": "Make it possible to download BLOB data from the Datasette UI"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1036#issuecomment-713185871", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1036", "id": 713185871, "node_id": "MDEyOklzc3VlQ29tbWVudDcxMzE4NTg3MQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-10-20T22:55:36Z", "updated_at": "2020-10-20T22:55:36Z", "author_association": "OWNER", "body": "I can also use a `Content-Disposition` header to force a download. I'm reasonably confident that the combination of `Content-Disposition` and `X-Content-Type-Options: nosniff` and `application/binary` will let me allow users to download the contents of arbitrary BLOB columns without any XSS risk.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 725996507, "label": "Make it possible to download BLOB data from the Datasette UI"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1036#issuecomment-713185173", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1036", "id": 713185173, "node_id": "MDEyOklzc3VlQ29tbWVudDcxMzE4NTE3Mw==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-10-20T22:53:41Z", "updated_at": "2020-10-20T22:53:41Z", "author_association": "OWNER", "body": "https://security.stackexchange.com/questions/12896/does-x-content-type-options-really-prevent-content-sniffing-attacks says:\r\n\r\n> In Tangled Web Michal Zalewski says:\r\n> \r\n> > Refrain from using Content-Type: application/octet-stream and use application/binary instead, especially for unknown document types. Refrain from returning Content-Type: text/plain.\r\n> > \r\n> > For example, any code-hosting platform must exercise caution when returning executables or source archives as application/octet-stream, because there is a risk they may be misinterpreted as HTML and displayed inline.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 725996507, "label": "Make it possible to download BLOB data from the Datasette UI"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1036#issuecomment-713184374", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1036", "id": 713184374, "node_id": "MDEyOklzc3VlQ29tbWVudDcxMzE4NDM3NA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-10-20T22:51:22Z", "updated_at": "2020-10-20T22:51:22Z", "author_association": "OWNER", "body": "From https://hackerone.com/reports/126197:\r\n\r\n> archive.uber.com mirrors pypi. When downloading `.tar.gz` files from archive.uber.com, the MIME type is `application/octet-stream`. Injecting `` into the start of the `.tar.gz` causes an XSS in Internet Explorer due to MIME sniffing.\r\n\r\nSo you do have to be careful not to open accidental XSS holes with `application/octet-stream` thanks to (presumably older) versions of IE.\r\n\r\nFrom that thread it looks like the solution is to add a `X-Content-Type-Options: nosniff` header.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 725996507, "label": "Make it possible to download BLOB data from the Datasette UI"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1036#issuecomment-713183306", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1036", "id": 713183306, "node_id": "MDEyOklzc3VlQ29tbWVudDcxMzE4MzMwNg==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-10-20T22:48:10Z", "updated_at": "2020-10-20T22:48:10Z", "author_association": "OWNER", "body": "Twitter thread: https://twitter.com/dancow/status/1318681053347840005", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 725996507, "label": "Make it possible to download BLOB data from the Datasette UI"}, "performed_via_github_app": null}