I'm trying use Lockbox to encrypt and decrypt file uploads, but the documentation assumes knowledge that I am unaware I lack, and the person who maintains the repo seems too busy to provide any help. Could someone please help me understand this?
The documentation says that the master key is used to create a cipher which is stored on the model. It says that the schema fields for this cipher should be text or binary and named like attribute_ciphertext as opposed to just plain attribute. As a result, my model looks like this:
class IdentityDocument < ApplicationRecord
belongs_to :user, foreign_key: :user_id
validates :document_front_ciphertext, :document_back_ciphertext, presence: true
mount_uploader :document_front_ciphertext, IdentityDocumentsUploader
mount_uploader :document_back_ciphertext, IdentityDocumentsUploader
end
According to the section on CarrierWave, encryption is as easy as adding an encrypt to my uploader:
class IdentityDocumentsUploader < CarrierWave::Uploader::Base
encrypt
end
The controller creates the model:
def create
@id_doc = current_user.identity_documents.new(id_doc_params)
end
def id_doc_params
params.require(:identity_document).permit(:document_front_ciphertext, :document_back_ciphertext)
end
And the view submits the params to the controller:
<%= form_for @id_doc do |f| %>
<%= f.label :document_front_ciphertext, "Front of driver's license or other state ID" %>
<%= f.file_field :document_front_ciphertext %>
<%= f.label :document_back_ciphertext, "Back of driver's license or other state ID" %>
<%= f.file_field :document_back_ciphertext %>
<%= f.submit "Upload", data: { disable: true } %>
<% end %>
The SQL output for this looks unencrypted (which I guess intended? Maybe file uploads don't need encrypted database fields, and I don't need the _ciphertext in my schema?):
INSERT INTO "identity_documents" ("user_id", "document_front_ciphertext", "document_back_ciphertext") VALUES ($1, $2, $3) RETURNING "id" [["user_id", 1], ["document_front_ciphertext", "california-drivers-license.jpg"], ["document_back_ciphertext", "2016-11-25-license-4.jpg"]]
Querying this model in my console looks something like this:
id = IdentityDocument.find 4
#<IdentityDocument id: 4, user_id: 1, document_front_ciphertext: "california-drivers-license.jpg", document_back_ciphertext: "2016-11-25-license-4.jpg">
id.document_front_ciphertext
#<IdentityDocumentsUploader:0x00007fec0cfad980 @model=#<IdentityDocument id: 4, user_id: 1, document_front_ciphertext: "california-drivers-license.jpg", document_back_ciphertext: "2016-11-25-license-4.jpg">, @mounted_as=:document_front_ciphertext, @file=#<CarrierWave::SanitizedFile:0x00007fec0cfad098 @file="/Users/me/code/site/public/uploads/identity_document/document_front_ciphertext/4/california-drivers-license.jpg", @original_filename=nil, @content_type=nil, @content=nil>, @filename=nil, @cache_id=nil, @versions={}, @format=nil, @storage=#<CarrierWave::Storage::File:0x00007fec0cfad7c8 @uploader=#<IdentityDocumentsUploader:0x00007fec0cfad980 ...>, @cache_called=nil>>
For some reason this Uploader includes the entire model, but only the first image is available through @file or @mounted_as.
Which brings me to decryption and showing the image to an admin. The docs say to do something like this in my controller:
def id_document
send_data user.identity_document.document_front_ciphertext.read, type: user.identity_document.document_front_ciphertext.content_type
end
...however, this results in a Errno::ENAMETOOLONG error. If I change the read to path at the end of send_data's first argument, my view fills up with...what I think is an encrypted file? It looks something like this:
/Users/me/code/project/public/uploads/identity_document/document_front_ciphertext/1/OWkN7fKEetY2vBWXxkAdWFr96aKOF7Abt8Q7E5cNWvK7zALMwUoH63ZpvYnvYQ7mLqbf32Imqdt+85WpyLjPKf+xmEjHIJ3U7PQNviMDJsBl+OHQRLsfurqNMY2IJXYvmoZLuFN0MykG7BEj9+aKodN0qxlQIHfMQEPBzdQ2G5iss46l7qlyImXt/BH64LYbDxxUqTfCB8B6N7UEZTWy7o8v2ggchQVtleQtxeYsSQoknPlXwa5eEe604c+CHWBXMjisF4LwP+cGcL+j8oIEg+vqwZo3Firxh367b+wzutBWGPNEzNVVtvSKEPToxu9aFjJrBPLwR3LTl8bLqap88i2MqkmtUtAT5UL4514OdqGh5dBduGnpAFOTMVCW4lBPZ7XGltjwCbZ+nLdCAQcT/xgCNRZ8qNpPzTOMsUbNJktwiM5J2J7YfX/H0lhG0CBxFxoGc0FoXs1+Jx82pCHJAdoemk4HNTXIRR3F0qgoVAi16F2wz2ofCJ0DQZT9h5witwxg3XpMYitUw/UnGCoCQpzxV60scnaCRb05wavDRR/97XQvFpBWxIFOjt0MJEzMCpTpCa51KT94a9Q9dL+P04MSQNQ7XVDRvqdsp1LYXKmoxAeBhdZQeOTjBvyLyDvI+TBkqQl/WwsgaabeFDw0O8ovo46yVl0OjjHQZOYmFgRz8VHX0iF6xfiqPRXnZlTB/BbhbRocnEGXav1DpwhLeEFtm/2OigZglBNtbI7B2t6EsEq87/eFHMRjbfUHGAovxfBlc3ZFXS9IlGFmhr5NdhBbEW/oaXc0ZpvR7tTx6H+yyvv6HFAa0tSwV6JThCc3OlvMGpykhQ3R58J5E1BYe/NJrKM3VlvTBptQEP4+RFDct83sthbCYwhlclAeAPDLPjbop6CaA35iV+9skkb1cpGlj3NLx7hY66ZloVDiE8JhCLD/sQTcvZ0zQ3/r7VFeXydiQZpu4QTA9v0Q+Cq5X+qMe1g5cc3cpfP90LfqfIag8Z+Scl18cNteqArl0Ex/lqQktLVINfZW5J+jvXZTV2Al9F5XW14NGlznXe9R4TT4XnlOzHDodThboLtMngWlIf3v/aywevcOE1TtqmxdwGu5wbsaffzKdZGDaxTWuiapMRn4IJUp7zYxUOSAipL7x++Ski+su5bgbUw/Gn2KFomCYRwwvEH1wVKl6BDajL29K6LEFF/jLHEdvwVhj22G0II747xkKtybHStSRrx+3vV...
So....how exactly do I display these images? I'm on the right path ;) but I'm very confused.