Class: Megar::FileDownloader

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

Overview

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

Javascript reference implementation: function startdownload2(res,ctx)

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 = {}) ⇒ FileDownloader

Returns a new instance of FileDownloader.



13
14
15
16
# File 'lib/megar/adapters/file_downloader.rb', line 13

def initialize(options={})
  @file = options[:file]
  @session = @file && @file.session
end

Instance Attribute Details

#fileObject (readonly)

Returns the value of attribute file.



11
12
13
# File 'lib/megar/adapters/file_downloader.rb', line 11

def file
  @file
end

#sessionObject (readonly)

Returns the value of attribute session.



10
11
12
# File 'lib/megar/adapters/file_downloader.rb', line 10

def session
  @session
end

Instance Method Details

#chunk_mac_ivObject



76
77
78
# File 'lib/megar/adapters/file_downloader.rb', line 76

def chunk_mac_iv
  [iv[0], iv[1], iv[0], iv[1]]
end

#contentObject

Returns the complete decrypted content. If anything goes wrong here, it’s going to bubble up an unhandled error.



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/megar/adapters/file_downloader.rb', line 29

def content
  return unless live_session?
  decoded_content = ''
  calculated_mac = [0, 0, 0, 0]

  decryptor = get_file_decrypter(decomposed_key,iv)

  get_chunks(download_size).each do |chunk_start, chunk_size|
    chunk = stream.readpartial(chunk_size)
    decoded_chunk = decryptor.update(chunk)
    decoded_content << decoded_chunk
    calculated_mac = accumulate_mac(decoded_chunk,calculated_mac,decomposed_key,chunk_mac_iv)
  end

  raise Megar::MacVerificationError.new unless ([calculated_mac[0] ^ calculated_mac[1], calculated_mac[2] ^ calculated_mac[3]] == mac)

  decoded_content
end

#decomposed_keyObject

Returns the file key (shortcut)



91
92
93
# File 'lib/megar/adapters/file_downloader.rb', line 91

def decomposed_key
  file.decomposed_key
end

#download_attributesObject

Returns the decrypted download attributes



65
66
67
68
69
# File 'lib/megar/adapters/file_downloader.rb', line 65

def download_attributes
  if attributes = download_url_response['at']
    decrypt_file_attributes(attributes,decomposed_key)
  end
end

#download_sizeObject

Returns a download size for the file content



60
61
62
# File 'lib/megar/adapters/file_downloader.rb', line 60

def download_size
  download_url_response['s']
end

#download_urlObject

Returns a download url for the file content



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

def download_url
  download_url_response['g']
end

#download_url_responseObject

Returns and caches a file download response



101
102
103
104
105
106
107
# File 'lib/megar/adapters/file_downloader.rb', line 101

def download_url_response
  @download_url_response ||= if live_session?
    session.get_file_download_url_response(file.id)
  else
    {}
  end
end

#initial_counter_valueObject

Returns the initial value for AES counter



96
97
98
# File 'lib/megar/adapters/file_downloader.rb', line 96

def initial_counter_value
  ((iv[0] << 32) + iv[1]) << 64
end

#ivObject

Returns the initialisation vector



72
73
74
# File 'lib/megar/adapters/file_downloader.rb', line 72

def iv
  @iv ||= key[4,2] + [0, 0]
end

#keyObject

Returns the file key (shortcut)



86
87
88
# File 'lib/megar/adapters/file_downloader.rb', line 86

def key
  file.key
end

#macObject

Returns the expected MAC for the file



81
82
83
# File 'lib/megar/adapters/file_downloader.rb', line 81

def mac
  key[6,2]
end

#raw_contentObject

Returns the complete encrypted content (mainly for testing purposes)



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

def raw_content
  return unless live_session?
  stream.read
end

#streamObject

Returns an io stream to the file content



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

def stream
  return unless live_session?
  @stream ||= if url = download_url
    open(url)
  end
end