Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Build direct upload token based on attachment name
- Loading branch information
1 parent
6515441
commit 9f65882
Showing
11 changed files
with
156 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
# frozen_string_literal: true | ||
|
||
module ActiveStorage | ||
module DirectUploadToken | ||
SEPARATOR = "." | ||
|
||
module_function | ||
|
||
def generate_direct_upload_token(attachment_name, service_name, session) | ||
token = per_attachment_direct_upload_token(session, attachment_name) | ||
encode_csrf_token([service_name, token].join(SEPARATOR)) | ||
end | ||
|
||
def verify_direct_upload_token(token, attachment_name, session) | ||
return if token.nil? | ||
|
||
service_name, csrf_token = decode_csrf_token(token).split(SEPARATOR) | ||
return service_name if valid_per_attachment_token?(csrf_token, attachment_name, session) | ||
|
||
raise ActiveStorage::WrongDirectUploadTokenError | ||
end | ||
|
||
def valid_per_attachment_token?(token, attachment_name, session) # :doc: | ||
correct_token = per_attachment_direct_upload_token(session, attachment_name) | ||
ActiveSupport::SecurityUtils.fixed_length_secure_compare(token, correct_token) | ||
rescue ArgumentError | ||
raise ActiveStorage::WrongDirectUploadTokenError | ||
end | ||
|
||
def per_attachment_direct_upload_token(session, attachment_name) # :doc: | ||
direct_upload_token_hmac(session, "direct_upload##{attachment_name}") | ||
end | ||
|
||
def direct_upload_token_hmac(session, identifier) # :doc: | ||
OpenSSL::HMAC.digest( | ||
OpenSSL::Digest::SHA256.new, | ||
real_direct_upload_token(session), | ||
identifier | ||
) | ||
end | ||
|
||
DIRECT_UPLOAD_TOKEN_LENGTH = 32 | ||
|
||
def real_direct_upload_token(session) # :doc: | ||
session[:_direct_upload_token] ||= SecureRandom.urlsafe_base64(DIRECT_UPLOAD_TOKEN_LENGTH, padding: false) | ||
encode_csrf_token(session[:_direct_upload_token]) | ||
end | ||
|
||
def decode_csrf_token(encoded_token) # :nodoc: | ||
Base64.urlsafe_decode64(encoded_token) | ||
end | ||
|
||
def encode_csrf_token(raw_token) # :nodoc: | ||
Base64.urlsafe_encode64(raw_token) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
# frozen_string_literal: true | ||
|
||
require "test_helper" | ||
|
||
class DirectUploadTokenTest < ActionController::TestCase | ||
setup do | ||
@session = {} | ||
@service_name = "local" | ||
@avatar_attachment_name = "User#avatar" | ||
end | ||
|
||
def test_validates_correct_token | ||
token = ActiveStorage::DirectUploadToken.generate_direct_upload_token(@avatar_attachment_name, @service_name, @session) | ||
verified_service_name = ActiveStorage::DirectUploadToken.verify_direct_upload_token(token, @avatar_attachment_name, @session) | ||
assert_equal verified_service_name, @service_name | ||
end | ||
|
||
def test_not_validates_token_when_session_is_empty | ||
token = ActiveStorage::DirectUploadToken.generate_direct_upload_token(@avatar_attachment_name, @service_name, {}) | ||
|
||
assert_raises(ActiveStorage::WrongDirectUploadTokenError) do | ||
ActiveStorage::DirectUploadToken.verify_direct_upload_token(token, @avatar_attachment_name, @session) | ||
end | ||
end | ||
|
||
def test_not_validates_token_from_different_attachment | ||
background_attachment_name = "User#background" | ||
token = ActiveStorage::DirectUploadToken.generate_direct_upload_token(background_attachment_name, @service_name, @session) | ||
|
||
assert_raises(ActiveStorage::WrongDirectUploadTokenError) do | ||
ActiveStorage::DirectUploadToken.verify_direct_upload_token(token, @avatar_attachment_name, @session) | ||
end | ||
end | ||
|
||
def test_not_validates_token_from_different_session | ||
token = ActiveStorage::DirectUploadToken.generate_direct_upload_token(@avatar_attachment_name, @service_name, @session) | ||
|
||
another_session = {} | ||
ActiveStorage::DirectUploadToken.generate_direct_upload_token(@avatar_attachment_name, @service_name, another_session) | ||
|
||
assert_raises(ActiveStorage::WrongDirectUploadTokenError) do | ||
ActiveStorage::DirectUploadToken.verify_direct_upload_token(token, @avatar_attachment_name, another_session) | ||
end | ||
end | ||
end |