From 00e09493c48762d14ab0a93b6642667a00c54c83 Mon Sep 17 00:00:00 2001 From: joshua stein Date: Sat, 25 May 2019 21:07:16 -0500 Subject: [PATCH 01/33] Cipher: add password history tracking This is just a simple array that the Bitwarden clients manage for us, so just pass it through to the db. Closes #89 --- db/migrate/20190526014920_password_history.rb | 5 +++++ lib/cipher.rb | 9 +++++++++ 2 files changed, 14 insertions(+) create mode 100644 db/migrate/20190526014920_password_history.rb diff --git a/db/migrate/20190526014920_password_history.rb b/db/migrate/20190526014920_password_history.rb new file mode 100644 index 0000000..c7374ee --- /dev/null +++ b/db/migrate/20190526014920_password_history.rb @@ -0,0 +1,5 @@ +class PasswordHistory < ActiveRecord::Migration[5.1] + def change + add_column :ciphers, :passwordhistory, :binary + end +end diff --git a/lib/cipher.rb b/lib/cipher.rb index a9dd0f7..b1b5950 100644 --- a/lib/cipher.rb +++ b/lib/cipher.rb @@ -29,6 +29,7 @@ class Cipher < DBModel serialize :securenote, JSON serialize :card, JSON serialize :identity, JSON + serialize :passwordhistory, JSON TYPE_LOGIN = 1 TYPE_NOTE = 2 @@ -99,6 +100,7 @@ def to_hash "Card" => self.card, "Identity" => self.identity, "SecureNote" => self.securenote, + "PasswordHistory" => self.passwordhistory, } end @@ -126,6 +128,13 @@ def update_from_params(params) 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 From eafbf20f94743fa0c03bdb817e8633f935c7db96 Mon Sep 17 00:00:00 2001 From: joshua stein Date: Sat, 25 May 2019 21:10:34 -0500 Subject: [PATCH 02/33] attachments: validate device bearer on attachment creation --- lib/routes/attachments.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/routes/attachments.rb b/lib/routes/attachments.rb index 748256f..4b3273c 100644 --- a/lib/routes/attachments.rb +++ b/lib/routes/attachments.rb @@ -20,6 +20,10 @@ module Attachments def self.registered(app) app.namespace BASE_URL do post "/ciphers/:uuid/attachment" do + if !device_from_bearer + return validation_error("invalid bearer") + end + cipher = retrieve_cipher uuid: params[:uuid] need_params(:data) do |p| @@ -62,6 +66,8 @@ def self.registered(app) app.namespace ATTACHMENTS_URL do get "/:uuid/:attachment_id" do + # no device authentication + a = Attachment.find_by_uuid_and_cipher_uuid(params[:attachment_id], params[:uuid]) attachment(a.filename) From 8208d89ce18efc3dc8dab015225db396ae6dc48a Mon Sep 17 00:00:00 2001 From: Johannes Date: Sun, 14 Oct 2018 10:51:06 +0200 Subject: [PATCH 03/33] move request helpers to module and include in spec_helper add inital stab at "factory" for creating and logging in users --- lib/app.rb | 2 +- spec/attachment_spec.rb | 35 ++-------------------------- spec/bitwarden_importer_spec.rb | 16 +------------ spec/cipher_spec.rb | 35 ++-------------------------- spec/folder_spec.rb | 38 ++---------------------------- spec/spec_helper.rb | 27 +++------------------- spec/support/factories.rb | 41 +++++++++++++++++++++++++++++++++ spec/support/request_helpers.rb | 30 ++++++++++++++++++++++++ spec/user_spec.rb | 11 +-------- 9 files changed, 83 insertions(+), 152 deletions(-) create mode 100644 spec/support/factories.rb create mode 100644 spec/support/request_helpers.rb diff --git a/lib/app.rb b/lib/app.rb index 4785f04..daccc9e 100644 --- a/lib/app.rb +++ b/lib/app.rb @@ -30,7 +30,7 @@ class App < Sinatra::Base register Sinatra::Namespace register Sinatra::ActiveRecordExtension - set :root, File.dirname(__FILE__) + set :root, File.expand_path("..", File.dirname(__FILE__)) configure do enable :logging diff --git a/spec/attachment_spec.rb b/spec/attachment_spec.rb index ad843f1..a8f623a 100644 --- a/spec/attachment_spec.rb +++ b/spec/attachment_spec.rb @@ -8,39 +8,8 @@ before do User.all.delete_all - post "/api/accounts/register", { - :name => nil, - :email => "api@example.com", - :masterPasswordHash => Bitwarden.hashPassword("asdf", "api@example.com", - User::DEFAULT_KDF_TYPE, - Bitwarden::KDF::DEFAULT_ITERATIONS[User::DEFAULT_KDF_TYPE]), - :masterPasswordHint => nil, - :key => Bitwarden.makeEncKey( - Bitwarden.makeKey("adsf", "api@example.com", - User::DEFAULT_KDF_TYPE, - Bitwarden::KDF::DEFAULT_ITERATIONS[User::DEFAULT_KDF_TYPE]), - ), - :kdf => Bitwarden::KDF::TYPE_IDS[User::DEFAULT_KDF_TYPE], - :kdfIterations => Bitwarden::KDF::DEFAULT_ITERATIONS[User::DEFAULT_KDF_TYPE], - } - last_response.status.must_equal 200 - - post "/identity/connect/token", { - :grant_type => "password", - :username => "api@example.com", - :password => Bitwarden.hashPassword("asdf", "api@example.com", - User::DEFAULT_KDF_TYPE, - Bitwarden::KDF::DEFAULT_ITERATIONS[User::DEFAULT_KDF_TYPE]), - :scope => "api offline_access", - :client_id => "browser", - :deviceType => 3, - :deviceIdentifier => SecureRandom.uuid, - :deviceName => "firefox", - :devicePushToken => "" - } - last_response.status.must_equal 200 - - @access_token = last_json_response["access_token"] + Rubywarden::Test::Factory.create_user + @access_token = Rubywarden::Test::Factory.login_user post_json "/api/ciphers", { :type => 1, diff --git a/spec/bitwarden_importer_spec.rb b/spec/bitwarden_importer_spec.rb index 4f9ce5a..0f96014 100644 --- a/spec/bitwarden_importer_spec.rb +++ b/spec/bitwarden_importer_spec.rb @@ -10,21 +10,7 @@ @master_key = Bitwarden.makeKey(@password, @email, User::DEFAULT_KDF_TYPE, Bitwarden::KDF::DEFAULT_ITERATIONS[User::DEFAULT_KDF_TYPE]) - - post "/api/accounts/register", { - :name => nil, - :email => @email, - :masterPasswordHash => Bitwarden.hashPassword(@password, @email, - User::DEFAULT_KDF_TYPE, - Bitwarden::KDF::DEFAULT_ITERATIONS[User::DEFAULT_KDF_TYPE]), - :masterPasswordHint => nil, - :key => Bitwarden.makeEncKey(@master_key), - :kdf => Bitwarden::KDF::TYPE_IDS[User::DEFAULT_KDF_TYPE], - :kdfIterations => Bitwarden::KDF::DEFAULT_ITERATIONS[User::DEFAULT_KDF_TYPE], - } - last_response.status.must_equal 200 - - @user = User.where(:email => @email).first! + @user = Rubywarden::Test::Factory.create_user email: @email, password: @password end it "imports all expected data" do diff --git a/spec/cipher_spec.rb b/spec/cipher_spec.rb index fc984f3..a39f88c 100644 --- a/spec/cipher_spec.rb +++ b/spec/cipher_spec.rb @@ -6,39 +6,8 @@ before do User.all.delete_all - post "/api/accounts/register", { - :name => nil, - :email => "api@example.com", - :masterPasswordHash => Bitwarden.hashPassword("asdf", "api@example.com", - User::DEFAULT_KDF_TYPE, - Bitwarden::KDF::DEFAULT_ITERATIONS[User::DEFAULT_KDF_TYPE]), - :masterPasswordHint => nil, - :key => Bitwarden.makeEncKey( - Bitwarden.makeKey("adsf", "api@example.com", - User::DEFAULT_KDF_TYPE, - Bitwarden::KDF::DEFAULT_ITERATIONS[User::DEFAULT_KDF_TYPE]), - ), - :kdf => Bitwarden::KDF::TYPE_IDS[User::DEFAULT_KDF_TYPE], - :kdfIterations => Bitwarden::KDF::DEFAULT_ITERATIONS[User::DEFAULT_KDF_TYPE], - } - last_response.status.must_equal 200 - - post "/identity/connect/token", { - :grant_type => "password", - :username => "api@example.com", - :password => Bitwarden.hashPassword("asdf", "api@example.com", - User::DEFAULT_KDF_TYPE, - Bitwarden::KDF::DEFAULT_ITERATIONS[User::DEFAULT_KDF_TYPE]), - :scope => "api offline_access", - :client_id => "browser", - :deviceType => 3, - :deviceIdentifier => SecureRandom.uuid, - :deviceName => "firefox", - :devicePushToken => "" - } - last_response.status.must_equal 200 - - @access_token = last_json_response["access_token"] + Rubywarden::Test::Factory.create_user + @access_token = Rubywarden::Test::Factory.login_user end it "should not allow access with bogus bearer token" do diff --git a/spec/folder_spec.rb b/spec/folder_spec.rb index 4b9393d..b5bb902 100644 --- a/spec/folder_spec.rb +++ b/spec/folder_spec.rb @@ -6,42 +6,8 @@ before do User.all.delete_all - post "/api/accounts/register", { - :name => nil, - :email => "api@example.com", - :masterPasswordHash => Bitwarden.hashPassword("asdf", "api@example.com", - User::DEFAULT_KDF_TYPE, - Bitwarden::KDF::DEFAULT_ITERATIONS[User::DEFAULT_KDF_TYPE]), - :masterPasswordHint => nil, - :key => Bitwarden.makeEncKey( - Bitwarden.makeKey("adsf", "api@example.com", User::DEFAULT_KDF_TYPE, - Bitwarden::KDF::DEFAULT_ITERATIONS[User::DEFAULT_KDF_TYPE]), - ), - :kdf => Bitwarden::KDF::TYPE_IDS[User::DEFAULT_KDF_TYPE], - :kdfIterations => Bitwarden::KDF::DEFAULT_ITERATIONS[User::DEFAULT_KDF_TYPE], - } - if last_response.status != 200 - raise last_response.inspect - end - - post "/identity/connect/token", { - :grant_type => "password", - :username => "api@example.com", - :password => Bitwarden.hashPassword("asdf", "api@example.com", - User::DEFAULT_KDF_TYPE, - Bitwarden::KDF::DEFAULT_ITERATIONS[User::DEFAULT_KDF_TYPE]), - :scope => "api offline_access", - :client_id => "browser", - :deviceType => 3, - :deviceIdentifier => SecureRandom.uuid, - :deviceName => "firefox", - :devicePushToken => "" - } - if last_response.status != 200 - raise last_response.inspect - end - - @access_token = last_json_response["access_token"] + Rubywarden::Test::Factory.create_user + @access_token = Rubywarden::Test::Factory.login_user end it "should not allow access with bogus bearer token" do diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 0f10da3..5c87815 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -18,36 +18,15 @@ ActiveRecord::Migrator.up "db/migrate" # in case migrations changed what we're testing -[ User, Cipher, Device, Folder ].each do |c| +[ Attachment, User, Cipher, Device, Folder ].each do |c| c.send(:reset_column_information) end include Rack::Test::Methods -def last_json_response - JSON.parse(last_response.body) -end - -def get_json(path, params = {}, headers = {}) - json_request :get, path, params, headers -end - -def post_json(path, params = {}, headers = {}) - json_request :post, path, params, headers -end +Dir[Rubywarden::App.settings.root + '/spec/support/**/*.rb'].sort.each { |f| require f } +include Rubywarden::Test::RequestHelpers -def put_json(path, params = {}, headers = {}) - json_request :put, path, params, headers -end - -def delete_json(path, params = {}, headers = {}) - json_request :delete, path, params, headers -end - -def json_request(verb, path, params = {}, headers = {}) - send verb, path, params.to_json, - headers.merge({ "CONTENT_TYPE" => "application/json" }) -end def app Rubywarden::App diff --git a/spec/support/factories.rb b/spec/support/factories.rb new file mode 100644 index 0000000..b196720 --- /dev/null +++ b/spec/support/factories.rb @@ -0,0 +1,41 @@ +module Rubywarden + module Test + class Factory + USER_EMAIL = "user@example.com" + USER_PASSWORD = "p4ssw0rd" + + def self.create_user email: USER_EMAIL, password: USER_PASSWORD + u = User.new + u.email = email + u.kdf_type = Bitwarden::KDF::TYPE_IDS[User::DEFAULT_KDF_TYPE] + u.kdf_iterations = Bitwarden::KDF::DEFAULT_ITERATIONS[User::DEFAULT_KDF_TYPE] + u.password_hash = Bitwarden.hashPassword(password, email, + Bitwarden::KDF::TYPES[u.kdf_type], u.kdf_iterations) + u.password_hint = "it's like password but not" + u.key = Bitwarden.makeEncKey(Bitwarden.makeKey(password, email, + Bitwarden::KDF::TYPES[u.kdf_type], u.kdf_iterations)) + u.save + u + end + + def self.login_user email: USER_EMAIL, password: USER_PASSWORD + post "/identity/connect/token", { + :grant_type => "password", + :username => email, + :password => Bitwarden.hashPassword(password, email, + User::DEFAULT_KDF_TYPE, + Bitwarden::KDF::DEFAULT_ITERATIONS[User::DEFAULT_KDF_TYPE]), + :scope => "api offline_access", + :client_id => "browser", + :deviceType => 3, + :deviceIdentifier => SecureRandom.uuid, + :deviceName => "firefox", + :devicePushToken => "" + } + last_response.status.must_equal 200 + + last_json_response["access_token"] + end + end + end +end diff --git a/spec/support/request_helpers.rb b/spec/support/request_helpers.rb new file mode 100644 index 0000000..ee0e58b --- /dev/null +++ b/spec/support/request_helpers.rb @@ -0,0 +1,30 @@ +module Rubywarden + module Test + module RequestHelpers + def last_json_response + JSON.parse(last_response.body) + end + + def get_json(path, params = {}, headers = {}) + json_request :get, path, params, headers + end + + def post_json(path, params = {}, headers = {}) + json_request :post, path, params, headers + end + + def put_json(path, params = {}, headers = {}) + json_request :put, path, params, headers + end + + def delete_json(path, params = {}, headers = {}) + json_request :delete, path, params, headers + end + + def json_request(verb, path, params = {}, headers = {}) + send verb, path, params.to_json, + headers.merge({ "CONTENT_TYPE" => "application/json" }) + end + end + end +end \ No newline at end of file diff --git a/spec/user_spec.rb b/spec/user_spec.rb index 592a28b..94fe9d0 100644 --- a/spec/user_spec.rb +++ b/spec/user_spec.rb @@ -7,16 +7,7 @@ before do User.all.delete_all - u = User.new - u.email = USER_EMAIL - u.kdf_type = Bitwarden::KDF::TYPE_IDS[User::DEFAULT_KDF_TYPE] - u.kdf_iterations = Bitwarden::KDF::DEFAULT_ITERATIONS[User::DEFAULT_KDF_TYPE] - u.password_hash = Bitwarden.hashPassword(USER_PASSWORD, USER_EMAIL, - Bitwarden::KDF::TYPES[u.kdf_type], u.kdf_iterations) - u.password_hint = "it's like password but not" - u.key = Bitwarden.makeEncKey(Bitwarden.makeKey(USER_PASSWORD, USER_EMAIL, - Bitwarden::KDF::TYPES[u.kdf_type], u.kdf_iterations)) - u.save + u = Rubywarden::Test::Factory.create_user email: USER_EMAIL, password: USER_PASSWORD end it "should compare a user's hash" do From ec222b378f7b12b349e4759504bf0e22dfb89d55 Mon Sep 17 00:00:00 2001 From: joshua stein Date: Sat, 25 May 2019 21:19:31 -0500 Subject: [PATCH 04/33] Rakefile: setup 'test' as default task --- Rakefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Rakefile b/Rakefile index 6866299..e6c9f3e 100644 --- a/Rakefile +++ b/Rakefile @@ -12,4 +12,6 @@ require 'rake/testtask' Rake::TestTask.new do |t| t.libs << "spec" t.pattern = "spec/*_spec.rb" -end \ No newline at end of file +end + +task :default => [ :test ] From d2a9250b724ab309d6d39c55f028b14117278bfe Mon Sep 17 00:00:00 2001 From: joshua stein Date: Sat, 25 May 2019 21:19:43 -0500 Subject: [PATCH 05/33] user_spec: remove assignment to unused variable --- spec/user_spec.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/spec/user_spec.rb b/spec/user_spec.rb index 94fe9d0..3b79ba6 100644 --- a/spec/user_spec.rb +++ b/spec/user_spec.rb @@ -6,8 +6,7 @@ before do User.all.delete_all - - u = Rubywarden::Test::Factory.create_user email: USER_EMAIL, password: USER_PASSWORD + Rubywarden::Test::Factory.create_user email: USER_EMAIL, password: USER_PASSWORD end it "should compare a user's hash" do From 3c5a7ca658dd8cb5f25e4624949bab58a5b34ecb Mon Sep 17 00:00:00 2001 From: joshua stein Date: Wed, 24 Jul 2019 11:39:04 -0500 Subject: [PATCH 06/33] Change users.kdf_iterations to not nullable The upstream clients may crash if this value is returned as null Issue #100 --- .../20190724163354_no_null_kdf_iterations.rb | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 db/migrate/20190724163354_no_null_kdf_iterations.rb diff --git a/db/migrate/20190724163354_no_null_kdf_iterations.rb b/db/migrate/20190724163354_no_null_kdf_iterations.rb new file mode 100644 index 0000000..2b9bd96 --- /dev/null +++ b/db/migrate/20190724163354_no_null_kdf_iterations.rb @@ -0,0 +1,16 @@ +class NoNullKdfIterations < ActiveRecord::Migration[5.1] + def change + User.all.each do |u| + if !u.kdf_iterations + u.kdf_iterations = Bitwarden::KDF::DEFAULT_ITERATIONS[User::DEFAULT_KDF_TYPE] + end + if !u.kdf_type + u.kdf_type = User::DEFAULT_KDF_TYPE + end + u.save! + end + + change_column :users, :kdf_iterations, :integer, :null => false, + :default => Bitwarden::KDF::DEFAULT_ITERATIONS[User::DEFAULT_KDF_TYPE] + end +end From 2ee5150748b80c6af2e5dc1956deb095d98a2aa8 Mon Sep 17 00:00:00 2001 From: joshua stein Date: Wed, 24 Jul 2019 11:45:36 -0500 Subject: [PATCH 07/33] Gemfile: update activerecord to update actionview --- Gemfile | 2 +- Gemfile.lock | 96 ++++++++++++++++++++++++++-------------------------- 2 files changed, 49 insertions(+), 49 deletions(-) diff --git a/Gemfile b/Gemfile index 8579076..5ed4fbc 100644 --- a/Gemfile +++ b/Gemfile @@ -7,7 +7,7 @@ gem "rack", ">= 2.0.6" gem "sinatra", "~> 2.0.3" gem "sinatra-contrib", "~> 2.0.3" -gem "activerecord", "~> 5.1.5" +gem "activerecord", "~> 5.1.7" gem "sinatra-activerecord", "~> 2.0.13" gem "sqlite3" diff --git a/Gemfile.lock b/Gemfile.lock index 891427b..05e15a0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,39 +1,39 @@ GEM remote: https://rubygems.org/ specs: - actioncable (5.1.6) - actionpack (= 5.1.6) + actioncable (5.1.7) + actionpack (= 5.1.7) nio4r (~> 2.0) websocket-driver (~> 0.6.1) - actionmailer (5.1.6) - actionpack (= 5.1.6) - actionview (= 5.1.6) - activejob (= 5.1.6) + actionmailer (5.1.7) + actionpack (= 5.1.7) + actionview (= 5.1.7) + activejob (= 5.1.7) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (5.1.6) - actionview (= 5.1.6) - activesupport (= 5.1.6) + actionpack (5.1.7) + actionview (= 5.1.7) + activesupport (= 5.1.7) rack (~> 2.0) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (5.1.6) - activesupport (= 5.1.6) + actionview (5.1.7) + activesupport (= 5.1.7) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.3) - activejob (5.1.6) - activesupport (= 5.1.6) + activejob (5.1.7) + activesupport (= 5.1.7) globalid (>= 0.3.6) - activemodel (5.1.6) - activesupport (= 5.1.6) - activerecord (5.1.6) - activemodel (= 5.1.6) - activesupport (= 5.1.6) + activemodel (5.1.7) + activesupport (= 5.1.7) + activerecord (5.1.7) + activemodel (= 5.1.7) + activesupport (= 5.1.7) arel (~> 8.0) - activesupport (5.1.6) + activesupport (5.1.7) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) @@ -43,16 +43,16 @@ GEM builder (3.2.3) chunky_png (1.3.10) coderay (1.1.2) - concurrent-ruby (1.0.5) + concurrent-ruby (1.1.5) crass (1.0.4) djinni (2.2.4) fagin (~> 1.2, >= 1.2.1) - erubi (1.7.1) + erubi (1.8.0) fagin (1.2.1) - globalid (0.4.1) + globalid (0.4.2) activesupport (>= 4.2.0) hilighter (1.2.3) - i18n (1.0.1) + i18n (1.6.0) concurrent-ruby (~> 1.0) json (2.1.0) json_config (0.1.4) @@ -61,52 +61,52 @@ GEM loofah (2.2.3) crass (~> 1.0.2) nokogiri (>= 1.5.9) - mail (2.7.0) + mail (2.7.1) mini_mime (>= 0.1.1) - method_source (0.9.0) - mini_mime (1.0.0) - mini_portile2 (2.3.0) + method_source (0.9.2) + mini_mime (1.0.2) + mini_portile2 (2.4.0) minitest (5.11.3) multi_json (1.13.1) mustermann (1.0.2) - nio4r (2.3.1) - nokogiri (1.8.5) - mini_portile2 (~> 2.3.0) + nio4r (2.4.0) + nokogiri (1.10.3) + mini_portile2 (~> 2.4.0) os (1.0.0) pbkdf2-ruby (0.2.1) pry (0.11.3) coderay (~> 1.1.0) method_source (~> 0.9.0) - rack (2.0.6) + rack (2.0.7) rack-protection (2.0.3) rack rack-test (1.1.0) rack (>= 1.0, < 3) - rails (5.1.6) - actioncable (= 5.1.6) - actionmailer (= 5.1.6) - actionpack (= 5.1.6) - actionview (= 5.1.6) - activejob (= 5.1.6) - activemodel (= 5.1.6) - activerecord (= 5.1.6) - activesupport (= 5.1.6) + rails (5.1.7) + actioncable (= 5.1.7) + actionmailer (= 5.1.7) + actionpack (= 5.1.7) + actionview (= 5.1.7) + activejob (= 5.1.7) + activemodel (= 5.1.7) + activerecord (= 5.1.7) + activesupport (= 5.1.7) bundler (>= 1.3.0) - railties (= 5.1.6) + railties (= 5.1.7) sprockets-rails (>= 2.0.0) rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) rails-html-sanitizer (1.0.4) loofah (~> 2.2, >= 2.2.2) - railties (5.1.6) - actionpack (= 5.1.6) - activesupport (= 5.1.6) + railties (5.1.7) + actionpack (= 5.1.7) + activesupport (= 5.1.7) method_source rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) raindrops (0.19.0) - rake (12.3.1) + rake (12.3.3) rotp (3.3.1) rqrcode (0.10.1) chunky_png (~> 1.0) @@ -144,7 +144,7 @@ GEM activesupport (>= 4.0) sprockets (>= 3.0.0) sqlite3 (1.3.13) - thor (0.20.0) + thor (0.20.3) thread_safe (0.3.6) tilt (2.0.8) twofish (1.0.8) @@ -155,7 +155,7 @@ GEM raindrops (~> 0.7) websocket-driver (0.6.5) websocket-extensions (>= 0.1.0) - websocket-extensions (0.1.3) + websocket-extensions (0.1.4) yaml_db (0.7.0) rails (>= 3.0) rake (>= 0.8.7) @@ -164,7 +164,7 @@ PLATFORMS ruby DEPENDENCIES - activerecord (~> 5.1.5) + activerecord (~> 5.1.7) json jwt minitest From 4b340c41c24ad1c7ffee26e88fa0016ec69b5f75 Mon Sep 17 00:00:00 2001 From: joshua stein Date: Wed, 24 Jul 2019 12:36:56 -0500 Subject: [PATCH 08/33] tools/change_master_password: support changing KDF iterations closes #90 --- lib/user.rb | 8 +++++--- tools/change_master_password.rb | 21 ++++++++++++++++++++- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/lib/user.rb b/lib/user.rb index 0fb480e..ce1e6ef 100644 --- a/lib/user.rb +++ b/lib/user.rb @@ -71,7 +71,8 @@ def two_factor_enabled? self.totp_secret.present? end - def update_master_password(old_pwd, new_pwd) + def update_master_password(old_pwd, new_pwd, + new_kdf_iterations = self.kdf_iterations) # original random encryption key must be preserved, just re-encrypted with # a new key derived from the new password @@ -81,10 +82,11 @@ def update_master_password(old_pwd, new_pwd) self.key = Bitwarden.encrypt(orig_key, Bitwarden.makeKey(new_pwd, self.email, - Bitwarden::KDF::TYPES[self.kdf_type], self.kdf_iterations)).to_s + Bitwarden::KDF::TYPES[self.kdf_type], new_kdf_iterations)).to_s self.password_hash = Bitwarden.hashPassword(new_pwd, self.email, - self.kdf_type, self.kdf_iterations) + self.kdf_type, new_kdf_iterations) + self.kdf_iterations = new_kdf_iterations self.security_stamp = SecureRandom.uuid end diff --git a/tools/change_master_password.rb b/tools/change_master_password.rb index 0eb5921..8e9637d 100644 --- a/tools/change_master_password.rb +++ b/tools/change_master_password.rb @@ -87,7 +87,26 @@ def usage end end -@u.update_master_password(password, new_master) +new_kdf_iterations = nil +while new_kdf_iterations.to_s == "" + print "kdf iterations (currently #{@u.kdf_iterations}, default " << + "#{Bitwarden::KDF::DEFAULT_ITERATIONS[@u.kdf_type]}): " + new_kdf_iterations = STDIN.gets.chomp + + if new_kdf_iterations.to_s == "" + new_kdf_iterations = Bitwarden::KDF::DEFAULT_ITERATIONS[@u.kdf_type] + break + elsif !(r = Bitwarden::KDF::ITERATION_RANGES[@u.kdf_type]). + include?(new_kdf_iterations.to_i) + puts "iterations must be between #{r}" + new_kdf_iterations = nil + else + new_kdf_iterations = new_kdf_iterations.to_i + break + end +end + +@u.update_master_password(password, new_master, new_kdf_iterations) @u.password_hint = new_master_hint if !@u.save puts "error saving new password" From 5ccd4174b00a4af77c2baf9d7ab6a45eced19156 Mon Sep 17 00:00:00 2001 From: joshua stein Date: Wed, 24 Jul 2019 12:38:40 -0500 Subject: [PATCH 09/33] Bitwarden: update default PBKDF2 iterations to 100,000 This matches at least the Firefox extension when creating a new account. --- lib/bitwarden.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/bitwarden.rb b/lib/bitwarden.rb index 8f6a90d..7c2929d 100644 --- a/lib/bitwarden.rb +++ b/lib/bitwarden.rb @@ -29,7 +29,7 @@ class Bitwarden::KDF TYPE_IDS = TYPES.invert DEFAULT_ITERATIONS = { - PBKDF2 => 5000, + PBKDF2 => 100_000, } ITERATION_RANGES = { From f19b9e9853db544aefa1ec51be438729099388df Mon Sep 17 00:00:00 2001 From: joshua stein Date: Wed, 24 Jul 2019 12:47:13 -0500 Subject: [PATCH 10/33] spec: update hash result with new default iterations --- spec/identity_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/identity_spec.rb b/spec/identity_spec.rb index b1b3011..452f2fa 100644 --- a/spec/identity_spec.rb +++ b/spec/identity_spec.rb @@ -109,7 +109,7 @@ (u = User.find_by_email("nobody4@example.com")).wont_be_nil u.uuid.wont_be_nil - u.password_hash.must_equal "PGC1vNJZUL3z5wTKAgpXsODf6KzIPcr0XCzTplceXQU=" + u.password_hash.must_equal "uQOY5dffPoKCueMu3cMXl2KOL52NerIQlwCEpQ6mW6s=" post "/api/accounts/prelogin", { :email => "nobody4@example.com", From c55f926548abc25e763bfcab862e1dbfa8df201f Mon Sep 17 00:00:00 2001 From: joshua stein Date: Wed, 24 Jul 2019 22:21:30 -0500 Subject: [PATCH 11/33] Fix 3c5a7ca65 Set null kdf_iterations to 5000, which is what the old default used to be. As the default changes in the future (or as it did in 5ccd4174b), this should still be 5000. --- db/migrate/20190724163354_no_null_kdf_iterations.rb | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/db/migrate/20190724163354_no_null_kdf_iterations.rb b/db/migrate/20190724163354_no_null_kdf_iterations.rb index 2b9bd96..8d12476 100644 --- a/db/migrate/20190724163354_no_null_kdf_iterations.rb +++ b/db/migrate/20190724163354_no_null_kdf_iterations.rb @@ -1,15 +1,17 @@ class NoNullKdfIterations < ActiveRecord::Migration[5.1] def change User.all.each do |u| + # any old users without a kdf_iterations value probably have the old + # value of 5000 if !u.kdf_iterations - u.kdf_iterations = Bitwarden::KDF::DEFAULT_ITERATIONS[User::DEFAULT_KDF_TYPE] - end - if !u.kdf_type - u.kdf_type = User::DEFAULT_KDF_TYPE + u.kdf_iterations = 5000 + u.kdf_type = Bitwarden::KDF::PBKDF2 end u.save! end + # but going forward, any new users should get whatever defaults are set in + # the future change_column :users, :kdf_iterations, :integer, :null => false, :default => Bitwarden::KDF::DEFAULT_ITERATIONS[User::DEFAULT_KDF_TYPE] end From fd84aa918f3e285f1309a503a9883ac4ec03c70d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 Aug 2019 18:46:14 +0000 Subject: [PATCH 12/33] Bump nokogiri from 1.10.3 to 1.10.4 Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.10.3 to 1.10.4. - [Release notes](https://github.com/sparklemotion/nokogiri/releases) - [Changelog](https://github.com/sparklemotion/nokogiri/blob/master/CHANGELOG.md) - [Commits](https://github.com/sparklemotion/nokogiri/compare/v1.10.3...v1.10.4) Signed-off-by: dependabot[bot] --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 05e15a0..e60d6b2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -70,7 +70,7 @@ GEM multi_json (1.13.1) mustermann (1.0.2) nio4r (2.4.0) - nokogiri (1.10.3) + nokogiri (1.10.4) mini_portile2 (~> 2.4.0) os (1.0.0) pbkdf2-ruby (0.2.1) From c7c9667044fc2225b074142b8772d1f096980450 Mon Sep 17 00:00:00 2001 From: joshua stein Date: Sat, 28 Sep 2019 21:04:46 -0500 Subject: [PATCH 13/33] Add a global route for OPTIONS requests, respond with CORS headers The new Safari extension does OPTIONS requests for each POST/PUT/DELETE and expects CORS headers to be in the response, so give it what it asks for Should fix #103 --- lib/app.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/app.rb b/lib/app.rb index daccc9e..cdd4828 100644 --- a/lib/app.rb +++ b/lib/app.rb @@ -55,11 +55,23 @@ class App < Sinatra::Base # we're always going to reply with json content_type :json + + # set CORS headers for safari extension + response.headers["Access-Control-Allow-Origin"] = "file://" + # just parrot back whatever safari asked for + response.headers["Access-Control-Allow-Methods"] = + request.env["HTTP_ACCESS_CONTROL_REQUEST_METHOD"] + response.headers["Access-Control-Allow-Headers"] = + request.env["HTTP_ACCESS_CONTROL_REQUEST_HEADERS"] end register Rubywarden::Routing::Api register Rubywarden::Routing::Icons register Rubywarden::Routing::Identity register Rubywarden::Routing::Attachments + + options /.*/ do + # empty response just to respond with CORS headers + end end end From 4540f3b1724a9dab69f20103695fc307e1e92db0 Mon Sep 17 00:00:00 2001 From: joshua stein Date: Sat, 28 Sep 2019 21:13:08 -0500 Subject: [PATCH 14/33] mitm: support OPTIONS requests --- tools/mitm.rb | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tools/mitm.rb b/tools/mitm.rb index c6aaae0..7ca2eba 100644 --- a/tools/mitm.rb +++ b/tools/mitm.rb @@ -76,7 +76,20 @@ def add_field(key, val) proxy_to upstream_url_for(request.path_info), :put end +options /(.*)/ do + proxy_to upstream_url_for(request.path_info), :options +end + def proxy_to(url, method) + if RAW_QUERIES + puts "#{request.env["REQUEST_METHOD"]} request to #{request.path_info}:" + request.env.each do |k,v| + if k.match(/^[A-Z_]+$/) + puts " #{k}: #{v}" + end + end + end + puts "proxying #{method.to_s.upcase} to #{url}" uri = URI.parse(url) @@ -121,6 +134,8 @@ def proxy_to(url, method) res = h.put(uri.path, post_data, send_headers) when :delete res = h.delete(uri.path, send_headers) + when :options + res = h.options(uri.path, send_headers) else raise "unknown method type #{method.inspect}" end From 133642ff07ebd29088abc4a386b9e475f542510d Mon Sep 17 00:00:00 2001 From: joshua stein Date: Sun, 29 Sep 2019 07:16:51 -0500 Subject: [PATCH 15/33] Only mirror CORS headers if the client sent them --- lib/app.rb | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/app.rb b/lib/app.rb index cdd4828..f7db2d2 100644 --- a/lib/app.rb +++ b/lib/app.rb @@ -59,10 +59,14 @@ class App < Sinatra::Base # set CORS headers for safari extension response.headers["Access-Control-Allow-Origin"] = "file://" # just parrot back whatever safari asked for - response.headers["Access-Control-Allow-Methods"] = - request.env["HTTP_ACCESS_CONTROL_REQUEST_METHOD"] - response.headers["Access-Control-Allow-Headers"] = - request.env["HTTP_ACCESS_CONTROL_REQUEST_HEADERS"] + if request.env["HTTP_ACCESS_CONTROL_REQUEST_METHOD"] + response.headers["Access-Control-Allow-Methods"] = + request.env["HTTP_ACCESS_CONTROL_REQUEST_METHOD"] + end + if request.env["HTTP_ACCESS_CONTROL_REQUEST_HEADERS"] + response.headers["Access-Control-Allow-Headers"] = + request.env["HTTP_ACCESS_CONTROL_REQUEST_HEADERS"] + end end register Rubywarden::Routing::Api From 0e8342d1660d1875bdc7fd4a5f000d87b53ba78e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Nov 2019 23:06:23 +0000 Subject: [PATCH 16/33] Bump loofah from 2.2.3 to 2.3.1 Bumps [loofah](https://github.com/flavorjones/loofah) from 2.2.3 to 2.3.1. - [Release notes](https://github.com/flavorjones/loofah/releases) - [Changelog](https://github.com/flavorjones/loofah/blob/master/CHANGELOG.md) - [Commits](https://github.com/flavorjones/loofah/compare/v2.2.3...v2.3.1) Signed-off-by: dependabot[bot] --- Gemfile.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index e60d6b2..cdcf0f3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -44,7 +44,7 @@ GEM chunky_png (1.3.10) coderay (1.1.2) concurrent-ruby (1.1.5) - crass (1.0.4) + crass (1.0.5) djinni (2.2.4) fagin (~> 1.2, >= 1.2.1) erubi (1.8.0) @@ -58,7 +58,7 @@ GEM json_config (0.1.4) jwt (2.1.0) kgio (2.11.2) - loofah (2.2.3) + loofah (2.3.1) crass (~> 1.0.2) nokogiri (>= 1.5.9) mail (2.7.1) @@ -70,7 +70,7 @@ GEM multi_json (1.13.1) mustermann (1.0.2) nio4r (2.4.0) - nokogiri (1.10.4) + nokogiri (1.10.5) mini_portile2 (~> 2.4.0) os (1.0.0) pbkdf2-ruby (0.2.1) From a9c5bbe10f2b6f98c94409947299706977738df2 Mon Sep 17 00:00:00 2001 From: joshua stein Date: Wed, 26 Feb 2020 10:32:09 -0600 Subject: [PATCH 17/33] Gemfile: only specify major/minor versions, update rack and nokogiri --- Gemfile | 10 ++--- Gemfile.lock | 123 +++++++++++++++++++++++++++------------------------ 2 files changed, 70 insertions(+), 63 deletions(-) diff --git a/Gemfile b/Gemfile index 5ed4fbc..9cf1d47 100644 --- a/Gemfile +++ b/Gemfile @@ -2,13 +2,13 @@ source "https://rubygems.org" ruby ">= 2.2.8" -gem "rack", ">= 2.0.6" +gem "rack", "~> 2.0.0" -gem "sinatra", "~> 2.0.3" -gem "sinatra-contrib", "~> 2.0.3" +gem "sinatra", "~> 2.0.0" +gem "sinatra-contrib", "~> 2.0.0" -gem "activerecord", "~> 5.1.7" -gem "sinatra-activerecord", "~> 2.0.13" +gem "activerecord", "~> 5.1.0" +gem "sinatra-activerecord", "~> 2.0.0" gem "sqlite3" gem "unicorn" diff --git a/Gemfile.lock b/Gemfile.lock index cdcf0f3..e1f97c4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -38,27 +38,29 @@ GEM i18n (>= 0.7, < 2) minitest (~> 5.1) tzinfo (~> 1.1) + addressable (2.7.0) + public_suffix (>= 2.0.2, < 5.0) arel (8.0.0) - backports (3.11.3) - builder (3.2.3) - chunky_png (1.3.10) + backports (3.16.1) + builder (3.2.4) + chunky_png (1.3.11) coderay (1.1.2) - concurrent-ruby (1.1.5) - crass (1.0.5) - djinni (2.2.4) - fagin (~> 1.2, >= 1.2.1) - erubi (1.8.0) - fagin (1.2.1) + concurrent-ruby (1.1.6) + crass (1.0.6) + djinni (2.2.5) + fagin (~> 1.2, >= 1.2.2) + erubi (1.9.0) + fagin (1.2.2) globalid (0.4.2) activesupport (>= 4.2.0) - hilighter (1.2.3) - i18n (1.6.0) + hilighter (1.5.9) + i18n (1.8.2) concurrent-ruby (~> 1.0) - json (2.1.0) - json_config (0.1.4) - jwt (2.1.0) - kgio (2.11.2) - loofah (2.3.1) + json (2.3.0) + jsoncfg (1.2.11) + jwt (2.2.1) + kgio (2.11.3) + loofah (2.4.0) crass (~> 1.0.2) nokogiri (>= 1.5.9) mail (2.7.1) @@ -66,19 +68,21 @@ GEM method_source (0.9.2) mini_mime (1.0.2) mini_portile2 (2.4.0) - minitest (5.11.3) - multi_json (1.13.1) - mustermann (1.0.2) - nio4r (2.4.0) - nokogiri (1.10.5) + minitest (5.14.0) + multi_json (1.14.1) + mustermann (1.1.1) + ruby2_keywords (~> 0.0.1) + nio4r (2.5.2) + nokogiri (1.10.8) mini_portile2 (~> 2.4.0) - os (1.0.0) + os (1.0.1) pbkdf2-ruby (0.2.1) - pry (0.11.3) + pry (0.12.2) coderay (~> 1.1.0) method_source (~> 0.9.0) - rack (2.0.7) - rack-protection (2.0.3) + public_suffix (4.0.3) + rack (2.0.9) + rack-protection (2.0.8.1) rack rack-test (1.1.0) rack (>= 1.0, < 3) @@ -97,60 +101,63 @@ GEM rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) - rails-html-sanitizer (1.0.4) - loofah (~> 2.2, >= 2.2.2) + rails-html-sanitizer (1.3.0) + loofah (~> 2.3) railties (5.1.7) actionpack (= 5.1.7) activesupport (= 5.1.7) method_source rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) - raindrops (0.19.0) - rake (12.3.3) - rotp (3.3.1) - rqrcode (0.10.1) + raindrops (0.19.1) + rake (13.0.1) + rotp (5.1.0) + addressable (~> 2.5) + rqrcode (1.1.2) chunky_png (~> 1.0) - rubeepass (3.3.0) - djinni (~> 2.2, >= 2.2.4) - hilighter (~> 1.1, >= 1.2.3) - json_config (~> 0.1, >= 0.1.4) - os (~> 1.0, >= 1.0.0) + rqrcode_core (~> 0.1) + rqrcode_core (0.1.1) + rubeepass (3.4.9) + djinni (~> 2.2, >= 2.2.5) + hilighter (~> 1.5, >= 1.5.1) + jsoncfg (~> 1.2, >= 1.2.11) + os (~> 1.0, >= 1.0.1) salsa20 (~> 0.1, >= 0.1.3) - scoobydoo (~> 0.1, >= 0.1.6) + scoobydoo (~> 1.0, >= 1.0.1) twofish (~> 1.0, >= 1.0.8) + ruby2_keywords (0.0.2) salsa20 (0.1.3) - scoobydoo (0.1.6) - sinatra (2.0.3) + scoobydoo (1.0.1) + sinatra (2.0.8.1) mustermann (~> 1.0) rack (~> 2.0) - rack-protection (= 2.0.3) + rack-protection (= 2.0.8.1) tilt (~> 2.0) - sinatra-activerecord (2.0.13) + sinatra-activerecord (2.0.14) activerecord (>= 3.2) sinatra (>= 1.0) - sinatra-contrib (2.0.3) - activesupport (>= 4.0.0) + sinatra-contrib (2.0.8.1) backports (>= 2.8.2) multi_json mustermann (~> 1.0) - rack-protection (= 2.0.3) - sinatra (= 2.0.3) - tilt (>= 1.3, < 3) - sprockets (3.7.2) + rack-protection (= 2.0.8.1) + sinatra (= 2.0.8.1) + tilt (~> 2.0) + sprockets (4.0.0) concurrent-ruby (~> 1.0) rack (> 1, < 3) sprockets-rails (3.2.1) actionpack (>= 4.0) activesupport (>= 4.0) sprockets (>= 3.0.0) - sqlite3 (1.3.13) - thor (0.20.3) + sqlite3 (1.4.2) + thor (1.0.1) thread_safe (0.3.6) - tilt (2.0.8) + tilt (2.0.10) twofish (1.0.8) - tzinfo (1.2.5) + tzinfo (1.2.6) thread_safe (~> 0.1) - unicorn (5.4.1) + unicorn (5.5.3) kgio (~> 2.6) raindrops (~> 0.7) websocket-driver (0.6.5) @@ -164,21 +171,21 @@ PLATFORMS ruby DEPENDENCIES - activerecord (~> 5.1.7) + activerecord (~> 5.1.0) json jwt minitest pbkdf2-ruby pry - rack (>= 2.0.6) + rack (~> 2.0.0) rack-test rake rotp rqrcode rubeepass (~> 3.3) - sinatra (~> 2.0.3) - sinatra-activerecord (~> 2.0.13) - sinatra-contrib (~> 2.0.3) + sinatra (~> 2.0.0) + sinatra-activerecord (~> 2.0.0) + sinatra-contrib (~> 2.0.0) sqlite3 unicorn yaml_db @@ -187,4 +194,4 @@ RUBY VERSION ruby 2.4.2p198 BUNDLED WITH - 1.17.1 + 1.17.2 From 549f66466ca753ee2f3c007b6e242d59dae05fdd Mon Sep 17 00:00:00 2001 From: joshua stein Date: Wed, 26 Feb 2020 10:34:40 -0600 Subject: [PATCH 18/33] Gemfile: bump ruby version to 2.4 --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 9cf1d47..818c7a3 100644 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,6 @@ source "https://rubygems.org" -ruby ">= 2.2.8" +ruby ">= 2.4.0" gem "rack", "~> 2.0.0" From 44f0fb8d7bf157c59ab78b4b1661f221e4cc4089 Mon Sep 17 00:00:00 2001 From: joshua stein Date: Wed, 27 May 2020 21:41:48 -0500 Subject: [PATCH 19/33] Remove ActiveRecord migration tools and info It's been almost 2 years since switching to AR, and the migration script requires yaml_db which brings in all of Rails. --- AR-MIGRATE.md | 59 ---------------------------- Gemfile | 4 -- Gemfile.lock | 79 ------------------------------------- README.md | 5 --- tools/migrate_to_ar.rb | 88 ------------------------------------------ 5 files changed, 235 deletions(-) delete mode 100644 AR-MIGRATE.md delete mode 100644 tools/migrate_to_ar.rb diff --git a/AR-MIGRATE.md b/AR-MIGRATE.md deleted file mode 100644 index 2ed62ad..0000000 --- a/AR-MIGRATE.md +++ /dev/null @@ -1,59 +0,0 @@ -## Rubywarden - -### Migrating From `bitwarden-ruby` to Rubywarden and ActiveRecord - -If you've used this application before it switched to using ActiveRecord -(when it was called `bitwarden-ruby`), you need to do the following steps to -migrate the data and generate the new table structures. - -Even though the migration script will import to a new database file at a -different path, it is probably best to create a backup yourself. -You can also copy the `db/production.sqlite3` to your local machine and do the -migration there. -After a successful migration you'd have to copy the updated database file back -to the production machine. - -First make sure you have the latest code: - - git pull - -Then checkout to a specific revision where the migration was made: - - git checkout 40044728d - -Run `bundle` to add some required libraries for the migration: - - bundle --with migrate - -Now you are ready to do the migration: - - bundle exec ruby tools/migrate_to_ar.rb -e production - -The `-e` switch allows you to select the correct database environment from -`db/config.yml`. - -The migration script will: - - - dump the contents of the old database (most likely at - `db/production.sqlite`) to a temporary YAML file - - create the new database at `db/production/production.sqlite3` using - ActiveRecord migrations - - import the contents from the dump file - - remove the dump file - -Now your data is completely migrated into a new database at the new recommended -path, and the library will now use ActiveRecord to handle anything database -related. - -It is recommended to follow the -[initial installation instructions](https://github.com/jcs/rubywarden#manual-setup) -to create a new, unprivileged user to own the new `db/production/` database -and run the server. - -Lastly, update to the current code: - - git checkout master - -And then follow the -[update instructions](https://github.com/jcs/rubywarden#updating) -to bring your database up to date with the latest migrations. diff --git a/Gemfile b/Gemfile index 818c7a3..477dda4 100644 --- a/Gemfile +++ b/Gemfile @@ -30,8 +30,4 @@ group :keepass, :optional => true do gem 'rubeepass', '~> 3.3' end -group :migrate, optional: true do - gem 'yaml_db' -end - gem 'pry' diff --git a/Gemfile.lock b/Gemfile.lock index e1f97c4..d62775a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,32 +1,6 @@ GEM remote: https://rubygems.org/ specs: - actioncable (5.1.7) - actionpack (= 5.1.7) - nio4r (~> 2.0) - websocket-driver (~> 0.6.1) - actionmailer (5.1.7) - actionpack (= 5.1.7) - actionview (= 5.1.7) - activejob (= 5.1.7) - mail (~> 2.5, >= 2.5.4) - rails-dom-testing (~> 2.0) - actionpack (5.1.7) - actionview (= 5.1.7) - activesupport (= 5.1.7) - rack (~> 2.0) - rack-test (>= 0.6.3) - rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (5.1.7) - activesupport (= 5.1.7) - builder (~> 3.1) - erubi (~> 1.4) - rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.0, >= 1.0.3) - activejob (5.1.7) - activesupport (= 5.1.7) - globalid (>= 0.3.6) activemodel (5.1.7) activesupport (= 5.1.7) activerecord (5.1.7) @@ -42,17 +16,12 @@ GEM public_suffix (>= 2.0.2, < 5.0) arel (8.0.0) backports (3.16.1) - builder (3.2.4) chunky_png (1.3.11) coderay (1.1.2) concurrent-ruby (1.1.6) - crass (1.0.6) djinni (2.2.5) fagin (~> 1.2, >= 1.2.2) - erubi (1.9.0) fagin (1.2.2) - globalid (0.4.2) - activesupport (>= 4.2.0) hilighter (1.5.9) i18n (1.8.2) concurrent-ruby (~> 1.0) @@ -60,21 +29,11 @@ GEM jsoncfg (1.2.11) jwt (2.2.1) kgio (2.11.3) - loofah (2.4.0) - crass (~> 1.0.2) - nokogiri (>= 1.5.9) - mail (2.7.1) - mini_mime (>= 0.1.1) method_source (0.9.2) - mini_mime (1.0.2) - mini_portile2 (2.4.0) minitest (5.14.0) multi_json (1.14.1) mustermann (1.1.1) ruby2_keywords (~> 0.0.1) - nio4r (2.5.2) - nokogiri (1.10.8) - mini_portile2 (~> 2.4.0) os (1.0.1) pbkdf2-ruby (0.2.1) pry (0.12.2) @@ -86,29 +45,6 @@ GEM rack rack-test (1.1.0) rack (>= 1.0, < 3) - rails (5.1.7) - actioncable (= 5.1.7) - actionmailer (= 5.1.7) - actionpack (= 5.1.7) - actionview (= 5.1.7) - activejob (= 5.1.7) - activemodel (= 5.1.7) - activerecord (= 5.1.7) - activesupport (= 5.1.7) - bundler (>= 1.3.0) - railties (= 5.1.7) - sprockets-rails (>= 2.0.0) - rails-dom-testing (2.0.3) - activesupport (>= 4.2.0) - nokogiri (>= 1.6) - rails-html-sanitizer (1.3.0) - loofah (~> 2.3) - railties (5.1.7) - actionpack (= 5.1.7) - activesupport (= 5.1.7) - method_source - rake (>= 0.8.7) - thor (>= 0.18.1, < 2.0) raindrops (0.19.1) rake (13.0.1) rotp (5.1.0) @@ -143,15 +79,7 @@ GEM rack-protection (= 2.0.8.1) sinatra (= 2.0.8.1) tilt (~> 2.0) - sprockets (4.0.0) - concurrent-ruby (~> 1.0) - rack (> 1, < 3) - sprockets-rails (3.2.1) - actionpack (>= 4.0) - activesupport (>= 4.0) - sprockets (>= 3.0.0) sqlite3 (1.4.2) - thor (1.0.1) thread_safe (0.3.6) tilt (2.0.10) twofish (1.0.8) @@ -160,12 +88,6 @@ GEM unicorn (5.5.3) kgio (~> 2.6) raindrops (~> 0.7) - websocket-driver (0.6.5) - websocket-extensions (>= 0.1.0) - websocket-extensions (0.1.4) - yaml_db (0.7.0) - rails (>= 3.0) - rake (>= 0.8.7) PLATFORMS ruby @@ -188,7 +110,6 @@ DEPENDENCIES sinatra-contrib (~> 2.0.0) sqlite3 unicorn - yaml_db RUBY VERSION ruby 2.4.2p198 diff --git a/README.md b/README.md index 7aa6939..4b0b75f 100644 --- a/README.md +++ b/README.md @@ -99,11 +99,6 @@ Then you can configure the Bitwarden clients with a single server URL of ### Updating -If you've previously used Rubywarden before July 30, 2018 when it was called -`bitwarden-ruby`, when it did not use ActiveRecord, you should instead -[migrate](AR-MIGRATE.md) -your existing database. - To update your instance of Rubywarden, fetch the latest code: cd /path/to/your/rubywarden diff --git a/tools/migrate_to_ar.rb b/tools/migrate_to_ar.rb deleted file mode 100644 index a1d1746..0000000 --- a/tools/migrate_to_ar.rb +++ /dev/null @@ -1,88 +0,0 @@ -# see https://github.com/jcs/rubywarden/blob/master/AR-MIGRATE.md - -require "fileutils" -require "getoptlong" -require "tempfile" -require "yaml_db" - -def usage - puts "usage: #{$PROGRAM_NAME} -e development" - exit 1 -end - -environment = nil -begin - GetoptLong.new( - ['--environment', '-e', GetoptLong::REQUIRED_ARGUMENT] - ).each do |opt, arg| - case opt - when '--environment' - environment = arg - end - end -rescue GetoptLong::InvalidOption - usage -end - -usage unless environment - -require File.realpath(File.dirname(__FILE__) + "/../lib/rubywarden.rb") - -ActiveRecord::Base.remove_connection - -dbconfig = YAML.load(File.read(File.realpath(__dir__ + "/../db/config.yml"))) - -# if a file exists at the new path, some kind of migration has already been -# done so bail out -newdb = dbconfig[environment]["database"] -if File.exists?(newdb) - raise "a file already exists at #{newdb}, has a migration already taken place?" -end - -olddb = File.realpath(__dir__ + "/../db/production.sqlite3") -if !olddb || !File.exists?(olddb) - raise "no file at #{olddb} to migrate" -end - -# point a temporary config at the old db path so we can dump it -tmpconfig = dbconfig[environment].dup -tmpconfig["database"] = olddb -ActiveRecord::Base.establish_connection tmpconfig - -# select only tables for defined models -class YamlDb::SerializationHelper::Dump - def self.tables - ObjectSpace.each_object(Class).select{|k| k < DBModel}.map{|k| k.table_name } - end -end - -dump_file = Tempfile.new("rubywarden-migrate") - -puts "dumping old database to #{dump_file.path}" -YamlDb::SerializationHelper::Base.new(YamlDb::Helper).dump(dump_file.path) -ActiveRecord::Base.remove_connection - -puts "creating new database at #{dbconfig[environment]["database"]}" -system("rake", "db:migrate", "RUBYWARDEN_ENV=#{environment}") - -puts "importing old database dump" -ActiveRecord::Base.establish_connection dbconfig[environment] -YamlDb::SerializationHelper::Base.new(YamlDb::Helper).load(dump_file.path) - -puts "deleting dump file" -dump_file.unlink - -# reset created_at / updated_at from seconds since epoch to actual datetime for ar magic -DBModel.record_timestamps = false -ObjectSpace.each_object(Class).select {|k| k < DBModel}.each do |k| - k.all.each do |i| - i.update created_at: Time.at(i.created_at), updated_at: Time.at(i.updated_at) - end -end -DBModel.record_timestamps = true - -newdb = File.realpath(__dir__ + "/../" + dbconfig[environment]["database"]) -puts "you may wish to delete the old database at #{newdb}" - -puts "you may also wish to create a new, unprivileged user to run the" -puts "rubywarden server and own the db/production/ directory" From 881815fd77c6fe4313df7b5fe179efa50593cfe7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Jun 2020 09:56:34 -0700 Subject: [PATCH 20/33] Bump rack from 2.0.9 to 2.1.4 (#116) Bumps [rack](https://github.com/rack/rack) from 2.0.9 to 2.1.4. - [Release notes](https://github.com/rack/rack/releases) - [Changelog](https://github.com/rack/rack/blob/master/CHANGELOG.md) - [Commits](https://github.com/rack/rack/compare/2.0.9...2.1.4) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile | 2 +- Gemfile.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index 477dda4..567e491 100644 --- a/Gemfile +++ b/Gemfile @@ -2,7 +2,7 @@ source "https://rubygems.org" ruby ">= 2.4.0" -gem "rack", "~> 2.0.0" +gem "rack", "~> 2.1.4" gem "sinatra", "~> 2.0.0" gem "sinatra-contrib", "~> 2.0.0" diff --git a/Gemfile.lock b/Gemfile.lock index d62775a..a526115 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -40,7 +40,7 @@ GEM coderay (~> 1.1.0) method_source (~> 0.9.0) public_suffix (4.0.3) - rack (2.0.9) + rack (2.1.4) rack-protection (2.0.8.1) rack rack-test (1.1.0) @@ -99,7 +99,7 @@ DEPENDENCIES minitest pbkdf2-ruby pry - rack (~> 2.0.0) + rack (~> 2.1.4) rack-test rake rotp From 8ded1067c6701da7e43ce5fd2c7ef8cc4e9c182c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Haluk=20=C3=9CNAL?= Date: Tue, 30 Jun 2020 00:10:26 +0300 Subject: [PATCH 21/33] Add Chrome import tool (#109) --- spec/fixtures/chrome_export.csv | 5 ++ tools/chrome_import.rb | 135 ++++++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+) create mode 100644 spec/fixtures/chrome_export.csv create mode 100644 tools/chrome_import.rb diff --git a/spec/fixtures/chrome_export.csv b/spec/fixtures/chrome_export.csv new file mode 100644 index 0000000..1e54565 --- /dev/null +++ b/spec/fixtures/chrome_export.csv @@ -0,0 +1,5 @@ +name,url,username,password +cloud.digitalocean.com,https://cloud.digitalocean.com/login,root,mySuper.Password1 +m.facebook.com,https://m.facebook.com/,admin,mySuper?Password2 +github.com,https://github.com/login,supervisor,mySuper%Password3 +gitlab.com,https://gitlab.com/users/sign_in,moderator,mySuper-Password4 diff --git a/tools/chrome_import.rb b/tools/chrome_import.rb new file mode 100644 index 0000000..61b1d31 --- /dev/null +++ b/tools/chrome_import.rb @@ -0,0 +1,135 @@ +#!/usr/bin/env ruby +# +# Copyright (c) 2017 joshua stein +# Chrome importer by Haluk Unal +# +# 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. +# + +# +# Read a given Chrome CSV file, ask for the given user's master password, +# then lookup the given user in the bitwarden-ruby SQLite database and +# fetch its key. Import each entry into the bitwarden-ruby database. +# +# No check is done to eliminate duplicates, so this is best used on a fresh +# bitwarden-ruby installation after creating a new account. +# + +require File.realpath(File.dirname(__FILE__) + '/../lib/rubywarden.rb') + +require 'csv' +require 'getoptlong' + +def usage + puts "usage: #{$PROGRAM_NAME} -f data.csv -u user@example.com" + exit 1 +end + +def encrypt(str) + @u.encrypt_data_with_master_password_key(str, @master_key).to_s +end + +username = nil +file = nil +@folders = {} + +begin + GetoptLong.new( + ['--file', '-f', GetoptLong::REQUIRED_ARGUMENT], + ['--user', '-u', GetoptLong::REQUIRED_ARGUMENT] + ).each do |opt, arg| + case opt + when '--file' + file = arg + when '--user' + username = arg + end + end +rescue GetoptLong::InvalidOption + usage +end + +usage unless file && username + +@u = User.find_by_email(username) +raise "can't find existing User record for #{username.inspect}" unless @u + +print "master password for #{@u.email}: " +system('stty -echo') if STDIN.tty? +password = STDIN.gets.chomp +system('stty echo') if STDIN.tty? +puts + +unless @u.has_password_hash?(Bitwarden.hashPassword(password, @u.email, +Bitwarden::KDF::TYPES[@u.kdf_type], @u.kdf_iterations)) + raise "master password does not match stored hash" +end + +@master_key = Bitwarden.makeKey(password, @u.email, + Bitwarden::KDF::TYPES[@u.kdf_type], @u.kdf_iterations) + +@u.folders.each do |folder| + folder_name = @u.decrypt_data_with_master_password_key(folder.name, @master_key) + @folders[folder_name] = folder.uuid +end + +to_save = {} +skipped = 0 + +CSV.foreach(file, headers: true) do |row| + next if row['name'].blank? + + puts "converting #{row['name']}..." + + c = Cipher.new + c.user_uuid = @u.uuid + c.type = Cipher::TYPE_LOGIN + + cdata = { 'Name' => encrypt(row['name']) } + cdata['Uri'] = encrypt(row['url']) if row['url'].present? + cdata['Username'] = encrypt(row['username']) if row['username'].present? + cdata['Password'] = encrypt(row['password']) if row['password'].present? + + c.data = cdata.to_json + + to_save[c.type] ||= [] + to_save[c.type].push c +end + +puts + +to_save.each do |k, v| + puts "#{format('% 4d', v.count)} #{Cipher.type_s(k)}" << + (v.count == 1 ? '' : 's') +end + +puts "#{format('% 4d', skipped)} skipped" if skipped > 0 + +print 'ready to import? [Y/n] ' +exit 1 if STDIN.gets =~ /n/i + +imp = 0 +Cipher.transaction do + to_save.each_value do |v| + v.each do |c| + # TODO: convert data to each field natively and call save! on our own + c.migrate_data! + + imp += 1 + end + end +end + +puts "successfully imported #{imp} item#{imp == 1 ? '' : 's'}" + +# EOF From f5818ca283a9c3a322cddadbbf1bc092e5059ab9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Haluk=20=C3=9CNAL?= Date: Tue, 30 Jun 2020 00:11:07 +0300 Subject: [PATCH 22/33] Add new cipher delete route (#117) --- lib/routes/api.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/routes/api.rb b/lib/routes/api.rb index b02f89e..c54e3d1 100644 --- a/lib/routes/api.rb +++ b/lib/routes/api.rb @@ -208,6 +208,11 @@ def self.registered(app) delete_cipher app: app, uuid: params[:uuid] end + # delete a cipher (new client) + put "/ciphers/:uuid/delete" do + delete_cipher app: app, uuid: params[:uuid] + end + # # folders # From ef76f71b187c9d423964bc959859a1a0ff3b054b Mon Sep 17 00:00:00 2001 From: joshua stein Date: Fri, 28 Aug 2020 12:42:54 -0500 Subject: [PATCH 23/33] README: i'm no longer working on this --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4b0b75f..9cdefd2 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,12 @@ -**This project is not associated with the +**This project is no longer being maintained. Please see +[this issue](https://github.com/jcs/rubywarden/issues/122) +for further information.** + +This project is not associated with the [Bitwarden](https://bitwarden.com/) project nor 8bit Solutions LLC. Do not contact Bitwarden for support with using this backend server -(or at the very least, make it abundantly clear that you are using a 3rd party backend server).** +(or at the very least, make it abundantly clear that you are using a 3rd party backend server). ## Rubywarden From 4230e07ac69f27b6a641ed325bcec606c517319e Mon Sep 17 00:00:00 2001 From: joshua stein Date: Mon, 21 Dec 2020 17:19:57 -0600 Subject: [PATCH 24/33] Identity: Return user Kdf and KdfIterations in login response It used to be enough just to return these in /accounts/prelogin but now, without them, the browser extension stores a null KDF iteration count upon login and then on subsequent unlock attempts, it uses the default KDF iteration count of 5000 which is probably not right (the new default is 100,000). This causes it to generate a failed key, making it impossible to unlock a logged-in vault without logging out and logging back in. See https://github.com/bitwarden/browser/issues/1456 --- lib/routes/identity.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/routes/identity.rb b/lib/routes/identity.rb index 9b8bac5..0fd4ac7 100644 --- a/lib/routes/identity.rb +++ b/lib/routes/identity.rb @@ -110,6 +110,8 @@ def self.registered(app) :token_type => "Bearer", :refresh_token => d.refresh_token, :Key => d.user.key, + :Kdf => d.user.kdf_type, + :KdfIterations => d.user.kdf_iterations, # TODO: when to include :privateKey and :TwoFactorToken? }.to_json end From 691159bc652fc21b4afabdc44af315675dbc3b40 Mon Sep 17 00:00:00 2001 From: joshua stein Date: Tue, 22 Dec 2020 12:44:37 -0600 Subject: [PATCH 25/33] Folder: Explicitly nullify associated cipher folder_id when deleting Fixes #111 --- lib/folder.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/folder.rb b/lib/folder.rb index 09a83fc..f0079bc 100644 --- a/lib/folder.rb +++ b/lib/folder.rb @@ -21,7 +21,10 @@ class Folder < DBModel before_create :generate_uuid_primary_key belongs_to :user, foreign_key: :user_uuid, inverse_of: :folders - has_many :ciphers, foreign_key: :folder_uuid, inverse_of: :folder + has_many :ciphers, + foreign_key: :folder_uuid, + inverse_of: :folder, + dependent: :nullify def to_hash { From 31122bdce330e452f4e99e986e053fd5c04b208e Mon Sep 17 00:00:00 2001 From: joshua stein Date: Tue, 22 Dec 2020 12:52:16 -0600 Subject: [PATCH 26/33] User: set dependent->destroy on all things for better user deletion --- lib/user.rb | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/user.rb b/lib/user.rb index ce1e6ef..f469390 100644 --- a/lib/user.rb +++ b/lib/user.rb @@ -25,9 +25,18 @@ class User < DBModel before_create :generate_uuid_primary_key before_validation :generate_security_stamp - has_many :ciphers, foreign_key: :user_uuid, inverse_of: :user - has_many :folders, foreign_key: :user_uuid, inverse_of: :user - has_many :devices, foreign_key: :user_uuid, inverse_of: :user + has_many :ciphers, + foreign_key: :user_uuid, + inverse_of: :user, + dependent: :destroy + has_many :folders, + foreign_key: :user_uuid, + inverse_of: :user, + dependent: :destroy + has_many :devices, + foreign_key: :user_uuid, + inverse_of: :user, + dependent: :destroy def decrypt_data_with_master_password_key(data, mk) # self.key is random data encrypted with the key of (password,email), so From 29e9d3a87f33e7fc669aebb81ed551ddebe1ffe8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Mar 2021 13:09:22 -0600 Subject: [PATCH 27/33] Bump activerecord from 5.1.7 to 5.2.4.5 (#123) Bumps [activerecord](https://github.com/rails/rails) from 5.1.7 to 5.2.4.5. - [Release notes](https://github.com/rails/rails/releases) - [Changelog](https://github.com/rails/rails/blob/v6.1.3/activerecord/CHANGELOG.md) - [Commits](https://github.com/rails/rails/compare/v5.1.7...v5.2.4.5) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile | 2 +- Gemfile.lock | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Gemfile b/Gemfile index 567e491..77d86df 100644 --- a/Gemfile +++ b/Gemfile @@ -7,7 +7,7 @@ gem "rack", "~> 2.1.4" gem "sinatra", "~> 2.0.0" gem "sinatra-contrib", "~> 2.0.0" -gem "activerecord", "~> 5.1.0" +gem "activerecord", "~> 5.2.4" gem "sinatra-activerecord", "~> 2.0.0" gem "sqlite3" diff --git a/Gemfile.lock b/Gemfile.lock index a526115..9d62bb1 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,29 +1,29 @@ GEM remote: https://rubygems.org/ specs: - activemodel (5.1.7) - activesupport (= 5.1.7) - activerecord (5.1.7) - activemodel (= 5.1.7) - activesupport (= 5.1.7) - arel (~> 8.0) - activesupport (5.1.7) + activemodel (5.2.4.5) + activesupport (= 5.2.4.5) + activerecord (5.2.4.5) + activemodel (= 5.2.4.5) + activesupport (= 5.2.4.5) + arel (>= 9.0) + activesupport (5.2.4.5) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) tzinfo (~> 1.1) addressable (2.7.0) public_suffix (>= 2.0.2, < 5.0) - arel (8.0.0) + arel (9.0.0) backports (3.16.1) chunky_png (1.3.11) coderay (1.1.2) - concurrent-ruby (1.1.6) + concurrent-ruby (1.1.8) djinni (2.2.5) fagin (~> 1.2, >= 1.2.2) fagin (1.2.2) hilighter (1.5.9) - i18n (1.8.2) + i18n (1.8.9) concurrent-ruby (~> 1.0) json (2.3.0) jsoncfg (1.2.11) @@ -83,7 +83,7 @@ GEM thread_safe (0.3.6) tilt (2.0.10) twofish (1.0.8) - tzinfo (1.2.6) + tzinfo (1.2.9) thread_safe (~> 0.1) unicorn (5.5.3) kgio (~> 2.6) @@ -93,7 +93,7 @@ PLATFORMS ruby DEPENDENCIES - activerecord (~> 5.1.0) + activerecord (~> 5.2.4) json jwt minitest From 2a7bf00c222eeb29671bd8242f7584c01adfcd99 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Jul 2021 13:33:54 -0500 Subject: [PATCH 28/33] Bump addressable from 2.7.0 to 2.8.0 (#124) Bumps [addressable](https://github.com/sporkmonger/addressable) from 2.7.0 to 2.8.0. - [Release notes](https://github.com/sporkmonger/addressable/releases) - [Changelog](https://github.com/sporkmonger/addressable/blob/main/CHANGELOG.md) - [Commits](https://github.com/sporkmonger/addressable/compare/addressable-2.7.0...addressable-2.8.0) --- updated-dependencies: - dependency-name: addressable dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 9d62bb1..42b97f1 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -12,7 +12,7 @@ GEM i18n (>= 0.7, < 2) minitest (~> 5.1) tzinfo (~> 1.1) - addressable (2.7.0) + addressable (2.8.0) public_suffix (>= 2.0.2, < 5.0) arel (9.0.0) backports (3.16.1) @@ -39,7 +39,7 @@ GEM pry (0.12.2) coderay (~> 1.1.0) method_source (~> 0.9.0) - public_suffix (4.0.3) + public_suffix (4.0.6) rack (2.1.4) rack-protection (2.0.8.1) rack From b0d8622c731e2e8d9e5ed58a4d510fbde14f325b Mon Sep 17 00:00:00 2001 From: Chris Lee Date: Tue, 17 May 2022 09:20:30 -0600 Subject: [PATCH 29/33] Correct device type ID for Firefox (#125) --- API.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/API.md b/API.md index 2c2355b..0bd101d 100644 --- a/API.md +++ b/API.md @@ -309,7 +309,7 @@ different). The `deviceIdentifier` is a random UUID generated by the device and remains constant across logins. -`deviceType` is `2` +`deviceType` is `3` [for Firefox](https://github.com/bitwarden/core/blob/c9a2e67d0965fd046a0b3099e9511c26f0201acd/src/Core/Enums/DeviceType.cs). POST $identityURL/connect/token From a41fcb8083df6e370a917a9c41fcfa92f6846b38 Mon Sep 17 00:00:00 2001 From: joshua stein Date: Tue, 17 May 2022 10:24:08 -0500 Subject: [PATCH 30/33] Gemfile: update dependencies, notably sinatra --- Gemfile | 10 +++--- Gemfile.lock | 94 ++++++++++++++++++++++++---------------------------- 2 files changed, 49 insertions(+), 55 deletions(-) diff --git a/Gemfile b/Gemfile index 77d86df..c6a07a5 100644 --- a/Gemfile +++ b/Gemfile @@ -2,13 +2,13 @@ source "https://rubygems.org" ruby ">= 2.4.0" -gem "rack", "~> 2.1.4" +gem "rack", "~> 2.2" -gem "sinatra", "~> 2.0.0" -gem "sinatra-contrib", "~> 2.0.0" +gem "sinatra", "~> 2.2" +gem "sinatra-contrib", "~> 2.2" -gem "activerecord", "~> 5.2.4" -gem "sinatra-activerecord", "~> 2.0.0" +gem "activerecord", "~> 5.2" +gem "sinatra-activerecord", "~> 2.0" gem "sqlite3" gem "unicorn" diff --git a/Gemfile.lock b/Gemfile.lock index 42b97f1..4c16023 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,59 +1,54 @@ GEM remote: https://rubygems.org/ specs: - activemodel (5.2.4.5) - activesupport (= 5.2.4.5) - activerecord (5.2.4.5) - activemodel (= 5.2.4.5) - activesupport (= 5.2.4.5) + activemodel (5.2.8) + activesupport (= 5.2.8) + activerecord (5.2.8) + activemodel (= 5.2.8) + activesupport (= 5.2.8) arel (>= 9.0) - activesupport (5.2.4.5) + activesupport (5.2.8) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) tzinfo (~> 1.1) - addressable (2.8.0) - public_suffix (>= 2.0.2, < 5.0) arel (9.0.0) - backports (3.16.1) - chunky_png (1.3.11) - coderay (1.1.2) - concurrent-ruby (1.1.8) + chunky_png (1.4.0) + coderay (1.1.3) + concurrent-ruby (1.1.10) djinni (2.2.5) fagin (~> 1.2, >= 1.2.2) fagin (1.2.2) hilighter (1.5.9) - i18n (1.8.9) + i18n (1.10.0) concurrent-ruby (~> 1.0) - json (2.3.0) + json (2.6.2) jsoncfg (1.2.11) - jwt (2.2.1) - kgio (2.11.3) - method_source (0.9.2) - minitest (5.14.0) - multi_json (1.14.1) + jwt (2.3.0) + kgio (2.11.4) + method_source (1.0.0) + minitest (5.15.0) + multi_json (1.15.0) mustermann (1.1.1) ruby2_keywords (~> 0.0.1) - os (1.0.1) + os (1.1.4) pbkdf2-ruby (0.2.1) - pry (0.12.2) - coderay (~> 1.1.0) - method_source (~> 0.9.0) - public_suffix (4.0.6) - rack (2.1.4) - rack-protection (2.0.8.1) + pry (0.14.1) + coderay (~> 1.1) + method_source (~> 1.0) + rack (2.2.3) + rack-protection (2.2.0) rack rack-test (1.1.0) rack (>= 1.0, < 3) - raindrops (0.19.1) - rake (13.0.1) - rotp (5.1.0) - addressable (~> 2.5) - rqrcode (1.1.2) + raindrops (0.20.0) + rake (13.0.6) + rotp (6.2.0) + rqrcode (2.1.1) chunky_png (~> 1.0) - rqrcode_core (~> 0.1) - rqrcode_core (0.1.1) - rubeepass (3.4.9) + rqrcode_core (~> 1.0) + rqrcode_core (1.2.0) + rubeepass (3.5.0) djinni (~> 2.2, >= 2.2.5) hilighter (~> 1.5, >= 1.5.1) jsoncfg (~> 1.2, >= 1.2.11) @@ -61,23 +56,22 @@ GEM salsa20 (~> 0.1, >= 0.1.3) scoobydoo (~> 1.0, >= 1.0.1) twofish (~> 1.0, >= 1.0.8) - ruby2_keywords (0.0.2) + ruby2_keywords (0.0.5) salsa20 (0.1.3) scoobydoo (1.0.1) - sinatra (2.0.8.1) + sinatra (2.2.0) mustermann (~> 1.0) - rack (~> 2.0) - rack-protection (= 2.0.8.1) + rack (~> 2.2) + rack-protection (= 2.2.0) tilt (~> 2.0) - sinatra-activerecord (2.0.14) - activerecord (>= 3.2) + sinatra-activerecord (2.0.25) + activerecord (>= 4.1) sinatra (>= 1.0) - sinatra-contrib (2.0.8.1) - backports (>= 2.8.2) + sinatra-contrib (2.2.0) multi_json mustermann (~> 1.0) - rack-protection (= 2.0.8.1) - sinatra (= 2.0.8.1) + rack-protection (= 2.2.0) + sinatra (= 2.2.0) tilt (~> 2.0) sqlite3 (1.4.2) thread_safe (0.3.6) @@ -85,7 +79,7 @@ GEM twofish (1.0.8) tzinfo (1.2.9) thread_safe (~> 0.1) - unicorn (5.5.3) + unicorn (6.1.0) kgio (~> 2.6) raindrops (~> 0.7) @@ -93,21 +87,21 @@ PLATFORMS ruby DEPENDENCIES - activerecord (~> 5.2.4) + activerecord (~> 5.2) json jwt minitest pbkdf2-ruby pry - rack (~> 2.1.4) + rack (~> 2.2) rack-test rake rotp rqrcode rubeepass (~> 3.3) - sinatra (~> 2.0.0) - sinatra-activerecord (~> 2.0.0) - sinatra-contrib (~> 2.0.0) + sinatra (~> 2.2) + sinatra-activerecord (~> 2.0) + sinatra-contrib (~> 2.2) sqlite3 unicorn From b65a7ba717b9915ec18b2d387ec59641e738f86f Mon Sep 17 00:00:00 2001 From: joshua stein Date: Fri, 27 May 2022 12:48:12 -0500 Subject: [PATCH 31/33] Gemfile: update rack --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 4c16023..0ae1614 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -36,7 +36,7 @@ GEM pry (0.14.1) coderay (~> 1.1) method_source (~> 1.0) - rack (2.2.3) + rack (2.2.3.1) rack-protection (2.2.0) rack rack-test (1.1.0) From 5e2d8574945b82149af50313bc46f02a9da436e0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 Jul 2022 16:43:07 -0500 Subject: [PATCH 32/33] Bump activerecord from 5.2.8 to 5.2.8.1 (#127) --- Gemfile.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 0ae1614..bc5a543 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,13 +1,13 @@ GEM remote: https://rubygems.org/ specs: - activemodel (5.2.8) - activesupport (= 5.2.8) - activerecord (5.2.8) - activemodel (= 5.2.8) - activesupport (= 5.2.8) + activemodel (5.2.8.1) + activesupport (= 5.2.8.1) + activerecord (5.2.8.1) + activemodel (= 5.2.8.1) + activesupport (= 5.2.8.1) arel (>= 9.0) - activesupport (5.2.8) + activesupport (5.2.8.1) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) @@ -20,7 +20,7 @@ GEM fagin (~> 1.2, >= 1.2.2) fagin (1.2.2) hilighter (1.5.9) - i18n (1.10.0) + i18n (1.11.0) concurrent-ruby (~> 1.0) json (2.6.2) jsoncfg (1.2.11) From 3d8c28219b0c70a1a757142f25b35b4a248745c9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 22 Jul 2022 06:36:22 -0700 Subject: [PATCH 33/33] Bump tzinfo from 1.2.9 to 1.2.10 (#128) --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index bc5a543..7ab9e47 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -77,7 +77,7 @@ GEM thread_safe (0.3.6) tilt (2.0.10) twofish (1.0.8) - tzinfo (1.2.9) + tzinfo (1.2.10) thread_safe (~> 0.1) unicorn (6.1.0) kgio (~> 2.6)