Class: Megar::FileUploader

Inherits:
Object
  • Object
show all
Includes:
CryptoSupport
Defined in:
lib/megar/adapters/file_uploader.rb

Overview

Encapsulates a file upload task. This is intended as a one-shot helper.

NB: there seems to be an issue if you try to upload multiple files of exactly the same size in the same session.

Javascript reference implementation: function initupload3()

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from CryptoSupport

#a32_to_base64, #a32_to_str, #accumulate_mac, #aes_cbc_decrypt, #aes_cbc_decrypt_a32, #aes_cbc_encrypt, #aes_cbc_encrypt_a32, #aes_encrypt_a32, #base64_mpi_to_a32, #base64_mpi_to_bn, #base64_to_a32, #base64urldecode, #base64urlencode, #calculate_chunk_mac, #crypto_requirements_met?, #decompose_file_key, #decompose_rsa_private_key, #decompose_rsa_private_key_a32, #decrypt_base64_to_a32, #decrypt_base64_to_str, #decrypt_file_attributes, #decrypt_file_key, #decrypt_key, #decrypt_session_id, #encrypt_file_attributes, #encrypt_key, #get_chunks, #get_file_decrypter, #get_file_encrypter, #hexstr_to_bstr, #mpi_to_a32, #openssl_rsa_cipher, #openssl_rsa_decrypt, #prepare_key, #prepare_key_pw, #rsa_decrypt, #str_to_a32, #stringhash

Constructor Details

#initialize(options = {}) ⇒ FileUploader

Returns a new instance of FileUploader.



20
21
22
23
24
25
# File 'lib/megar/adapters/file_uploader.rb', line 20

def initialize(options={})
  @folder = options[:folder]
  @session = @folder && @folder.session
  self.body = options[:body]
  self.name = options[:name]
end

Instance Attribute Details

#bodyObject

Returns the value of attribute body.



17
18
19
# File 'lib/megar/adapters/file_uploader.rb', line 17

def body
  @body
end

#folderObject (readonly)

Returns the value of attribute folder.



15
16
17
# File 'lib/megar/adapters/file_uploader.rb', line 15

def folder
  @folder
end

#nameObject

Returns the name of the file



55
56
57
# File 'lib/megar/adapters/file_uploader.rb', line 55

def name
  @name ||= Pathname.new(body.path).basename.to_s
end

#sessionObject (readonly)

Returns the value of attribute session.



16
17
18
# File 'lib/megar/adapters/file_uploader.rb', line 16

def session
  @session
end

Instance Method Details

#ivObject



123
124
125
# File 'lib/megar/adapters/file_uploader.rb', line 123

def iv
  ((upload_key[4]<<32)+upload_key[5])<<64
end

#iv_strObject



127
128
129
# File 'lib/megar/adapters/file_uploader.rb', line 127

def iv_str
  hexstr_to_bstr( iv.to_s(16) )
end

#mac_encryption_keyObject

Returns the encryption key to use for calculating the MAC



114
115
116
# File 'lib/megar/adapters/file_uploader.rb', line 114

def mac_encryption_key
  upload_key[0,4]
end

#mac_ivObject

Returns the initialisation vector as array of 32bit integer to use for calculating the MAC



119
120
121
# File 'lib/megar/adapters/file_uploader.rb', line 119

def mac_iv
  [upload_key[4], upload_key[5], upload_key[4], upload_key[5]]
end

#post!Object

Command: perform upload



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/megar/adapters/file_uploader.rb', line 60

def post!
  return unless live_session?
  calculated_mac = [0, 0, 0, 0]
  completion_file_handle = ''

  encryptor = get_file_encrypter(upload_key,iv_str)

  get_chunks(upload_size).each do |chunk_start, chunk_size|
    chunk = stream.readpartial(chunk_size)
    encrypted_chunk = encryptor.update(chunk)
    calculated_mac = accumulate_mac(chunk,calculated_mac,mac_encryption_key,mac_iv,false)
    completion_file_handle = post_chunk(encrypted_chunk,chunk_start)
  end
  stream.close
  meta_mac = [calculated_mac[0] ^ calculated_mac[1], calculated_mac[2] ^ calculated_mac[3]]

  upload_attributes_response = send_file_upload_attributes(meta_mac,completion_file_handle)
  if upload_attributes_response.is_a?(Hash) && upload_attributes_response['f']
    session.handle_files_response(upload_attributes_response,false)
  else
    raise Megar::FileUploadError.new
  end
end

#streamObject

Returns stream handle to the file body



50
51
52
# File 'lib/megar/adapters/file_uploader.rb', line 50

def stream
  body
end

#upload_keyObject



109
110
111
# File 'lib/megar/adapters/file_uploader.rb', line 109

def upload_key
  @upload_key ||= 6.times.each_with_object([]) {|i,memo| memo << rand( 0xFFFFFFFF) }
end

#upload_sizeObject

Returns the size of the file content



45
46
47
# File 'lib/megar/adapters/file_uploader.rb', line 45

def upload_size
  body.size
end

#upload_uriObject

Returns an upload url for the file content as a URI



105
106
107
# File 'lib/megar/adapters/file_uploader.rb', line 105

def upload_uri
  @upload_uri ||= URI.parse(upload_url)
end

#upload_urlObject

Returns an upload url for the file content



100
101
102
# File 'lib/megar/adapters/file_uploader.rb', line 100

def upload_url
  upload_url_response['p']
end

#upload_url_responseObject

Returns and caches a file upload response



132
133
134
135
136
137
138
# File 'lib/megar/adapters/file_uploader.rb', line 132

def upload_url_response
  @upload_url_response ||= if live_session?
    session.get_file_upload_url_response(upload_size)
  else
    {}
  end
end