Skip to content

Commit f89838b

Browse files
authored
Merge pull request #2079 from basecamp/fix-direct-uploads-via-api
Fix direct uploads via API
2 parents dcdd853 + fb77d85 commit f89838b

File tree

3 files changed

+84
-1
lines changed

3 files changed

+84
-1
lines changed

config/initializers/active_storage.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,16 @@ module ActiveStorageControllerExtensions
3535
end
3636
end
3737

38+
module ActiveStorageDirectUploadsControllerExtensions
39+
extend ActiveSupport::Concern
40+
41+
included do
42+
include Authentication
43+
skip_forgery_protection if: :authenticate_by_bearer_token
44+
end
45+
end
46+
3847
Rails.application.config.to_prepare do
3948
ActiveStorage::BaseController.include ActiveStorageControllerExtensions
49+
ActiveStorage::DirectUploadsController.include ActiveStorageDirectUploadsControllerExtensions
4050
end

docs/API.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,10 +178,11 @@ curl -X POST \
178178
"content_type": "image/png"
179179
}
180180
}' \
181-
https://app.fizzy.do/rails/active_storage/direct_uploads
181+
https://app.fizzy.do/123456/rails/active_storage/direct_uploads
182182
```
183183

184184
The `checksum` is a Base64-encoded MD5 hash of the file content.
185+
The direct upload endpoint is scoped to your account (replace `/123456` with your account slug).
185186

186187
__Response:__
187188

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
require "test_helper"
2+
3+
class ActiveStorage::DirectUploadsControllerTest < ActionDispatch::IntegrationTest
4+
setup do
5+
@blob_params = {
6+
blob: {
7+
filename: "screenshot.png",
8+
byte_size: 12345,
9+
checksum: "GQ5SqLsM7ylnji0Wgd9wNC==",
10+
content_type: "image/png"
11+
}
12+
}
13+
end
14+
15+
test "create" do
16+
sign_in_as :david
17+
18+
post rails_direct_uploads_path,
19+
params: @blob_params,
20+
headers: bearer_token_header(identity_access_tokens(:davids_api_token).token),
21+
as: :json
22+
23+
assert_response :success
24+
assert_includes response.parsed_body.keys, "direct_upload"
25+
end
26+
27+
test "create with valid access token" do
28+
post rails_direct_uploads_path,
29+
params: @blob_params,
30+
headers: bearer_token_header(identity_access_tokens(:davids_api_token).token),
31+
as: :json
32+
33+
assert_response :success
34+
assert_includes response.parsed_body.keys, "direct_upload"
35+
end
36+
37+
test "create with read-only access token" do
38+
post rails_direct_uploads_path,
39+
params: @blob_params,
40+
headers: bearer_token_header(identity_access_tokens(:jasons_api_token).token),
41+
as: :json
42+
43+
assert_response :unauthorized
44+
end
45+
46+
test "create with invalid access token" do
47+
post rails_direct_uploads_path,
48+
params: @blob_params,
49+
headers: bearer_token_header("invalid_token"),
50+
as: :json
51+
52+
assert_response :unauthorized
53+
end
54+
55+
test "create unauthenticated" do
56+
post rails_direct_uploads_path,
57+
params: @blob_params.merge(authenticity_token: csrf_token),
58+
as: :json
59+
60+
assert_response :redirect
61+
end
62+
63+
private
64+
def bearer_token_header(token)
65+
{ "Authorization" => "Bearer #{token}" }
66+
end
67+
68+
def csrf_token
69+
get new_session_url
70+
response.body[/name="csrf-token" content="([^"]+)"/, 1]
71+
end
72+
end

0 commit comments

Comments
 (0)