# # Copyright (c) 2017-2018 joshua stein # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # class Cipher < DBModel self.table_name = "ciphers" #set_primary_key "uuid" before_create :generate_uuid_primary_key belongs_to :user, foreign_key: :user_uuid, inverse_of: :folders belongs_to :folder, foreign_key: :folder_uuid, inverse_of: :ciphers, optional: true has_many :attachments, foreign_key: :cipher_uuid, dependent: :destroy serialize :fields, JSON serialize :login, JSON serialize :securenote, JSON serialize :card, JSON serialize :identity, JSON serialize :passwordhistory, JSON TYPE_LOGIN = 1 TYPE_NOTE = 2 TYPE_CARD = 3 TYPE_IDENTITY = 4 def self.type_s(type) case type when TYPE_LOGIN "login" when TYPE_NOTE "note" when TYPE_CARD "card" when TYPE_IDENTITY "identity" else type.to_s end end # migrate from older style everything-in-data to separate fields def migrate_data! return false if !self.data js = JSON.parse(self.data) return false if !js self.name = js.delete("Name") self.notes = js.delete("Notes") self.fields = js.delete("Fields") if self.type == TYPE_LOGIN js["Uris"] = [ { "Uri" => js["Uri"], "Match" => nil }, ] js.delete("Uri") end # move the remaining fields into the new dedicated field based on the type fmap = { TYPE_LOGIN => "login", TYPE_NOTE => "securenote", TYPE_CARD => "card", TYPE_IDENTITY => "identity", } self.send("#{fmap[self.type]}=", js) self.save || raise("failed migrating #{self.inspect}") true end def to_hash { "Id" => self.uuid, "Type" => self.type, "RevisionDate" => self.updated_at.strftime("%Y-%m-%dT%H:%M:%S.000000Z"), "FolderId" => self.folder_uuid, "Favorite" => self.favorite, "OrganizationId" => nil, "Attachments" => self.attachments.map(&:to_hash), "OrganizationUseTotp" => false, "Object" => "cipher", "Name" => self.name, "Notes" => self.notes, "Fields" => self.fields, "Login" => self.login, "Card" => self.card, "Identity" => self.identity, "SecureNote" => self.securenote, "PasswordHistory" => self.passwordhistory, } end def update_from_params(params) self.folder_uuid = params[:folderid] self.organization_uuid = params[:organizationid] self.favorite = params[:favorite] self.type = params[:type].to_i self.name = params[:name] self.notes = params[:notes] self.fields = nil if params[:fields] && params[:fields].is_a?(Array) self.fields = params[:fields].map{|h| h.ucfirst_hash } end case self.type when TYPE_LOGIN tlogin = params[:login].ucfirst_hash if tlogin["Uris"] && tlogin["Uris"].is_a?(Array) tlogin["Uris"].map!{|h| h.ucfirst_hash } end self.login = tlogin if params[:passwordhistory].present? self.passwordhistory = params[:passwordhistory]. map{|ph| ph.ucfirst_hash } else self.passwordhistory = nil end when TYPE_NOTE self.securenote = params[:securenote].ucfirst_hash when TYPE_CARD self.card = params[:card].ucfirst_hash when TYPE_IDENTITY self.identity = params[:identity].ucfirst_hash end end end