An unofficial, mostly Bitwarden-compatible API server written in Ruby (Sinatra and ActiveRecord)
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at 5ccd4174b00a4af77c2baf9d7ab6a45eced19156 103 lines 3.5 kB view raw
1# 2# Copyright (c) 2017 joshua stein <jcs@jcs.org> 3# 4# Permission to use, copy, modify, and distribute this software for any 5# purpose with or without fee is hereby granted, provided that the above 6# copyright notice and this permission notice appear in all copies. 7# 8# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15# 16 17require "rotp" 18 19class User < DBModel 20 self.table_name = "users" 21 #set_primary_key "uuid" 22 23 DEFAULT_KDF_TYPE = Bitwarden::KDF::PBKDF2 24 25 before_create :generate_uuid_primary_key 26 before_validation :generate_security_stamp 27 28 has_many :ciphers, foreign_key: :user_uuid, inverse_of: :user 29 has_many :folders, foreign_key: :user_uuid, inverse_of: :user 30 has_many :devices, foreign_key: :user_uuid, inverse_of: :user 31 32 def decrypt_data_with_master_password_key(data, mk) 33 # self.key is random data encrypted with the key of (password,email), so 34 # create that key and decrypt the random data to get the original 35 # encryption key, then use that key to decrypt the data 36 encKey = Bitwarden.decrypt(self.key, mk) 37 Bitwarden.decrypt(data, encKey) 38 end 39 40 def encrypt_data_with_master_password_key(data, mk) 41 # self.key is random data encrypted with the key of (password,email), so 42 # create that key and decrypt the random data to get the original 43 # encryption key, then use that key to encrypt the data 44 encKey = Bitwarden.decrypt(self.key, mk) 45 Bitwarden.encrypt(data, encKey) 46 end 47 48 def has_password_hash?(hash) 49 self.password_hash.timingsafe_equal_to(hash) 50 end 51 52 def to_hash 53 { 54 "Id" => self.uuid, 55 "Name" => self.name, 56 "Email" => self.email, 57 "EmailVerified" => self.email_verified, 58 "Premium" => self.premium, 59 "MasterPasswordHint" => self.password_hint, 60 "Culture" => self.culture, 61 "TwoFactorEnabled" => self.two_factor_enabled?, 62 "Key" => self.key, 63 "PrivateKey" => nil, 64 "SecurityStamp" => self.security_stamp, 65 "Organizations" => [], 66 "Object" => "profile" 67 } 68 end 69 70 def two_factor_enabled? 71 self.totp_secret.present? 72 end 73 74 def update_master_password(old_pwd, new_pwd, 75 new_kdf_iterations = self.kdf_iterations) 76 # original random encryption key must be preserved, just re-encrypted with 77 # a new key derived from the new password 78 79 orig_key = Bitwarden.decrypt(self.key, 80 Bitwarden.makeKey(old_pwd, self.email, 81 Bitwarden::KDF::TYPES[self.kdf_type], self.kdf_iterations)) 82 83 self.key = Bitwarden.encrypt(orig_key, 84 Bitwarden.makeKey(new_pwd, self.email, 85 Bitwarden::KDF::TYPES[self.kdf_type], new_kdf_iterations)).to_s 86 87 self.password_hash = Bitwarden.hashPassword(new_pwd, self.email, 88 self.kdf_type, new_kdf_iterations) 89 self.kdf_iterations = new_kdf_iterations 90 self.security_stamp = SecureRandom.uuid 91 end 92 93 def verifies_totp_code?(code) 94 ROTP::TOTP.new(self.totp_secret).now == code.to_s 95 end 96 97protected 98 def generate_security_stamp 99 if self.security_stamp.blank? 100 self.security_stamp = SecureRandom.uuid 101 end 102 end 103end