Skip to content

Instantly share code, notes, and snippets.

@onnimonni
Created December 29, 2017 17:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save onnimonni/013331a23755d29406f9e5cd3edf1eeb to your computer and use it in GitHub Desktop.
Save onnimonni/013331a23755d29406f9e5cd3edf1eeb to your computer and use it in GitHub Desktop.
Ruby script to upload versioned private files to s3 bucket and to retrieve their presigned_url. This can be used to achieve append only file uploads which can't be deleted easily.
require 'aws-sdk-s3'
# When there's something wrong with the s3
class S3StorageError < StandardError
def initialize(data)
@data = data
end
end
class S3File
def initialize(params)
# Bucket info
@bucket = params[:bucket] || ENV['AWS_S3_BUCKET_NAME'] || raise(S3StorageError,'You need to provide :bucket or AWS_S3_BUCKET_NAME')
# AWS credentials
@client = Aws::S3::Client.new(
region: param[:region] || ENV['AWS_DEFAULT_REGION'] || 'eu-central-1',
access_key_id: param[:access_key_id] || ENV['AWS_ACCESS_KEY_ID'] || raise(S3StorageError,'You need to provide :access_key_id or AWS_ACCESS_KEY_ID'),
secret_access_key: param[:secret_access_key] || ENV['AWS_SECRET_ACCESS_KEY'] || raise(S3StorageError,'You need to provide :secret_access_key or AWS_SECRET_ACCESS_KEY')
)
# This is used to get the secret url to private files
@signer = Aws::S3::Presigner.new(client: client)
# These are needed in order to find the file
@path = params[:path]
@version_id = params[:version_id]
# Saves the file into s3
def save(params)
raise S3StorageError "@path for file is not defined!" unless @path
request = defaults.merge(params)
raise S3StorageError "Can't define :content and :file into same object" if request[:content] && request[:file]
if request[:content]
response = s3.put_object(request)
elsif request[:file]
# Stream the file into s3
filename = request.delete(:file)
File.open(filename, 'rb') do |file_contents|
response = s3.put_object( request.merge({ body: file_contents }) )
end
end
# This is the version which is interesting to us
@version_id = resp.version_id
end
# Gets presigned url which will expire automatically
def presigned_url(params)
signer.presigned_url( defaults.merge(params) )
end
private
# Default settings
def defaults
{
acl: 'private',
expires_in: 15.minutes.to_i
bucket: @bucket,
path: @path
}
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment