Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/vendor
diff options
context:
space:
mode:
Diffstat (limited to 'vendor')
-rw-r--r--vendor/gems/attr_encrypted/.gitignore5
-rw-r--r--vendor/gems/attr_encrypted/.gitlab-ci.yml (renamed from vendor/gems/omniauth-google-oauth2/.gitlab-ci.yml)28
-rw-r--r--vendor/gems/attr_encrypted/CHANGELOG.md98
-rw-r--r--vendor/gems/attr_encrypted/Gemfile (renamed from vendor/gems/omniauth-google-oauth2/Gemfile)2
-rw-r--r--vendor/gems/attr_encrypted/Gemfile.lock155
-rw-r--r--vendor/gems/attr_encrypted/MIT-LICENSE20
-rw-r--r--vendor/gems/attr_encrypted/README.md466
-rw-r--r--vendor/gems/attr_encrypted/Rakefile25
-rw-r--r--vendor/gems/attr_encrypted/attr_encrypted.gemspec52
-rw-r--r--vendor/gems/attr_encrypted/lib/attr_encrypted.rb473
-rw-r--r--vendor/gems/attr_encrypted/lib/attr_encrypted/adapters/active_record.rb146
-rw-r--r--vendor/gems/attr_encrypted/lib/attr_encrypted/adapters/data_mapper.rb24
-rw-r--r--vendor/gems/attr_encrypted/lib/attr_encrypted/adapters/sequel.rb16
-rw-r--r--vendor/gems/attr_encrypted/lib/attr_encrypted/version.rb19
-rw-r--r--vendor/gems/attr_encrypted/test/active_record_test.rb368
-rw-r--r--vendor/gems/attr_encrypted/test/attr_encrypted_test.rb490
-rw-r--r--vendor/gems/attr_encrypted/test/compatibility_test.rb109
-rw-r--r--vendor/gems/attr_encrypted/test/data_mapper_test.rb59
-rw-r--r--vendor/gems/attr_encrypted/test/legacy_active_record_test.rb120
-rw-r--r--vendor/gems/attr_encrypted/test/legacy_attr_encrypted_test.rb300
-rw-r--r--vendor/gems/attr_encrypted/test/legacy_compatibility_test.rb95
-rw-r--r--vendor/gems/attr_encrypted/test/legacy_data_mapper_test.rb57
-rw-r--r--vendor/gems/attr_encrypted/test/legacy_sequel_test.rb54
-rwxr-xr-xvendor/gems/attr_encrypted/test/run.sh12
-rw-r--r--vendor/gems/attr_encrypted/test/sequel_test.rb55
-rw-r--r--vendor/gems/attr_encrypted/test/test_helper.rb63
-rw-r--r--vendor/gems/bundler-checksum/test/project_with_checksum_lock/Gemfile.checksum1
-rw-r--r--vendor/gems/bundler-checksum/test/project_with_checksum_lock/Gemfile.lock11
-rw-r--r--vendor/gems/devise-pbkdf2-encryptable/Gemfile.lock11
-rw-r--r--vendor/gems/devise-pbkdf2-encryptable/devise-pbkdf2-encryptable.gemspec1
-rw-r--r--vendor/gems/devise-pbkdf2-encryptable/lib/devise-pbkdf2-encryptable.rb1
-rw-r--r--vendor/gems/devise-pbkdf2-encryptable/lib/devise/models/two_factor_backupable_pbkdf2.rb58
-rw-r--r--vendor/gems/devise-pbkdf2-encryptable/spec/lib/models/two_factor_backupable_pbkdf2_spec.rb100
-rw-r--r--vendor/gems/devise-pbkdf2-encryptable/spec/spec_helper.rb2
-rw-r--r--vendor/gems/microsoft_graph_mailer/README.md4
-rw-r--r--vendor/gems/omniauth-gitlab/Gemfile.lock6
-rw-r--r--vendor/gems/omniauth-gitlab/omniauth-gitlab.gemspec2
-rw-r--r--vendor/gems/omniauth-google-oauth2/CHANGELOG.md354
-rw-r--r--vendor/gems/omniauth-google-oauth2/Gemfile.lock87
-rw-r--r--vendor/gems/omniauth-google-oauth2/README.md368
-rw-r--r--vendor/gems/omniauth-google-oauth2/Rakefile8
-rw-r--r--vendor/gems/omniauth-google-oauth2/examples/Gemfile8
-rw-r--r--vendor/gems/omniauth-google-oauth2/examples/Gemfile.lock72
-rw-r--r--vendor/gems/omniauth-google-oauth2/examples/config.ru120
-rw-r--r--vendor/gems/omniauth-google-oauth2/examples/omni_auth.rb37
-rw-r--r--vendor/gems/omniauth-google-oauth2/lib/omniauth-google-oauth2.rb3
-rw-r--r--vendor/gems/omniauth-google-oauth2/lib/omniauth/google_oauth2.rb3
-rw-r--r--vendor/gems/omniauth-google-oauth2/lib/omniauth/google_oauth2/version.rb7
-rw-r--r--vendor/gems/omniauth-google-oauth2/lib/omniauth/strategies/google_oauth2.rb254
-rw-r--r--vendor/gems/omniauth-google-oauth2/omniauth-google-oauth2.gemspec31
-rw-r--r--vendor/gems/omniauth-google-oauth2/spec/omniauth/strategies/google_oauth2_spec.rb850
-rw-r--r--vendor/gems/omniauth-google-oauth2/spec/spec_helper.rb4
52 files changed, 3551 insertions, 2163 deletions
diff --git a/vendor/gems/attr_encrypted/.gitignore b/vendor/gems/attr_encrypted/.gitignore
new file mode 100644
index 00000000000..b25958999b0
--- /dev/null
+++ b/vendor/gems/attr_encrypted/.gitignore
@@ -0,0 +1,5 @@
+.bundle
+.DS_Store
+.ruby-version
+pkg
+coverage
diff --git a/vendor/gems/omniauth-google-oauth2/.gitlab-ci.yml b/vendor/gems/attr_encrypted/.gitlab-ci.yml
index dbc4a7c16b1..42b2b9e1e01 100644
--- a/vendor/gems/omniauth-google-oauth2/.gitlab-ci.yml
+++ b/vendor/gems/attr_encrypted/.gitlab-ci.yml
@@ -2,27 +2,25 @@ workflow:
rules:
- if: $CI_MERGE_REQUEST_ID
-.rspec:
+default:
+ image: "ruby:${RUBY_VERSION}"
+
+rspec:
cache:
- key: omniauth-google-oauth2
+ key: attr_encrypted-ruby
paths:
- - vendor/gems/omniauth-google-oauth2/vendor/ruby
+ - vendor/gems/attr_encrypted/vendor/ruby
before_script:
- - cd vendor/gems/omniauth-google-oauth2
- - ruby -v # Print out ruby version for debugging
+ - cd vendor/gems/attr_encrypted
+ - ruby -v # Print out ruby version for debugging
- gem install bundler --no-document # Bundler is not installed with the image
- bundle config set --local path 'vendor' # Install dependencies into ./vendor/ruby
- - bundle config set with 'development'
+ - bundle config set with 'development' # This is set to 'deployment' otherwise
- bundle config set --local frozen 'true' # Disallow Gemfile.lock changes on CI
- bundle config # Show bundler configuration
- bundle install -j $(nproc)
script:
- - bundle exec rspec
-
-rspec-2.7:
- image: "ruby:2.7"
- extends: .rspec
-
-rspec-3.0:
- image: "ruby:3.0"
- extends: .rspec
+ - bundle exec rake test
+ parallel:
+ matrix:
+ - RUBY_VERSION: ["2.7", "3.0"]
diff --git a/vendor/gems/attr_encrypted/CHANGELOG.md b/vendor/gems/attr_encrypted/CHANGELOG.md
new file mode 100644
index 00000000000..52ef721b311
--- /dev/null
+++ b/vendor/gems/attr_encrypted/CHANGELOG.md
@@ -0,0 +1,98 @@
+# attr_encrypted #
+
+## 3.1.0 ##
+* Added: Abitilty to encrypt empty values. (@tamird)
+* Added: MIT license
+* Added: MRI 2.5.x support (@saghaulor)
+* Fixed: No long generate IV and salt if value is empty, unless :allow_empty_value options is passed. (@saghaulor)
+* Fixed: Only generate IV and salt when :if and :unless options evaluate such that encryption should be performed. (@saghaulor)
+* Fixed: Private methods are correctly evaluated as options. (@saghaulor)
+* Fixed: Mark virtual attributes for Rails 5.x compatibility (@grosser)
+* Fixed: Only check empty on strings, allows for encrypting non-string type objects
+* Fixed: Fixed how accessors for db columns are defined in the ActiveRecord adapter, preventing premature definition. (@nagachika)
+
+## 3.0.3 ##
+* Fixed: attr_was would decrypt the attribute upon every call. This is inefficient and introduces problems when the options change between decrypting an old value and encrypting a new value; for example, when rotating the encryption key. As such, the new approach caches the decrypted value of the old encrypted value such that the old options are no longer needed. (@johnny-lai) (@saghaulor)
+
+## 3.0.2 ##
+* Changed: Removed alias_method_chain for compatibility with Rails v5.x (@grosser)
+* Changed: Updated Travis build matrix to include Rails 5. (@saghaulor) (@connorshea)
+* Changed: Removed `.silence_stream` from tests as it has been removed from Rails 5. (@sblackstone)
+
+## 3.0.1 ##
+* Fixed: attr_was method no longer calls undefined methods. (@saghaulor)
+
+## 3.0.0 ##
+* Changed: Updated gemspec to use Encryptor v3.0.0. (@saghaulor)
+* Changed: Updated README with instructions related to moving from v2.0.0 to v3.0.0. (@saghaulor)
+* Fixed: ActiveModel::Dirty methods in the ActiveRecord adapter. (@saghaulor)
+
+## 2.0.0 ##
+* Added: Now using Encryptor v2.0.0 (@saghaulor)
+* Added: Options are copied to the instance. (@saghaulor)
+* Added: Operation option is set during encryption/decryption to allow options to be evaluated in the context of the current operation. (@saghaulor)
+* Added: IV and salt can be conditionally encoded. (@saghaulor)
+* Added: Changelog! (@saghaulor)
+* Changed: attr_encrypted no longer extends object, to use with PORO extend your class, all supported ORMs are already extended. (@saghaulor)
+* Changed: Salt is now generated with more entropy. (@saghaulor)
+* Changed: The default algorithm is now `aes-256-gcm`. (@saghaulor)
+* Changed: The default mode is now `:per_attribute_iv`' (@saghaulor)
+* Changed: Extracted class level default options hash to a private method. (@saghaulor)
+* Changed: Dynamic finders only work with `:single_iv_and_salt` mode. (@saghaulor)
+* Changed: Updated documentation to include v2.0.0 changes and 'things to consider' section. (@saghaulor)
+* Fixed: All options are evaluated correctly. (@saghaulor)
+* Fixed: IV is generated for every encryption operation. (@saghaulor)
+* Deprecated: `:single_iv_and_salt` and `:per_attribute_iv_and_salt` modes are deprecated and will be removed in the next major release. (@saghaulor)
+* Deprecated: Dynamic finders via `method_missing` is deprecated and will be removed in the next major release. (@saghaulor)
+* Removed: Support for Ruby < 2.x (@saghaulor)
+* Removed: Support for Rails < 3.x (@saghaulor)
+* Removed: Unnecessary use of `alias_method` from ActiveRecord adapter. (@saghaulor)
+
+## 1.4.0 ##
+* Added: ActiveModel::Dirty#attribute_was (@saghaulor)
+* Added: ActiveModel::Dirty#attribute_changed? (@mwean)
+
+## 1.3.5 ##
+* Changed: Fixed gemspec to explicitly depend on Encryptor v1.3.0 (@saghaulor)
+* Fixed: Evaluate `:mode` option as a symbol or proc. (@cheynewallace)
+
+## 1.3.4 ##
+* Added: ActiveRecord::Base.reload support. (@rcook)
+* Fixed: ActiveRecord adapter no longer forces attribute hashes to be string-keyed. (@tamird)
+* Fixed: Mass assignment protection in ActiveRecord 4. (@tamird)
+* Changed: Now using rubygems over https. (@tamird)
+* Changed: Let ActiveRecord define attribute methods. (@saghaulor)
+
+## 1.3.3 ##
+* Added: Alias attr_encryptor and attr_encrpted. (@Billy Monk)
+
+## 1.3.2 ##
+* Fixed: Bug regarding strong parameters. (@S. Brent Faulkner)
+* Fixed: Bug regarding loading per instance IV and salt. (@S. Brent Faulkner)
+* Fixed: Bug regarding assigning nil. (@S. Brent Faulkner)
+* Added: Support for protected attributes. (@S. Brent Faulkner)
+* Added: Support for ActiveRecord 4. (@S. Brent Faulkner)
+
+## 1.3.1 ##
+* Added: Support for Rails 2.3.x and 3.1.x. (@S. Brent Faulkner)
+
+## 1.3.0 ##
+* Fixed: Serialization bug. (@Billy Monk)
+* Added: Support for :per_attribute_iv_and_salt mode. (@rcook)
+* Fixed: Added dependencies to gemspec. (@jmazzi)
+
+## 1.2.1 ##
+* Added: Force encoding when not marshaling. (@mosaicxm)
+* Fixed: Issue specifying multiple attributes on the same line. (@austintaylor)
+* Added: Typecasting to String before encryption (@shuber)
+* Added: `"#{attribute}?"` method. (@shuber)
+
+## 1.2.0 ##
+* Changed: General code refactoring (@shuber)
+
+## 1.1.2 ##
+* No significant changes
+
+## 1.1.1 ##
+* Changled: Updated README. (@shuber)
+* Added: `before_type_cast` alias to ActiveRecord adapter. (@shuber)
diff --git a/vendor/gems/omniauth-google-oauth2/Gemfile b/vendor/gems/attr_encrypted/Gemfile
index 7f4f5e950d1..fa75df15632 100644
--- a/vendor/gems/omniauth-google-oauth2/Gemfile
+++ b/vendor/gems/attr_encrypted/Gemfile
@@ -1,5 +1,3 @@
-# frozen_string_literal: true
-
source 'https://rubygems.org'
gemspec
diff --git a/vendor/gems/attr_encrypted/Gemfile.lock b/vendor/gems/attr_encrypted/Gemfile.lock
new file mode 100644
index 00000000000..1094e6da3fc
--- /dev/null
+++ b/vendor/gems/attr_encrypted/Gemfile.lock
@@ -0,0 +1,155 @@
+PATH
+ remote: .
+ specs:
+ attr_encrypted (3.2.4)
+ encryptor (~> 3.0.0)
+
+GEM
+ remote: https://rubygems.org/
+ specs:
+ actionpack (6.1.7)
+ actionview (= 6.1.7)
+ activesupport (= 6.1.7)
+ rack (~> 2.0, >= 2.0.9)
+ rack-test (>= 0.6.3)
+ rails-dom-testing (~> 2.0)
+ rails-html-sanitizer (~> 1.0, >= 1.2.0)
+ actionview (6.1.7)
+ activesupport (= 6.1.7)
+ builder (~> 3.1)
+ erubi (~> 1.4)
+ rails-dom-testing (~> 2.0)
+ rails-html-sanitizer (~> 1.1, >= 1.2.0)
+ activemodel (6.1.7)
+ activesupport (= 6.1.7)
+ activerecord (6.1.7)
+ activemodel (= 6.1.7)
+ activesupport (= 6.1.7)
+ activesupport (6.1.7)
+ concurrent-ruby (~> 1.0, >= 1.0.2)
+ i18n (>= 1.6, < 2)
+ minitest (>= 5.1)
+ tzinfo (~> 2.0)
+ zeitwerk (~> 2.3)
+ addressable (2.8.1)
+ public_suffix (>= 2.0.2, < 6.0)
+ bcrypt (3.1.18)
+ bcrypt-ruby (3.1.5)
+ bcrypt (>= 3.1.3)
+ builder (3.2.4)
+ codeclimate-test-reporter (0.6.0)
+ simplecov (>= 0.7.1, < 1.0.0)
+ concurrent-ruby (1.1.10)
+ crass (1.0.6)
+ data_objects (0.10.17)
+ addressable (~> 2.1)
+ datamapper (1.2.0)
+ dm-aggregates (~> 1.2.0)
+ dm-constraints (~> 1.2.0)
+ dm-core (~> 1.2.0)
+ dm-migrations (~> 1.2.0)
+ dm-serializer (~> 1.2.0)
+ dm-timestamps (~> 1.2.0)
+ dm-transactions (~> 1.2.0)
+ dm-types (~> 1.2.0)
+ dm-validations (~> 1.2.0)
+ dm-aggregates (1.2.0)
+ dm-core (~> 1.2.0)
+ dm-constraints (1.2.0)
+ dm-core (~> 1.2.0)
+ dm-core (1.2.1)
+ addressable (~> 2.3)
+ dm-do-adapter (1.2.0)
+ data_objects (~> 0.10.6)
+ dm-core (~> 1.2.0)
+ dm-migrations (1.2.0)
+ dm-core (~> 1.2.0)
+ dm-serializer (1.2.2)
+ dm-core (~> 1.2.0)
+ fastercsv (~> 1.5)
+ json (~> 1.6)
+ json_pure (~> 1.6)
+ multi_json (~> 1.0)
+ dm-sqlite-adapter (1.2.0)
+ dm-do-adapter (~> 1.2.0)
+ do_sqlite3 (~> 0.10.6)
+ dm-timestamps (1.2.0)
+ dm-core (~> 1.2.0)
+ dm-transactions (1.2.0)
+ dm-core (~> 1.2.0)
+ dm-types (1.2.2)
+ bcrypt-ruby (~> 3.0)
+ dm-core (~> 1.2.0)
+ fastercsv (~> 1.5)
+ json (~> 1.6)
+ multi_json (~> 1.0)
+ stringex (~> 1.4)
+ uuidtools (~> 2.1)
+ dm-validations (1.2.0)
+ dm-core (~> 1.2.0)
+ do_sqlite3 (0.10.17)
+ data_objects (= 0.10.17)
+ docile (1.4.0)
+ encryptor (3.0.0)
+ erubi (1.11.0)
+ fastercsv (1.5.5)
+ i18n (1.12.0)
+ concurrent-ruby (~> 1.0)
+ json (1.8.6)
+ json_pure (1.8.6)
+ loofah (2.19.0)
+ crass (~> 1.0.2)
+ nokogiri (>= 1.5.9)
+ mini_portile2 (2.8.0)
+ minitest (5.16.3)
+ multi_json (1.15.0)
+ nokogiri (1.13.8)
+ mini_portile2 (~> 2.8.0)
+ racc (~> 1.4)
+ public_suffix (5.0.0)
+ racc (1.6.0)
+ rack (2.2.4)
+ rack-test (2.0.2)
+ rack (>= 1.3)
+ rails-dom-testing (2.0.3)
+ activesupport (>= 4.2.0)
+ nokogiri (>= 1.6)
+ rails-html-sanitizer (1.4.3)
+ loofah (~> 2.3)
+ rake (13.0.6)
+ sequel (5.60.1)
+ simplecov (0.21.2)
+ docile (~> 1.1)
+ simplecov-html (~> 0.11)
+ simplecov_json_formatter (~> 0.1)
+ simplecov-html (0.12.3)
+ simplecov-rcov (0.3.1)
+ simplecov (>= 0.4.1)
+ simplecov_json_formatter (0.1.4)
+ sqlite3 (1.5.0)
+ mini_portile2 (~> 2.8.0)
+ stringex (1.5.1)
+ tzinfo (2.0.5)
+ concurrent-ruby (~> 1.0)
+ uuidtools (2.2.0)
+ zeitwerk (2.6.1)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ actionpack (~> 6.1)
+ activerecord (~> 6.1)
+ attr_encrypted!
+ codeclimate-test-reporter (<= 0.6.0)
+ datamapper
+ dm-sqlite-adapter
+ minitest
+ rake
+ sequel
+ simplecov
+ simplecov-rcov
+ sqlite3
+
+BUNDLED WITH
+ 2.3.22
diff --git a/vendor/gems/attr_encrypted/MIT-LICENSE b/vendor/gems/attr_encrypted/MIT-LICENSE
new file mode 100644
index 00000000000..07f53f78f58
--- /dev/null
+++ b/vendor/gems/attr_encrypted/MIT-LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2008 Sean Huber - shuber@huberry.com
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file
diff --git a/vendor/gems/attr_encrypted/README.md b/vendor/gems/attr_encrypted/README.md
new file mode 100644
index 00000000000..87ac7219a92
--- /dev/null
+++ b/vendor/gems/attr_encrypted/README.md
@@ -0,0 +1,466 @@
+## Maintainer(s) wanted!!!
+
+**If you have an interest in maintaining this project... please see https://github.com/attr-encrypted/attr_encrypted/issues/379**
+
+# attr_encrypted
+
+[![Build Status](https://secure.travis-ci.org/attr-encrypted/attr_encrypted.svg)](https://travis-ci.org/attr-encrypted/attr_encrypted) [![Test Coverage](https://codeclimate.com/github/attr-encrypted/attr_encrypted/badges/coverage.svg)](https://codeclimate.com/github/attr-encrypted/attr_encrypted/coverage) [![Code Climate](https://codeclimate.com/github/attr-encrypted/attr_encrypted/badges/gpa.svg)](https://codeclimate.com/github/attr-encrypted/attr_encrypted) [![Gem Version](https://badge.fury.io/rb/attr_encrypted.svg)](https://badge.fury.io/rb/attr_encrypted) [![security](https://hakiri.io/github/attr-encrypted/attr_encrypted/master.svg)](https://hakiri.io/github/attr-encrypted/attr_encrypted/master)
+
+Generates attr_accessors that transparently encrypt and decrypt attributes.
+
+It works with ANY class, however, you get a few extra features when you're using it with `ActiveRecord`, `DataMapper`, or `Sequel`.
+
+
+## Installation
+
+Add attr_encrypted to your gemfile:
+
+```ruby
+ gem "attr_encrypted", "~> 3.1.0"
+```
+
+Then install the gem:
+
+```bash
+ bundle install
+```
+
+## Usage
+
+If you're using an ORM like `ActiveRecord`, `DataMapper`, or `Sequel`, using attr_encrypted is easy:
+
+```ruby
+ class User
+ attr_encrypted :ssn, key: 'This is a key that is 256 bits!!'
+ end
+```
+
+If you're using a PORO, you have to do a little bit more work by extending the class:
+
+```ruby
+ class User
+ extend AttrEncrypted
+ attr_accessor :name
+ attr_encrypted :ssn, key: 'This is a key that is 256 bits!!'
+
+ def load
+ # loads the stored data
+ end
+
+ def save
+ # saves the :name and :encrypted_ssn attributes somewhere (e.g. filesystem, database, etc)
+ end
+ end
+
+ user = User.new
+ user.ssn = '123-45-6789'
+ user.ssn # returns the unencrypted object ie. '123-45-6789'
+ user.encrypted_ssn # returns the encrypted version of :ssn
+ user.save
+
+ user = User.load
+ user.ssn # decrypts :encrypted_ssn and returns '123-45-6789'
+```
+
+### Encrypt/decrypt attribute class methods
+
+Two class methods are available for each attribute: `User.encrypt_email` and `User.decrypt_email`. They accept as arguments the same options that the `attr_encrypted` class method accepts. For example:
+
+```ruby
+ key = SecureRandom.random_bytes(32)
+ iv = SecureRandom.random_bytes(12)
+ encrypted_email = User.encrypt_email('test@test.com', iv: iv, key: key)
+ email = User.decrypt_email(encrypted_email, iv: iv, key: key)
+```
+
+The `attr_encrypted` class method is also aliased as `attr_encryptor` to conform to Ruby's `attr_` naming conventions. I should have called this project `attr_encryptor` but it was too late when I realized it ='(.
+
+### attr_encrypted with database persistence
+
+By default, `attr_encrypted` uses the `:per_attribute_iv` encryption mode. This mode requires a column to store your cipher text and a column to store your IV (initialization vector).
+
+Create or modify the table that your model uses to add a column with the `encrypted_` prefix (which can be modified, see below), e.g. `encrypted_ssn` via a migration like the following:
+
+```ruby
+ create_table :users do |t|
+ t.string :name
+ t.string :encrypted_ssn
+ t.string :encrypted_ssn_iv
+ t.timestamps
+ end
+```
+
+You can use a string or binary column type. (See the encode option section below for more info)
+
+If you use the same key for each record, add a unique index on the IV. Repeated IVs with AES-GCM (the default algorithm) allow an attacker to recover the key.
+
+```ruby
+ add_index :users, :encrypted_ssn_iv, unique: true
+```
+
+### Specifying the encrypted attribute name
+
+By default, the encrypted attribute name is `encrypted_#{attribute}` (e.g. `attr_encrypted :email` would create an attribute named `encrypted_email`). So, if you're storing the encrypted attribute in the database, you need to make sure the `encrypted_#{attribute}` field exists in your table. You have a couple of options if you want to name your attribute or db column something else, see below for more details.
+
+
+## attr_encrypted options
+
+#### Options are evaluated
+All options will be evaluated at the instance level. If you pass in a symbol it will be passed as a message to the instance of your class. If you pass a proc or any object that responds to `:call` it will be called. You can pass in the instance of your class as an argument to the proc. Anything else will be returned. For example:
+
+##### Symbols representing instance methods
+
+Here is an example class that uses an instance method to determines the encryption key to use.
+
+```ruby
+ class User
+ attr_encrypted :email, key: :encryption_key
+
+ def encryption_key
+ # does some fancy logic and returns an encryption key
+ end
+ end
+```
+
+
+##### Procs
+
+Here is an example of passing a proc/lambda object as the `:key` option as well:
+
+```ruby
+ class User
+ attr_encrypted :email, key: proc { |user| user.key }
+ end
+```
+
+
+### Default options
+
+The following are the default options used by `attr_encrypted`:
+
+```ruby
+ prefix: 'encrypted_',
+ suffix: '',
+ if: true,
+ unless: false,
+ encode: false,
+ encode_iv: true,
+ encode_salt: true,
+ default_encoding: 'm',
+ marshal: false,
+ marshaler: Marshal,
+ dump_method: 'dump',
+ load_method: 'load',
+ encryptor: Encryptor,
+ encrypt_method: 'encrypt',
+ decrypt_method: 'decrypt',
+ mode: :per_attribute_iv,
+ algorithm: 'aes-256-gcm',
+ allow_empty_value: false
+```
+
+All of the aforementioned options are explained in depth below.
+
+Additionally, you can specify default options for all encrypted attributes in your class. Instead of having to define your class like this:
+
+```ruby
+ class User
+ attr_encrypted :email, key: 'This is a key that is 256 bits!!', prefix: '', suffix: '_crypted'
+ attr_encrypted :ssn, key: 'a different secret key', prefix: '', suffix: '_crypted'
+ attr_encrypted :credit_card, key: 'another secret key', prefix: '', suffix: '_crypted'
+ end
+```
+
+You can simply define some default options like so:
+
+```ruby
+ class User
+ attr_encrypted_options.merge!(prefix: '', :suffix => '_crypted')
+ attr_encrypted :email, key: 'This is a key that is 256 bits!!'
+ attr_encrypted :ssn, key: 'a different secret key'
+ attr_encrypted :credit_card, key: 'another secret key'
+ end
+```
+
+This should help keep your classes clean and DRY.
+
+### The `:attribute` option
+
+You can simply pass the name of the encrypted attribute as the `:attribute` option:
+
+```ruby
+ class User
+ attr_encrypted :email, key: 'This is a key that is 256 bits!!', attribute: 'email_encrypted'
+ end
+```
+
+This would generate an attribute named `email_encrypted`
+
+
+### The `:prefix` and `:suffix` options
+
+If you don't like the `encrypted_#{attribute}` naming convention then you can specify your own:
+
+```ruby
+ class User
+ attr_encrypted :email, key: 'This is a key that is 256 bits!!', prefix: 'secret_', suffix: '_crypted'
+ end
+```
+
+This would generate the following attribute: `secret_email_crypted`.
+
+
+### The `:key` option
+
+The `:key` option is used to pass in a data encryption key to be used with whatever encryption class you use. If you're using `Encryptor`, the key must meet minimum length requirements respective to the algorithm that you use; aes-256 requires a 256 bit key, etc. The `:key` option is not required (see custom encryptor below).
+
+
+##### Unique keys for each attribute
+
+You can specify unique keys for each attribute if you'd like:
+
+```ruby
+ class User
+ attr_encrypted :email, key: 'This is a key that is 256 bits!!'
+ attr_encrypted :ssn, key: 'a different secret key'
+ end
+```
+
+It is recommended to use a symbol or a proc for the key and to store information regarding what key was used to encrypt your data. (See below for more details.)
+
+
+### The `:if` and `:unless` options
+
+There may be times that you want to only encrypt when certain conditions are met. For example maybe you're using rails and you don't want to encrypt attributes when you're in development mode. You can specify conditions like this:
+
+```ruby
+ class User < ActiveRecord::Base
+ attr_encrypted :email, key: 'This is a key that is 256 bits!!', unless: Rails.env.development?
+ attr_encrypted :ssn, key: 'This is a key that is 256 bits!!', if: Rails.env.development?
+ end
+```
+
+You can specify both `:if` and `:unless` options.
+
+
+### The `:encryptor`, `:encrypt_method`, and `:decrypt_method` options
+
+The `Encryptor` class is used by default. You may use your own custom encryptor by specifying the `:encryptor`, `:encrypt_method`, and `:decrypt_method` options.
+
+Lets suppose you'd like to use this custom encryptor class:
+
+```ruby
+ class SillyEncryptor
+ def self.silly_encrypt(options)
+ (options[:value] + options[:secret_key]).reverse
+ end
+
+ def self.silly_decrypt(options)
+ options[:value].reverse.gsub(/#{options[:secret_key]}$/, '')
+ end
+ end
+```
+
+Simply set up your class like so:
+
+```ruby
+ class User
+ attr_encrypted :email, secret_key: 'This is a key that is 256 bits!!', encryptor: SillyEncryptor, encrypt_method: :silly_encrypt, decrypt_method: :silly_decrypt
+ end
+```
+
+Any options that you pass to `attr_encrypted` will be passed to the encryptor class along with the `:value` option which contains the string to encrypt/decrypt. Notice that the above example uses `:secret_key` instead of `:key`. See [encryptor](https://github.com/attr-encrypted/encryptor) for more info regarding the default encryptor class.
+
+
+### The `:mode` option
+
+The mode options allows you to specify in what mode your data will be encrypted. There are currently three modes: `:per_attribute_iv`, `:per_attribute_iv_and_salt`, and `:single_iv_and_salt`.
+
+__NOTE: `:per_attribute_iv_and_salt` and `:single_iv_and_salt` modes are deprecated and will be removed in the next major release.__
+
+
+### The `:algorithm` option
+
+The default `Encryptor` class uses the standard ruby OpenSSL library. Its default algorithm is `aes-256-gcm`. You can modify this by passing the `:algorithm` option to the `attr_encrypted` call like so:
+
+```ruby
+ class User
+ attr_encrypted :email, key: 'This is a key that is 256 bits!!', algorithm: 'aes-256-cbc'
+ end
+```
+
+To view a list of all cipher algorithms that are supported on your platform, run the following code in your favorite Ruby REPL:
+
+```ruby
+ require 'openssl'
+ puts OpenSSL::Cipher.ciphers
+```
+See [Encryptor](https://github.com/attr-encrypted/encryptor#algorithms) for more information.
+
+
+### The `:encode`, `:encode_iv`, `:encode_salt`, and `:default_encoding` options
+
+You're probably going to be storing your encrypted attributes somehow (e.g. filesystem, database, etc). You can simply pass the `:encode` option to automatically encode/decode when encrypting/decrypting. The default behavior assumes that you're using a string column type and will base64 encode your cipher text. If you choose to use the binary column type then encoding is not required, but be sure to pass in `false` with the `:encode` option.
+
+```ruby
+ class User
+ attr_encrypted :email, key: 'some secret key', encode: true, encode_iv: true, encode_salt: true
+ end
+```
+
+The default encoding is `m` (base64). You can change this by setting `encode: 'some encoding'`. See [`Array#pack`](http://ruby-doc.org/core-2.3.0/Array.html#method-i-pack) for more encoding options.
+
+
+### The `:marshal`, `:dump_method`, and `:load_method` options
+
+You may want to encrypt objects other than strings (e.g. hashes, arrays, etc). If this is the case, simply pass the `:marshal` option to automatically marshal when encrypting/decrypting.
+
+```ruby
+ class User
+ attr_encrypted :credentials, key: 'some secret key', marshal: true
+ end
+```
+
+You may also optionally specify `:marshaler`, `:dump_method`, and `:load_method` if you want to use something other than the default `Marshal` object.
+
+### The `:allow_empty_value` option
+
+You may want to encrypt empty strings or nil so as to not reveal which records are populated and which records are not.
+
+```ruby
+ class User
+ attr_encrypted :credentials, key: 'some secret key', marshal: true, allow_empty_value: true
+ end
+```
+
+
+## ORMs
+
+### ActiveRecord
+
+If you're using this gem with `ActiveRecord`, you get a few extra features:
+
+#### Default options
+
+The `:encode` option is set to true by default.
+
+#### Dynamic `find_by_` and `scoped_by_` methods
+
+Let's say you'd like to encrypt your user's email addresses, but you also need a way for them to login. Simply set up your class like so:
+
+```ruby
+ class User < ActiveRecord::Base
+ attr_encrypted :email, key: 'This is a key that is 256 bits!!'
+ attr_encrypted :password, key: 'some other secret key'
+ end
+```
+
+You can now lookup and login users like so:
+
+```ruby
+ User.find_by_email_and_password('test@example.com', 'testing')
+```
+
+The call to `find_by_email_and_password` is intercepted and modified to `find_by_encrypted_email_and_encrypted_password('ENCRYPTED EMAIL', 'ENCRYPTED PASSWORD')`. The dynamic scope methods like `scoped_by_email_and_password` work the same way.
+
+NOTE: This only works if all records are encrypted with the same encryption key (per attribute).
+
+__NOTE: This feature is deprecated and will be removed in the next major release.__
+
+
+### DataMapper and Sequel
+
+#### Default options
+
+The `:encode` option is set to true by default.
+
+
+## Deprecations
+
+attr_encrypted v2.0.0 now depends on encryptor v2.0.0. As part of both major releases many insecure defaults and behaviors have been deprecated. The new default behavior is as follows:
+
+* Default `:mode` is now `:per_attribute_iv`, the default `:mode` in attr_encrypted v1.x was `:single_iv_and_salt`.
+* Default `:algorithm` is now 'aes-256-gcm', the default `:algorithm` in attr_encrypted v1.x was 'aes-256-cbc'.
+* The encryption key provided must be of appropriate length respective to the algorithm used. Previously, encryptor did not verify minimum key length.
+* The dynamic finders available in ActiveRecord will only work with `:single_iv_and_salt` mode. It is strongly advised that you do not use this mode. If you can search the encrypted data, it wasn't encrypted securely. This functionality will be deprecated in the next major release.
+* `:per_attribute_iv_and_salt` and `:single_iv_and_salt` modes are deprecated and will be removed in the next major release.
+
+Backwards compatibility is supported by providing a special option that is passed to encryptor, namely, `:insecure_mode`:
+
+```ruby
+ class User
+ attr_encrypted :email, key: 'a secret key', algorithm: 'aes-256-cbc', mode: :single_iv_and_salt, insecure_mode: true
+ end
+```
+
+The `:insecure_mode` option will allow encryptor to ignore the new security requirements. It is strongly advised that if you use this older insecure behavior that you migrate to the newer more secure behavior.
+
+
+## Upgrading from attr_encrypted v1.x to v3.x
+
+Modify your gemfile to include the new version of attr_encrypted:
+
+```ruby
+ gem attr_encrypted, "~> 3.0.0"
+```
+
+The update attr_encrypted:
+
+```bash
+ bundle update attr_encrypted
+```
+
+Then modify your models using attr\_encrypted to account for the changes in default options. Specifically, pass in the `:mode` and `:algorithm` options that you were using if you had not previously done so. If your key is insufficient length relative to the algorithm that you use, you should also pass in `insecure_mode: true`; this will prevent Encryptor from raising an exception regarding insufficient key length. Please see the Deprecations sections for more details including an example of how to specify your model with default options from attr_encrypted v1.x.
+
+## Upgrading from attr_encrypted v2.x to v3.x
+
+A bug was discovered in Encryptor v2.0.0 that inccorectly set the IV when using an AES-\*-GCM algorithm. Unfornately fixing this major security issue results in the inability to decrypt records encrypted using an AES-*-GCM algorithm from Encryptor v2.0.0. Please see [Upgrading to Encryptor v3.0.0](https://github.com/attr-encrypted/encryptor#upgrading-from-v200-to-v300) for more info.
+
+It is strongly advised that you re-encrypt your data encrypted with Encryptor v2.0.0. However, you'll have to take special care to re-encrypt. To decrypt data encrypted with Encryptor v2.0.0 using an AES-\*-GCM algorithm you can use the `:v2_gcm_iv` option.
+
+It is recommended that you implement a strategy to insure that you do not mix the encryption implementations of Encryptor. One way to do this is to re-encrypt everything while your application is offline.Another way is to add a column that keeps track of what implementation was used. The path that you choose will depend on your situtation. Below is an example of how you might go about re-encrypting your data.
+
+```ruby
+ class User
+ attr_encrypted :ssn, key: :encryption_key, v2_gcm_iv: is_decrypting?(:ssn)
+
+ def is_decrypting?(attribute)
+ encrypted_attributes[attribute][:operation] == :decrypting
+ end
+ end
+
+ User.all.each do |user|
+ old_ssn = user.ssn
+ user.ssn= old_ssn
+ user.save
+ end
+```
+
+## Things to consider before using attr_encrypted
+
+#### Searching, joining, etc
+While choosing to encrypt at the attribute level is the most secure solution, it is not without drawbacks. Namely, you cannot search the encrypted data, and because you can't search it, you can't index it either. You also can't use joins on the encrypted data. Data that is securely encrypted is effectively noise. So any operations that rely on the data not being noise will not work. If you need to do any of the aforementioned operations, please consider using database and file system encryption along with transport encryption as it moves through your stack.
+
+#### Data leaks
+Please also consider where your data leaks. If you're using attr_encrypted with Rails, it's highly likely that this data will enter your app as a request parameter. You'll want to be sure that you're filtering your request params from you logs or else your data is sitting in the clear in your logs. [Parameter Filtering in Rails](http://apidock.com/rails/ActionDispatch/Http/FilterParameters) Please also consider other possible leak points.
+
+#### Storage requirements
+When storing your encrypted data, please consider the length requirements of the db column that you're storing the cipher text in. Older versions of Mysql attempt to 'help' you by truncating strings that are too large for the column. When this happens, you will not be able to decrypt your data. [MySQL Strict Trans](http://www.davidpashley.com/2009/02/15/silently-truncated/)
+
+#### Metadata regarding your crypto implementation
+It is advisable to also store metadata regarding the circumstances of your encrypted data. Namely, you should store information about the key used to encrypt your data, as well as the algorithm. Having this metadata with every record will make key rotation and migrating to a new algorithm signficantly easier. It will allow you to continue to decrypt old data using the information provided in the metadata and new data can be encrypted using your new key and algorithm of choice.
+
+#### Enforcing the IV as a nonce
+On a related note, most algorithms require that your IV be unique for every record and key combination. You can enforce this using composite unique indexes on your IV and encryption key name/id column. [RFC 5084](https://tools.ietf.org/html/rfc5084#section-1.5)
+
+#### Unique key per record
+Lastly, while the `:per_attribute_iv_and_salt` mode is more secure than `:per_attribute_iv` mode because it uses a unique key per record, it uses a PBKDF function which introduces a huge performance hit (175x slower by my benchmarks). There are other ways of deriving a unique key per record that would be much faster.
+
+## Note on Patches/Pull Requests
+
+* Fork the project.
+* Make your feature addition or bug fix.
+* Add tests for it. This is important so I don't break it in a
+ future version unintentionally.
+* Commit, do not mess with rakefile, version, changelog, or history.
+* Send me a pull request. Bonus points for topic branches.
diff --git a/vendor/gems/attr_encrypted/Rakefile b/vendor/gems/attr_encrypted/Rakefile
new file mode 100644
index 00000000000..3dbc96ceb14
--- /dev/null
+++ b/vendor/gems/attr_encrypted/Rakefile
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+require 'rake/testtask'
+require 'rdoc/task'
+require "bundler/gem_tasks"
+
+desc 'Test the attr_encrypted gem.'
+Rake::TestTask.new(:test) do |t|
+ t.libs << 'lib'
+ t.pattern = 'test/**/*_test.rb'
+ t.warning = false
+ t.verbose = true
+end
+
+desc 'Generate documentation for the attr_encrypted gem.'
+Rake::RDocTask.new(:rdoc) do |rdoc|
+ rdoc.rdoc_dir = 'rdoc'
+ rdoc.title = 'attr_encrypted'
+ rdoc.options << '--line-numbers' << '--inline-source'
+ rdoc.rdoc_files.include('README*')
+ rdoc.rdoc_files.include('lib/**/*.rb')
+end
+
+desc 'Default: run unit tests.'
+task :default => :test
diff --git a/vendor/gems/attr_encrypted/attr_encrypted.gemspec b/vendor/gems/attr_encrypted/attr_encrypted.gemspec
new file mode 100644
index 00000000000..b6a39bddd2c
--- /dev/null
+++ b/vendor/gems/attr_encrypted/attr_encrypted.gemspec
@@ -0,0 +1,52 @@
+# -*- encoding: utf-8 -*-
+
+lib = File.expand_path('../lib/', __FILE__)
+$:.unshift lib unless $:.include?(lib)
+
+require 'attr_encrypted/version'
+require 'date'
+
+Gem::Specification.new do |s|
+ s.name = 'attr_encrypted'
+ s.version = AttrEncrypted::Version.string
+ s.date = Date.today
+
+ s.summary = 'GitLab fork of attr_encrypted'
+ s.description = "Generates attr_accessors that encrypt and decrypt attributes transparently.\n\n
+Forked from https://github.com/attr-encrypted/attr_encrypted."
+
+ s.authors = ['Sean Huber', 'S. Brent Faulkner', 'William Monk', 'Stephen Aghaulor']
+ s.email = ['seah@shuber.io', 'sbfaulkner@gmail.com', 'billy.monk@gmail.com', 'saghaulor@gmail.com']
+ s.homepage = 'https://gitlab.com/gitlab-org/ruby/gems/attr_encrypted'
+ s.license = 'MIT'
+
+ s.rdoc_options = ['--line-numbers', '--inline-source', '--main', 'README.rdoc']
+
+ s.require_paths = ['lib']
+
+ s.files = Dir['lib/**/*.rb']
+ s.test_files = Dir['test/**/*']
+
+ s.required_ruby_version = '>= 2.7.0'
+
+ s.add_dependency('encryptor', ['~> 3.0.0'])
+
+ activerecord_version = "~> 6.1"
+ s.add_development_dependency('activerecord', activerecord_version)
+ s.add_development_dependency('actionpack', activerecord_version)
+ s.add_development_dependency('datamapper')
+ s.add_development_dependency('rake')
+ s.add_development_dependency('minitest')
+ s.add_development_dependency('sequel')
+ s.add_development_dependency('sqlite3')
+ s.add_development_dependency('dm-sqlite-adapter')
+ s.add_development_dependency('simplecov')
+ s.add_development_dependency('simplecov-rcov')
+ s.add_development_dependency("codeclimate-test-reporter", '<= 0.6.0')
+
+ s.post_install_message = "\n\n\nWARNING: Several insecure default options and features were deprecated in attr_encrypted v2.0.0.\n
+Additionally, there was a bug in Encryptor v2.0.0 that insecurely encrypted data when using an AES-*-GCM algorithm.\n
+This bug was fixed but introduced breaking changes between v2.x and v3.x.\n
+Please see the README for more information regarding upgrading to attr_encrypted v3.0.0.\n\n\n"
+
+end
diff --git a/vendor/gems/attr_encrypted/lib/attr_encrypted.rb b/vendor/gems/attr_encrypted/lib/attr_encrypted.rb
new file mode 100644
index 00000000000..88e5f65e3c8
--- /dev/null
+++ b/vendor/gems/attr_encrypted/lib/attr_encrypted.rb
@@ -0,0 +1,473 @@
+# frozen_string_literal: true
+
+require 'encryptor'
+
+# Adds attr_accessors that encrypt and decrypt an object's attributes
+module AttrEncrypted
+ autoload :Version, 'attr_encrypted/version'
+
+ def self.extended(base) # :nodoc:
+ base.class_eval do
+ include InstanceMethods
+ attr_writer :attr_encrypted_options
+ @attr_encrypted_options, @encrypted_attributes = {}, {}
+ end
+ end
+
+ # Generates attr_accessors that encrypt and decrypt attributes transparently
+ #
+ # Options (any other options you specify are passed to the Encryptor's encrypt and decrypt methods)
+ #
+ # attribute: The name of the referenced encrypted attribute. For example
+ # <tt>attr_accessor :email, attribute: :ee</tt> would generate an
+ # attribute named 'ee' to store the encrypted email. This is useful when defining
+ # one attribute to encrypt at a time or when the :prefix and :suffix options
+ # aren't enough.
+ # Defaults to nil.
+ #
+ # prefix: A prefix used to generate the name of the referenced encrypted attributes.
+ # For example <tt>attr_accessor :email, prefix: 'crypted_'</tt> would
+ # generate attributes named 'crypted_email' to store the encrypted
+ # email and password.
+ # Defaults to 'encrypted_'.
+ #
+ # suffix: A suffix used to generate the name of the referenced encrypted attributes.
+ # For example <tt>attr_accessor :email, prefix: '', suffix: '_encrypted'</tt>
+ # would generate attributes named 'email_encrypted' to store the
+ # encrypted email.
+ # Defaults to ''.
+ #
+ # key: The encryption key. This option may not be required if
+ # you're using a custom encryptor. If you pass a symbol
+ # representing an instance method then the :key option
+ # will be replaced with the result of the method before
+ # being passed to the encryptor. Objects that respond
+ # to :call are evaluated as well (including procs).
+ # Any other key types will be passed directly to the encryptor.
+ # Defaults to nil.
+ #
+ # encode: If set to true, attributes will be encoded as well as
+ # encrypted. This is useful if you're planning on storing
+ # the encrypted attributes in a database. The default
+ # encoding is 'm' (base64), however this can be overwritten
+ # by setting the :encode option to some other encoding
+ # string instead of just 'true'. See
+ # http://www.ruby-doc.org/core/classes/Array.html#M002245
+ # for more encoding directives.
+ # Defaults to false unless you're using it with ActiveRecord, DataMapper, or Sequel.
+ #
+ # encode_iv: Defaults to true.
+
+ # encode_salt: Defaults to true.
+ #
+ # default_encoding: Defaults to 'm' (base64).
+ #
+ # marshal: If set to true, attributes will be marshaled as well
+ # as encrypted. This is useful if you're planning on
+ # encrypting something other than a string.
+ # Defaults to false.
+ #
+ # marshaler: The object to use for marshaling.
+ # Defaults to Marshal.
+ #
+ # dump_method: The dump method name to call on the <tt>:marshaler</tt> object to.
+ # Defaults to 'dump'.
+ #
+ # load_method: The load method name to call on the <tt>:marshaler</tt> object.
+ # Defaults to 'load'.
+ #
+ # encryptor: The object to use for encrypting.
+ # Defaults to Encryptor.
+ #
+ # encrypt_method: The encrypt method name to call on the <tt>:encryptor</tt> object.
+ # Defaults to 'encrypt'.
+ #
+ # decrypt_method: The decrypt method name to call on the <tt>:encryptor</tt> object.
+ # Defaults to 'decrypt'.
+ #
+ # if: Attributes are only encrypted if this option evaluates
+ # to true. If you pass a symbol representing an instance
+ # method then the result of the method will be evaluated.
+ # Any objects that respond to <tt>:call</tt> are evaluated as well.
+ # Defaults to true.
+ #
+ # unless: Attributes are only encrypted if this option evaluates
+ # to false. If you pass a symbol representing an instance
+ # method then the result of the method will be evaluated.
+ # Any objects that respond to <tt>:call</tt> are evaluated as well.
+ # Defaults to false.
+ #
+ # mode: Selects encryption mode for attribute: choose <tt>:single_iv_and_salt</tt> for compatibility
+ # with the old attr_encrypted API: the IV is derived from the encryption key by the underlying Encryptor class; salt is not used.
+ # The <tt>:per_attribute_iv_and_salt</tt> mode uses a per-attribute IV and salt. The salt is used to derive a unique key per attribute.
+ # A <tt>:per_attribute_iv</default> mode derives a unique IV per attribute; salt is not used.
+ # Defaults to <tt>:per_attribute_iv</tt>.
+ #
+ # allow_empty_value: Attributes which have nil or empty string values will not be encrypted unless this option
+ # has a truthy value.
+ #
+ # You can specify your own default options
+ #
+ # class User
+ # # Now all attributes will be encoded and marshaled by default
+ # attr_encrypted_options.merge!(encode: true, marshal: true, some_other_option: true)
+ # attr_encrypted :configuration, key: 'my secret key'
+ # end
+ #
+ #
+ # Example
+ #
+ # class User
+ # attr_encrypted :email, key: 'some secret key'
+ # attr_encrypted :configuration, key: 'some other secret key', marshal: true
+ # end
+ #
+ # @user = User.new
+ # @user.encrypted_email # nil
+ # @user.email? # false
+ # @user.email = 'test@example.com'
+ # @user.email? # true
+ # @user.encrypted_email # returns the encrypted version of 'test@example.com'
+ #
+ # @user.configuration = { time_zone: 'UTC' }
+ # @user.encrypted_configuration # returns the encrypted version of configuration
+ #
+ # See README for more examples
+ def attr_encrypted(*attributes)
+ options = attributes.last.is_a?(Hash) ? attributes.pop : {}
+ options = attr_encrypted_default_options.dup.merge!(attr_encrypted_options).merge!(options)
+
+ options[:encode] = options[:default_encoding] if options[:encode] == true
+ options[:encode_iv] = options[:default_encoding] if options[:encode_iv] == true
+ options[:encode_salt] = options[:default_encoding] if options[:encode_salt] == true
+
+ attributes.each do |attribute|
+ encrypted_attribute_name = (options[:attribute] ? options[:attribute] : [options[:prefix], attribute, options[:suffix]].join).to_sym
+
+ instance_methods_as_symbols = attribute_instance_methods_as_symbols
+
+ if attribute_instance_methods_as_symbols_available?
+ attr_reader encrypted_attribute_name unless instance_methods_as_symbols.include?(encrypted_attribute_name)
+ attr_writer encrypted_attribute_name unless instance_methods_as_symbols.include?(:"#{encrypted_attribute_name}=")
+
+ iv_name = "#{encrypted_attribute_name}_iv".to_sym
+ attr_reader iv_name unless instance_methods_as_symbols.include?(iv_name)
+ attr_writer iv_name unless instance_methods_as_symbols.include?(:"#{iv_name}=")
+
+ salt_name = "#{encrypted_attribute_name}_salt".to_sym
+ attr_reader salt_name unless instance_methods_as_symbols.include?(salt_name)
+ attr_writer salt_name unless instance_methods_as_symbols.include?(:"#{salt_name}=")
+ end
+
+ define_method(attribute) do
+ instance_variable_get("@#{attribute}") || instance_variable_set("@#{attribute}", decrypt(attribute, send(encrypted_attribute_name)))
+ end
+
+ define_method("#{attribute}=") do |value|
+ send("#{encrypted_attribute_name}=", encrypt(attribute, value))
+ instance_variable_set("@#{attribute}", value)
+ end
+
+ define_method("#{attribute}?") do
+ value = send(attribute)
+ value.respond_to?(:empty?) ? !value.empty? : !!value
+ end
+
+ encrypted_attributes[attribute.to_sym] = options.merge(attribute: encrypted_attribute_name)
+ end
+ end
+
+ alias_method :attr_encryptor, :attr_encrypted
+
+ # Default options to use with calls to <tt>attr_encrypted</tt>
+ #
+ # It will inherit existing options from its superclass
+ def attr_encrypted_options
+ @attr_encrypted_options ||= superclass.attr_encrypted_options.dup
+ end
+
+ def attr_encrypted_default_options
+ {
+ prefix: 'encrypted_',
+ suffix: '',
+ if: true,
+ unless: false,
+ encode: false,
+ encode_iv: true,
+ encode_salt: true,
+ default_encoding: 'm',
+ marshal: false,
+ marshaler: Marshal,
+ dump_method: 'dump',
+ load_method: 'load',
+ encryptor: Encryptor,
+ encrypt_method: 'encrypt',
+ decrypt_method: 'decrypt',
+ mode: :per_attribute_iv,
+ algorithm: 'aes-256-gcm',
+ allow_empty_value: false,
+ }
+ end
+
+ private :attr_encrypted_default_options
+
+ # Checks if an attribute is configured with <tt>attr_encrypted</tt>
+ #
+ # Example
+ #
+ # class User
+ # attr_accessor :name
+ # attr_encrypted :email
+ # end
+ #
+ # User.attr_encrypted?(:name) # false
+ # User.attr_encrypted?(:email) # true
+ def attr_encrypted?(attribute)
+ encrypted_attributes.has_key?(attribute.to_sym)
+ end
+
+ # Decrypts a value for the attribute specified
+ #
+ # Example
+ #
+ # class User
+ # attr_encrypted :email
+ # end
+ #
+ # email = User.decrypt(:email, 'SOME_ENCRYPTED_EMAIL_STRING')
+ def decrypt(attribute, encrypted_value, options = {})
+ options = encrypted_attributes[attribute.to_sym].merge(options)
+ if options[:if] && !options[:unless] && not_empty?(encrypted_value)
+ encrypted_value = encrypted_value.unpack(options[:encode]).first if options[:encode]
+ value = options[:encryptor].send(options[:decrypt_method], options.merge!(value: encrypted_value))
+ if options[:marshal]
+ value = options[:marshaler].send(options[:load_method], value)
+ elsif defined?(Encoding)
+ encoding = Encoding.default_internal || Encoding.default_external
+ value = value.force_encoding(encoding.name)
+ end
+ value
+ else
+ encrypted_value
+ end
+ end
+
+ # Encrypts a value for the attribute specified
+ #
+ # Example
+ #
+ # class User
+ # attr_encrypted :email
+ # end
+ #
+ # encrypted_email = User.encrypt(:email, 'test@example.com')
+ def encrypt(attribute, value, options = {})
+ options = encrypted_attributes[attribute.to_sym].merge(options)
+ if options[:if] && !options[:unless] && (options[:allow_empty_value] || not_empty?(value))
+ value = options[:marshal] ? options[:marshaler].send(options[:dump_method], value) : value.to_s
+ encrypted_value = options[:encryptor].send(options[:encrypt_method], options.merge!(value: value))
+ encrypted_value = [encrypted_value].pack(options[:encode]) if options[:encode]
+ encrypted_value
+ else
+ value
+ end
+ end
+
+ def not_empty?(value)
+ !value.nil? && !(value.is_a?(String) && value.empty?)
+ end
+
+ # Contains a hash of encrypted attributes with virtual attribute names as keys
+ # and their corresponding options as values
+ #
+ # Example
+ #
+ # class User
+ # attr_encrypted :email, key: 'my secret key'
+ # end
+ #
+ # User.encrypted_attributes # { email: { attribute: 'encrypted_email', key: 'my secret key' } }
+ def encrypted_attributes
+ @encrypted_attributes ||= superclass.encrypted_attributes.dup
+ end
+
+ # Forwards calls to :encrypt_#{attribute} or :decrypt_#{attribute} to the corresponding encrypt or decrypt method
+ # if attribute was configured with attr_encrypted
+ #
+ # Example
+ #
+ # class User
+ # attr_encrypted :email, key: 'my secret key'
+ # end
+ #
+ # User.encrypt_email('SOME_ENCRYPTED_EMAIL_STRING')
+ def method_missing(method, *arguments, &block)
+ if method.to_s =~ /^((en|de)crypt)_(.+)$/ && attr_encrypted?($3)
+ send($1, $3, *arguments)
+ else
+ super
+ end
+ end
+
+ module InstanceMethods
+ # Decrypts a value for the attribute specified using options evaluated in the current object's scope
+ #
+ # Example
+ #
+ # class User
+ # attr_accessor :secret_key
+ # attr_encrypted :email, key: :secret_key
+ #
+ # def initialize(secret_key)
+ # self.secret_key = secret_key
+ # end
+ # end
+ #
+ # @user = User.new('some-secret-key')
+ # @user.decrypt(:email, 'SOME_ENCRYPTED_EMAIL_STRING')
+ def decrypt(attribute, encrypted_value)
+ encrypted_attributes[attribute.to_sym][:operation] = :decrypting
+ encrypted_attributes[attribute.to_sym][:value_present] = self.class.not_empty?(encrypted_value)
+ self.class.decrypt(attribute, encrypted_value, evaluated_attr_encrypted_options_for(attribute))
+ end
+
+ # Encrypts a value for the attribute specified using options evaluated in the current object's scope
+ #
+ # Example
+ #
+ # class User
+ # attr_accessor :secret_key
+ # attr_encrypted :email, key: :secret_key
+ #
+ # def initialize(secret_key)
+ # self.secret_key = secret_key
+ # end
+ # end
+ #
+ # @user = User.new('some-secret-key')
+ # @user.encrypt(:email, 'test@example.com')
+ def encrypt(attribute, value)
+ encrypted_attributes[attribute.to_sym][:operation] = :encrypting
+ encrypted_attributes[attribute.to_sym][:value_present] = self.class.not_empty?(value)
+ self.class.encrypt(attribute, value, evaluated_attr_encrypted_options_for(attribute))
+ end
+
+ # Copies the class level hash of encrypted attributes with virtual attribute names as keys
+ # and their corresponding options as values to the instance
+ #
+ def encrypted_attributes
+ @encrypted_attributes ||= begin
+ duplicated= {}
+ self.class.encrypted_attributes.map { |key, value| duplicated[key] = value.dup }
+ duplicated
+ end
+ end
+
+ protected
+
+ # Returns attr_encrypted options evaluated in the current object's scope for the attribute specified
+ def evaluated_attr_encrypted_options_for(attribute)
+ evaluated_options = Hash.new
+ attributes = encrypted_attributes[attribute.to_sym]
+ attribute_option_value = attributes[:attribute]
+
+ [:if, :unless, :value_present, :allow_empty_value].each do |option|
+ evaluated_options[option] = evaluate_attr_encrypted_option(attributes[option])
+ end
+
+ evaluated_options[:attribute] = attribute_option_value
+
+ evaluated_options.tap do |options|
+ if options[:if] && !options[:unless] && options[:value_present] || options[:allow_empty_value]
+ (attributes.keys - evaluated_options.keys).each do |option|
+ options[option] = evaluate_attr_encrypted_option(attributes[option])
+ end
+
+ unless options[:mode] == :single_iv_and_salt
+ load_iv_for_attribute(attribute, options)
+ end
+
+ if options[:mode] == :per_attribute_iv_and_salt
+ load_salt_for_attribute(attribute, options)
+ end
+ end
+ end
+ end
+
+ # Evaluates symbol (method reference) or proc (responds to call) options
+ #
+ # If the option is not a symbol or proc then the original option is returned
+ def evaluate_attr_encrypted_option(option)
+ if option.is_a?(Symbol) && respond_to?(option, true)
+ send(option)
+ elsif option.respond_to?(:call)
+ option.call(self)
+ else
+ option
+ end
+ end
+
+ def load_iv_for_attribute(attribute, options)
+ encrypted_attribute_name = options[:attribute]
+ encode_iv = options[:encode_iv]
+ iv = options[:iv] || send("#{encrypted_attribute_name}_iv")
+ if options[:operation] == :encrypting
+ begin
+ iv = generate_iv(options[:algorithm])
+ iv = [iv].pack(encode_iv) if encode_iv
+ send("#{encrypted_attribute_name}_iv=", iv)
+ rescue RuntimeError
+ end
+ end
+ if iv && !iv.empty?
+ iv = iv.unpack(encode_iv).first if encode_iv
+ options[:iv] = iv
+ end
+ end
+
+ def generate_iv(algorithm)
+ algo = OpenSSL::Cipher.new(algorithm)
+ algo.encrypt
+ algo.random_iv
+ end
+
+ def load_salt_for_attribute(attribute, options)
+ encrypted_attribute_name = options[:attribute]
+ encode_salt = options[:encode_salt]
+ salt = options[:salt] || send("#{encrypted_attribute_name}_salt")
+ if options[:operation] == :encrypting
+ salt = SecureRandom.random_bytes
+ salt = prefix_and_encode_salt(salt, encode_salt) if encode_salt
+ send("#{encrypted_attribute_name}_salt=", salt)
+ end
+ if salt && !salt.empty?
+ salt = decode_salt_if_encoded(salt, encode_salt) if encode_salt
+ options[:salt] = salt
+ end
+ end
+
+ def prefix_and_encode_salt(salt, encoding)
+ prefix = '_'
+ prefix + [salt].pack(encoding)
+ end
+
+ def decode_salt_if_encoded(salt, encoding)
+ prefix = '_'
+ salt.slice(0).eql?(prefix) ? salt.slice(1..-1).unpack(encoding).first : salt
+ end
+ end
+
+ protected
+
+ def attribute_instance_methods_as_symbols
+ instance_methods.collect { |method| method.to_sym }
+ end
+
+ def attribute_instance_methods_as_symbols_available?
+ true
+ end
+
+end
+
+
+Dir[File.join(File.dirname(__FILE__), 'attr_encrypted', 'adapters', '*.rb')].each { |adapter| require adapter }
diff --git a/vendor/gems/attr_encrypted/lib/attr_encrypted/adapters/active_record.rb b/vendor/gems/attr_encrypted/lib/attr_encrypted/adapters/active_record.rb
new file mode 100644
index 00000000000..ec8d0208e92
--- /dev/null
+++ b/vendor/gems/attr_encrypted/lib/attr_encrypted/adapters/active_record.rb
@@ -0,0 +1,146 @@
+# frozen_string_literal: true
+
+if defined?(ActiveRecord::Base)
+ module AttrEncrypted
+ module Adapters
+ module ActiveRecord
+ def self.extended(base) # :nodoc:
+ base.class_eval do
+
+ # https://github.com/attr-encrypted/attr_encrypted/issues/68
+ alias_method :reload_without_attr_encrypted, :reload
+ def reload(*args, &block)
+ result = reload_without_attr_encrypted(*args, &block)
+ self.class.encrypted_attributes.keys.each do |attribute_name|
+ instance_variable_set("@#{attribute_name}", nil)
+ end
+ result
+ end
+
+ attr_encrypted_options[:encode] = true
+
+ class << self
+ alias_method :method_missing_without_attr_encrypted, :method_missing
+ alias_method :method_missing, :method_missing_with_attr_encrypted
+ end
+
+ def perform_attribute_assignment(method, new_attributes, *args)
+ return if new_attributes.blank?
+
+ send method, new_attributes.reject { |k, _| self.class.encrypted_attributes.key?(k.to_sym) }, *args
+ send method, new_attributes.reject { |k, _| !self.class.encrypted_attributes.key?(k.to_sym) }, *args
+ end
+ private :perform_attribute_assignment
+
+ if ::ActiveRecord::VERSION::STRING > "3.1"
+ alias_method :assign_attributes_without_attr_encrypted, :assign_attributes
+ def assign_attributes(*args)
+ perform_attribute_assignment :assign_attributes_without_attr_encrypted, *args
+ end
+ end
+
+ alias_method :attributes_without_attr_encrypted=, :attributes=
+ def attributes=(*args)
+ perform_attribute_assignment :attributes_without_attr_encrypted=, *args
+ end
+ end
+ end
+
+ protected
+
+ # <tt>attr_encrypted</tt> method
+ def attr_encrypted(*attrs)
+ super
+ options = attrs.extract_options!
+ attr = attrs.pop
+ attribute attr if ::ActiveRecord::VERSION::STRING >= "5.1.0"
+ options.merge! encrypted_attributes[attr]
+
+ define_method("#{attr}_was") do
+ attribute_was(attr)
+ end
+
+ if ::ActiveRecord::VERSION::STRING >= "4.1"
+ define_method("#{attr}_changed?") do |options = {}|
+ attribute_changed?(attr, **options)
+ end
+ else
+ define_method("#{attr}_changed?") do
+ attribute_changed?(attr)
+ end
+ end
+
+ define_method("#{attr}_change") do
+ attribute_change(attr)
+ end
+
+ define_method("#{attr}_with_dirtiness=") do |value|
+ attribute_will_change!(attr) if value != __send__(attr)
+ __send__("#{attr}_without_dirtiness=", value)
+ end
+
+ alias_method "#{attr}_without_dirtiness=", "#{attr}="
+ alias_method "#{attr}=", "#{attr}_with_dirtiness="
+
+ alias_method "#{attr}_before_type_cast", attr
+ end
+
+ def attribute_instance_methods_as_symbols
+ # We add accessor methods of the db columns to the list of instance
+ # methods returned to let ActiveRecord define the accessor methods
+ # for the db columns
+
+ if connected? && table_exists?
+ columns_hash.keys.inject(super) {|instance_methods, column_name| instance_methods.concat [column_name.to_sym, :"#{column_name}="]}
+ else
+ super
+ end
+ end
+
+ # Prevent attr_encrypted from defining virtual accessors for encryption
+ # data when the code and schema are out of sync. See this issue for more
+ # details: https://github.com/attr-encrypted/attr_encrypted/issues/332
+ def attribute_instance_methods_as_symbols_available?
+ false
+ end
+
+ # Allows you to use dynamic methods like <tt>find_by_email</tt> or <tt>scoped_by_email</tt> for
+ # encrypted attributes
+ #
+ # NOTE: This only works when the <tt>:key</tt> option is specified as a string (see the README)
+ #
+ # This is useful for encrypting fields like email addresses. Your user's email addresses
+ # are encrypted in the database, but you can still look up a user by email for logging in
+ #
+ # Example
+ #
+ # class User < ActiveRecord::Base
+ # attr_encrypted :email, key: 'secret key'
+ # end
+ #
+ # User.find_by_email_and_password('test@example.com', 'testing')
+ # # results in a call to
+ # User.find_by_encrypted_email_and_password('the_encrypted_version_of_test@example.com', 'testing')
+ def method_missing_with_attr_encrypted(method, *args, &block)
+ if match = /^(find|scoped)_(all_by|by)_([_a-zA-Z]\w*)$/.match(method.to_s)
+ attribute_names = match.captures.last.split('_and_')
+ attribute_names.each_with_index do |attribute, index|
+ if attr_encrypted?(attribute) && encrypted_attributes[attribute.to_sym][:mode] == :single_iv_and_salt
+ args[index] = send("encrypt_#{attribute}", args[index])
+ warn "DEPRECATION WARNING: This feature will be removed in the next major release."
+ attribute_names[index] = encrypted_attributes[attribute.to_sym][:attribute]
+ end
+ end
+ method = "#{match.captures[0]}_#{match.captures[1]}_#{attribute_names.join('_and_')}".to_sym
+ end
+ method_missing_without_attr_encrypted(method, *args, &block)
+ end
+ end
+ end
+ end
+
+ ActiveSupport.on_load(:active_record) do
+ extend AttrEncrypted
+ extend AttrEncrypted::Adapters::ActiveRecord
+ end
+end
diff --git a/vendor/gems/attr_encrypted/lib/attr_encrypted/adapters/data_mapper.rb b/vendor/gems/attr_encrypted/lib/attr_encrypted/adapters/data_mapper.rb
new file mode 100644
index 00000000000..03fb5caa457
--- /dev/null
+++ b/vendor/gems/attr_encrypted/lib/attr_encrypted/adapters/data_mapper.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+if defined?(DataMapper)
+ module AttrEncrypted
+ module Adapters
+ module DataMapper
+ def self.extended(base) # :nodoc:
+ class << base
+ alias_method :included_without_attr_encrypted, :included
+ alias_method :included, :included_with_attr_encrypted
+ end
+ end
+
+ def included_with_attr_encrypted(base)
+ included_without_attr_encrypted(base)
+ base.extend AttrEncrypted
+ base.attr_encrypted_options[:encode] = true
+ end
+ end
+ end
+ end
+
+ DataMapper::Resource.extend AttrEncrypted::Adapters::DataMapper
+end
diff --git a/vendor/gems/attr_encrypted/lib/attr_encrypted/adapters/sequel.rb b/vendor/gems/attr_encrypted/lib/attr_encrypted/adapters/sequel.rb
new file mode 100644
index 00000000000..ff14b9a0c8b
--- /dev/null
+++ b/vendor/gems/attr_encrypted/lib/attr_encrypted/adapters/sequel.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+if defined?(Sequel)
+ module AttrEncrypted
+ module Adapters
+ module Sequel
+ def self.extended(base) # :nodoc:
+ base.attr_encrypted_options[:encode] = true
+ end
+ end
+ end
+ end
+
+ Sequel::Model.extend AttrEncrypted
+ Sequel::Model.extend AttrEncrypted::Adapters::Sequel
+end
diff --git a/vendor/gems/attr_encrypted/lib/attr_encrypted/version.rb b/vendor/gems/attr_encrypted/lib/attr_encrypted/version.rb
new file mode 100644
index 00000000000..d97f1532249
--- /dev/null
+++ b/vendor/gems/attr_encrypted/lib/attr_encrypted/version.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module AttrEncrypted
+ # Contains information about this gem's version
+ module Version
+ MAJOR = 3
+ MINOR = 2
+ PATCH = 4
+
+ # Returns a version string by joining <tt>MAJOR</tt>, <tt>MINOR</tt>, and <tt>PATCH</tt> with <tt>'.'</tt>
+ #
+ # Example
+ #
+ # Version.string # '1.0.2'
+ def self.string
+ [MAJOR, MINOR, PATCH].join('.')
+ end
+ end
+end
diff --git a/vendor/gems/attr_encrypted/test/active_record_test.rb b/vendor/gems/attr_encrypted/test/active_record_test.rb
new file mode 100644
index 00000000000..4c903bc3cd8
--- /dev/null
+++ b/vendor/gems/attr_encrypted/test/active_record_test.rb
@@ -0,0 +1,368 @@
+# frozen_string_literal: true
+
+require_relative 'test_helper'
+
+ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
+
+def create_tables
+ ActiveRecord::Schema.define(version: 1) do
+ self.verbose = false
+ create_table :people do |t|
+ t.string :encrypted_email
+ t.string :password
+ t.string :encrypted_credentials
+ t.binary :salt
+ t.binary :key_iv
+ t.string :encrypted_email_salt
+ t.string :encrypted_credentials_salt
+ t.string :encrypted_email_iv
+ t.string :encrypted_credentials_iv
+ end
+ create_table :accounts do |t|
+ t.string :encrypted_password
+ t.string :encrypted_password_iv
+ t.string :encrypted_password_salt
+ t.string :key
+ end
+ create_table :users do |t|
+ t.string :login
+ t.string :encrypted_password
+ t.string :encrypted_password_iv
+ t.boolean :is_admin
+ end
+ create_table :prime_ministers do |t|
+ t.string :encrypted_name
+ t.string :encrypted_name_iv
+ end
+ create_table :addresses do |t|
+ t.binary :encrypted_street
+ t.binary :encrypted_street_iv
+ t.binary :encrypted_zipcode
+ t.string :mode
+ end
+ end
+end
+
+ActiveRecord::MissingAttributeError = ActiveModel::MissingAttributeError unless defined?(ActiveRecord::MissingAttributeError)
+
+if ::ActiveRecord::VERSION::STRING > "4.0"
+ module Rack
+ module Test
+ class UploadedFile; end
+ end
+ end
+
+ require 'action_controller/metal/strong_parameters'
+end
+
+class Person < ActiveRecord::Base
+ self.attr_encrypted_options[:mode] = :per_attribute_iv_and_salt
+ attr_encrypted :email, key: SECRET_KEY
+ attr_encrypted :credentials, key: Proc.new { |user| Encryptor.encrypt(value: user.salt, key: SECRET_KEY, iv: user.key_iv) }, marshal: true
+
+ after_initialize :initialize_salt_and_credentials
+
+ protected
+
+ def initialize_salt_and_credentials
+ self.key_iv ||= SecureRandom.random_bytes(12)
+ self.salt ||= Digest::SHA256.hexdigest((Time.now.to_i * rand(1000)).to_s)[0..15]
+ self.credentials ||= { username: 'example', password: 'test' }
+ end
+end
+
+class PersonWithValidation < Person
+ validates_presence_of :email
+end
+
+class PersonWithProcMode < Person
+ attr_encrypted :email, key: SECRET_KEY, mode: Proc.new { :per_attribute_iv_and_salt }
+ attr_encrypted :credentials, key: SECRET_KEY, mode: Proc.new { :single_iv_and_salt }, insecure_mode: true
+end
+
+class PersonWithInstanceAttribute < Person
+ attr_encrypted :age
+end
+
+class Account < ActiveRecord::Base
+ ACCOUNT_ENCRYPTION_KEY = SecureRandom.urlsafe_base64(24)
+ attr_encrypted :password, key: :password_encryption_key
+
+ def encrypting?(attr)
+ encrypted_attributes[attr][:operation] == :encrypting
+ end
+
+ def password_encryption_key
+ if encrypting?(:password)
+ self.key = ACCOUNT_ENCRYPTION_KEY
+ else
+ self.key
+ end
+ end
+end
+
+class PersonWithSerialization < ActiveRecord::Base
+ self.table_name = 'people'
+ attr_encrypted :email, key: SECRET_KEY
+ serialize :password
+end
+
+class UserWithProtectedAttribute < ActiveRecord::Base
+ self.table_name = 'users'
+ attr_encrypted :password, key: SECRET_KEY
+ attr_protected :is_admin if ::ActiveRecord::VERSION::STRING < "4.0"
+end
+
+class PersonUsingAlias < ActiveRecord::Base
+ self.table_name = 'people'
+ attr_encryptor :email, key: SECRET_KEY
+end
+
+class PrimeMinister < ActiveRecord::Base
+ attr_encrypted :name, marshal: true, key: SECRET_KEY
+end
+
+class Address < ActiveRecord::Base
+ self.attr_encrypted_options[:marshal] = false
+ self.attr_encrypted_options[:encode] = false
+ attr_encrypted :street, encode_iv: false, key: SECRET_KEY
+ attr_encrypted :zipcode, key: SECRET_KEY, mode: Proc.new { |address| address.mode.to_sym }, insecure_mode: true
+end
+
+class ActiveRecordTest < Minitest::Test
+
+ def setup
+ drop_all_tables
+ create_tables
+ end
+
+ def test_should_encrypt_email
+ @person = Person.create(email: 'test@example.com')
+ refute_nil @person.encrypted_email
+ refute_equal @person.email, @person.encrypted_email
+ assert_equal @person.email, Person.first.email
+ end
+
+ def test_should_marshal_and_encrypt_credentials
+ @person = Person.create
+ refute_nil @person.encrypted_credentials
+ refute_equal @person.credentials, @person.encrypted_credentials
+ assert_equal @person.credentials, Person.first.credentials
+ end
+
+ def test_should_encode_by_default
+ assert Person.attr_encrypted_options[:encode]
+ end
+
+ def test_should_validate_presence_of_email
+ @person = PersonWithValidation.new
+ assert !@person.valid?
+ assert !@person.errors[:email].empty? || @person.errors.on(:email)
+ end
+
+ def test_should_encrypt_decrypt_with_iv
+ @person = Person.create(email: 'test@example.com')
+ @person2 = Person.find(@person.id)
+ refute_nil @person2.encrypted_email_iv
+ assert_equal 'test@example.com', @person2.email
+ end
+
+ def test_should_ensure_attributes_can_be_deserialized
+ @person = PersonWithSerialization.new(email: 'test@example.com', password: %w(an array of strings))
+ @person.save
+ assert_equal @person.password, %w(an array of strings)
+ end
+
+ def test_should_create_an_account_regardless_of_arguments_order
+ Account.create!(key: SECRET_KEY, password: "password")
+ Account.create!(password: "password" , key: SECRET_KEY)
+ end
+
+ def test_should_set_attributes_regardless_of_arguments_order
+ # minitest does not implement `assert_nothing_raised` https://github.com/seattlerb/minitest/issues/112
+ Account.new.attributes = { password: "password", key: SECRET_KEY }
+ end
+
+ def test_should_create_changed_predicate
+ person = Person.create!(email: 'test@example.com')
+ refute person.email_changed?
+ person.email = 'test@example.com'
+ refute person.email_changed?
+ person.email = nil
+ assert person.email_changed?
+ person.email = 'test2@example.com'
+ assert person.email_changed?
+ end
+
+ # PENDING - this test is failing because attr_encrypted does not adhere to the
+ # interface contract for ActiveModel::Dirty as of ActiveRecord 6.1:
+ # https://devdocs.io/rails~6.1/activemodel/dirty
+ def pending_test_should_create_was_predicate
+ original_email = 'test@example.com'
+ person = Person.create!(email: original_email)
+ assert_equal original_email, person.email_was
+ person.email = 'test2@example.com'
+ assert_equal original_email, person.email_was
+ old_pm_name = "Winston Churchill"
+ pm = PrimeMinister.create!(name: old_pm_name)
+ assert_equal old_pm_name, pm.name_was
+ old_zipcode = "90210"
+ address = Address.create!(zipcode: old_zipcode, mode: "single_iv_and_salt")
+ assert_equal old_zipcode, address.zipcode_was
+ end
+
+ # PENDING - this test is failing because attr_encrypted does not adhere to the
+ # interface contract for ActiveModel::Dirty as of ActiveRecord 6.1:
+ # https://devdocs.io/rails~6.1/activemodel/dirty
+ def pending_test_attribute_was_works_when_options_for_old_encrypted_value_are_different_than_options_for_new_encrypted_value
+ pw = 'password'
+ crypto_key = SecureRandom.urlsafe_base64(24)
+ old_iv = SecureRandom.random_bytes(12)
+ account = Account.create
+ encrypted_value = Encryptor.encrypt(value: pw, iv: old_iv, key: crypto_key)
+ Account.where(id: account.id).update_all(key: crypto_key, encrypted_password_iv: [old_iv].pack('m'), encrypted_password: [encrypted_value].pack('m'))
+ account = Account.find(account.id)
+ assert_equal pw, account.password
+ account.password = pw.reverse
+ assert_equal pw, account.password_was
+ account.save
+ account.reload
+ assert_equal Account::ACCOUNT_ENCRYPTION_KEY, account.key
+ assert_equal pw.reverse, account.password
+ end
+
+ if ::ActiveRecord::VERSION::STRING > "4.0"
+ def test_should_assign_attributes
+ @user = UserWithProtectedAttribute.new(login: 'login', is_admin: false)
+ @user.attributes = ActionController::Parameters.new(login: 'modified', is_admin: true).permit(:login)
+ assert_equal 'modified', @user.login
+ end
+
+ def test_should_not_assign_protected_attributes
+ @user = UserWithProtectedAttribute.new(login: 'login', is_admin: false)
+ @user.attributes = ActionController::Parameters.new(login: 'modified', is_admin: true).permit(:login)
+ assert !@user.is_admin?
+ end
+
+ def test_should_raise_exception_if_not_permitted
+ @user = UserWithProtectedAttribute.new(login: 'login', is_admin: false)
+ assert_raises ActiveModel::ForbiddenAttributesError do
+ @user.attributes = ActionController::Parameters.new(login: 'modified', is_admin: true)
+ end
+ end
+
+ def test_should_raise_exception_on_init_if_not_permitted
+ assert_raises ActiveModel::ForbiddenAttributesError do
+ @user = UserWithProtectedAttribute.new ActionController::Parameters.new(login: 'modified', is_admin: true)
+ end
+ end
+ else
+ def test_should_assign_attributes
+ @user = UserWithProtectedAttribute.new(login: 'login', is_admin: false)
+ @user.attributes = { login: 'modified', is_admin: true }
+ assert_equal 'modified', @user.login
+ end
+
+ def test_should_not_assign_protected_attributes
+ @user = UserWithProtectedAttribute.new(login: 'login', is_admin: false)
+ @user.attributes = { login: 'modified', is_admin: true }
+ assert !@user.is_admin?
+ end
+
+ def test_should_assign_protected_attributes
+ @user = UserWithProtectedAttribute.new(login: 'login', is_admin: false)
+ if ::ActiveRecord::VERSION::STRING > "3.1"
+ @user.send(:assign_attributes, { login: 'modified', is_admin: true }, without_protection: true)
+ else
+ @user.send(:attributes=, { login: 'modified', is_admin: true }, false)
+ end
+ assert @user.is_admin?
+ end
+ end
+
+ def test_should_allow_assignment_of_nil_attributes
+ @person = Person.new
+ assert_nil(@person.attributes = nil)
+ end
+
+ def test_should_allow_proc_based_mode
+ @person = PersonWithProcMode.create(email: 'test@example.com', credentials: 'password123')
+
+ # Email is :per_attribute_iv_and_salt
+ assert_equal @person.class.encrypted_attributes[:email][:mode].class, Proc
+ assert_equal @person.class.encrypted_attributes[:email][:mode].call, :per_attribute_iv_and_salt
+ refute_nil @person.encrypted_email_salt
+ refute_nil @person.encrypted_email_iv
+
+ # Credentials is :single_iv_and_salt
+ assert_equal @person.class.encrypted_attributes[:credentials][:mode].class, Proc
+ assert_equal @person.class.encrypted_attributes[:credentials][:mode].call, :single_iv_and_salt
+ assert_nil @person.encrypted_credentials_salt
+ assert_nil @person.encrypted_credentials_iv
+ end
+
+ if ::ActiveRecord::VERSION::STRING > "3.1"
+ def test_should_allow_assign_attributes_with_nil
+ @person = Person.new
+ assert_nil(@person.assign_attributes nil)
+ end
+ end
+
+ def test_that_alias_encrypts_column
+ user = PersonUsingAlias.new
+ user.email = 'test@example.com'
+ user.save
+
+ refute_nil user.encrypted_email
+ refute_equal user.email, user.encrypted_email
+ assert_equal user.email, PersonUsingAlias.first.email
+ end
+
+ # See https://github.com/attr-encrypted/attr_encrypted/issues/68
+ def test_should_invalidate_virtual_attributes_on_reload
+ old_pm_name = 'Winston Churchill'
+ new_pm_name = 'Neville Chamberlain'
+ pm = PrimeMinister.create!(name: old_pm_name)
+ assert_equal old_pm_name, pm.name
+ pm.name = new_pm_name
+ assert_equal new_pm_name, pm.name
+
+ result = pm.reload
+ assert_equal pm, result
+ assert_equal old_pm_name, pm.name
+ end
+
+ def test_should_save_encrypted_data_as_binary
+ street = '123 Elm'
+ address = Address.create!(street: street)
+ refute_equal address.encrypted_street, street
+ assert_equal Address.first.street, street
+ end
+
+ def test_should_evaluate_proc_based_mode
+ street = '123 Elm'
+ zipcode = '12345'
+ address = Address.create(street: street, zipcode: zipcode, mode: :single_iv_and_salt)
+ address.reload
+ refute_equal address.encrypted_zipcode, zipcode
+ assert_equal address.zipcode, zipcode
+ end
+
+ # See https://github.com/attr-encrypted/attr_encrypted/issues/332
+ def test_attribute_instance_methods_as_symbols_available_returns_false
+ assert_equal false, ActiveRecord::Base.__send__(:attribute_instance_methods_as_symbols_available?)
+ end
+
+ # See https://github.com/attr-encrypted/attr_encrypted/issues/332
+ def test_does_not_define_virtual_attributes
+ instance = Person.new
+
+ %w[
+ encrypted_age encrypted_age=
+ encrypted_age_iv encrypted_age_iv=
+ encrypted_age_salt encrypted_age_salt=
+ ].each do |method_name|
+ assert_equal false, instance.respond_to?(method_name), "should not define #{method_name}"
+ end
+ end
+end
diff --git a/vendor/gems/attr_encrypted/test/attr_encrypted_test.rb b/vendor/gems/attr_encrypted/test/attr_encrypted_test.rb
new file mode 100644
index 00000000000..84cb130aa50
--- /dev/null
+++ b/vendor/gems/attr_encrypted/test/attr_encrypted_test.rb
@@ -0,0 +1,490 @@
+# frozen_string_literal: true
+
+# encoding: UTF-8
+require_relative 'test_helper'
+
+class SillyEncryptor
+ def self.silly_encrypt(options)
+ (options[:value] + options[:some_arg]).reverse
+ end
+
+ def self.silly_decrypt(options)
+ options[:value].reverse.gsub(/#{options[:some_arg]}$/, '')
+ end
+end
+
+class User
+ extend AttrEncrypted
+ self.attr_encrypted_options[:key] = Proc.new { |user| SECRET_KEY } # default key
+ self.attr_encrypted_options[:mode] = :per_attribute_iv_and_salt
+
+ attr_encrypted :email, :without_encoding, :key => SECRET_KEY
+ attr_encrypted :password, :prefix => 'crypted_', :suffix => '_test'
+ attr_encrypted :ssn, :key => :secret_key, :attribute => 'ssn_encrypted'
+ attr_encrypted :credit_card, :encryptor => SillyEncryptor, :encrypt_method => :silly_encrypt, :decrypt_method => :silly_decrypt, :some_arg => 'test'
+ attr_encrypted :with_encoding, :key => SECRET_KEY, :encode => true
+ attr_encrypted :with_custom_encoding, :key => SECRET_KEY, :encode => 'm'
+ attr_encrypted :with_marshaling, :key => SECRET_KEY, :marshal => true
+ attr_encrypted :with_true_if, :key => SECRET_KEY, :if => true, mode: :per_attribute_iv_and_salt
+ attr_encrypted :with_false_if, :key => SECRET_KEY, :if => false, mode: :per_attribute_iv_and_salt
+ attr_encrypted :with_true_unless, :key => SECRET_KEY, :unless => true, mode: :per_attribute_iv_and_salt
+ attr_encrypted :with_false_unless, :key => SECRET_KEY, :unless => false, mode: :per_attribute_iv_and_salt
+ attr_encrypted :with_if_changed, :key => SECRET_KEY, :if => :should_encrypt
+ attr_encrypted :with_allow_empty_value, key: SECRET_KEY, allow_empty_value: true, marshal: true
+
+ attr_encryptor :aliased, :key => SECRET_KEY
+
+ attr_accessor :salt
+ attr_accessor :should_encrypt
+
+ def initialize(email: nil)
+ self.email = email
+ self.salt = Time.now.to_i.to_s
+ self.should_encrypt = true
+ end
+
+ private
+ def secret_key
+ SECRET_KEY
+ end
+end
+
+class Admin < User
+ attr_encrypted :testing
+end
+
+class SomeOtherClass
+ extend AttrEncrypted
+ def self.call(object)
+ object.class
+ end
+end
+
+class YetAnotherClass
+ extend AttrEncrypted
+ self.attr_encrypted_options[:encode_iv] = false
+
+ attr_encrypted :email, :key => SECRET_KEY
+ attr_encrypted :phone_number, :key => SECRET_KEY, mode: Proc.new { |thing| thing.mode }, encode_iv: Proc.new { |thing| thing.encode_iv }, encode_salt: Proc.new { |thing| thing.encode_salt }
+
+ def initialize(email: nil, encode_iv: 'm', encode_salt: 'm', mode: :per_attribute_iv_and_salt)
+ self.email = email
+ @encode_iv = encode_iv
+ @encode_salt = encode_salt
+ @mode = mode
+ end
+
+ attr_reader :encode_iv, :encode_salt, :mode
+end
+
+class AttrEncryptedTest < Minitest::Test
+ def setup
+ @iv = SecureRandom.random_bytes(12)
+ end
+
+ def test_should_store_email_in_encrypted_attributes
+ assert User.encrypted_attributes.include?(:email)
+ end
+
+ def test_should_not_store_salt_in_encrypted_attributes
+ refute User.encrypted_attributes.include?(:salt)
+ end
+
+ def test_attr_encrypted_should_return_true_for_email
+ assert User.attr_encrypted?('email')
+ end
+
+ def test_attr_encrypted_should_not_use_the_same_attribute_name_for_two_attributes_in_the_same_line
+ refute_equal User.encrypted_attributes[:email][:attribute], User.encrypted_attributes[:without_encoding][:attribute]
+ end
+
+ def test_attr_encrypted_should_return_false_for_salt
+ assert !User.attr_encrypted?('salt')
+ end
+
+ def test_should_generate_an_encrypted_attribute
+ assert User.new.respond_to?(:encrypted_email)
+ end
+
+ def test_should_generate_an_encrypted_attribute_with_a_prefix_and_suffix
+ assert User.new.respond_to?(:crypted_password_test)
+ end
+
+ def test_should_generate_an_encrypted_attribute_with_the_attribute_option
+ assert User.new.respond_to?(:ssn_encrypted)
+ end
+
+ def test_should_not_encrypt_nil_value
+ assert_nil User.encrypt_email(nil, iv: @iv)
+ end
+
+ def test_should_not_encrypt_empty_string_by_default
+ assert_equal '', User.encrypt_email('', iv: @iv)
+ end
+
+ def test_should_encrypt_email
+ refute_nil User.encrypt_email('test@example.com', iv: @iv)
+ refute_equal 'test@example.com', User.encrypt_email('test@example.com', iv: @iv)
+ end
+
+ def test_should_encrypt_email_when_modifying_the_attr_writer
+ @user = User.new
+ assert_nil @user.encrypted_email
+ @user.email = 'test@example.com'
+ refute_nil @user.encrypted_email
+ iv = @user.encrypted_email_iv.unpack('m').first
+ salt = @user.encrypted_email_salt[1..-1].unpack('m').first
+ assert_equal User.encrypt_email('test@example.com', iv: iv, salt: salt), @user.encrypted_email
+ end
+
+ def test_should_not_decrypt_nil_value
+ assert_nil User.decrypt_email(nil, iv: @iv)
+ end
+
+ def test_should_not_decrypt_empty_string
+ assert_equal '', User.decrypt_email('', iv: @iv)
+ end
+
+ def test_should_decrypt_email
+ encrypted_email = User.encrypt_email('test@example.com', iv: @iv)
+ refute_equal 'test@test.com', encrypted_email
+ assert_equal 'test@example.com', User.decrypt_email(encrypted_email, iv: @iv)
+ end
+
+ def test_should_decrypt_email_when_reading
+ @user = User.new
+ assert_nil @user.email
+ options = @user.encrypted_attributes[:email]
+ iv = @user.send(:generate_iv, options[:algorithm])
+ encoded_iv = [iv].pack(options[:encode_iv])
+ salt = SecureRandom.random_bytes
+ encoded_salt = @user.send(:prefix_and_encode_salt, salt, options[:encode_salt])
+ @user.encrypted_email = User.encrypt_email('test@example.com', iv: iv, salt: salt)
+ @user.encrypted_email_iv = encoded_iv
+ @user.encrypted_email_salt = encoded_salt
+ assert_equal 'test@example.com', @user.email
+ end
+
+ def test_should_encrypt_with_encoding
+ assert_equal User.encrypt_with_encoding('test', iv: @iv), [User.encrypt_without_encoding('test', iv: @iv)].pack('m')
+ end
+
+ def test_should_decrypt_with_encoding
+ encrypted = User.encrypt_with_encoding('test', iv: @iv)
+ assert_equal 'test', User.decrypt_with_encoding(encrypted, iv: @iv)
+ assert_equal User.decrypt_with_encoding(encrypted, iv: @iv), User.decrypt_without_encoding(encrypted.unpack('m').first, iv: @iv)
+ end
+
+ def test_should_encrypt_with_custom_encoding
+ assert_equal User.encrypt_with_encoding('test', iv: @iv), [User.encrypt_without_encoding('test', iv: @iv)].pack('m')
+ end
+
+ def test_should_decrypt_with_custom_encoding
+ encrypted = User.encrypt_with_encoding('test', iv: @iv)
+ assert_equal 'test', User.decrypt_with_encoding(encrypted, iv: @iv)
+ assert_equal User.decrypt_with_encoding(encrypted, iv: @iv), User.decrypt_without_encoding(encrypted.unpack('m').first, iv: @iv)
+ end
+
+ def test_should_encrypt_with_marshaling
+ @user = User.new
+ @user.with_marshaling = [1, 2, 3]
+ refute_nil @user.encrypted_with_marshaling
+ end
+
+ def test_should_use_custom_encryptor_and_crypt_method_names_and_arguments
+ assert_equal SillyEncryptor.silly_encrypt(:value => 'testing', :some_arg => 'test'), User.encrypt_credit_card('testing')
+ end
+
+ def test_should_evaluate_a_key_passed_as_a_symbol
+ @user = User.new
+ assert_nil @user.ssn_encrypted
+ @user.ssn = 'testing'
+ refute_nil @user.ssn_encrypted
+ encrypted = Encryptor.encrypt(:value => 'testing', :key => SECRET_KEY, :iv => @user.ssn_encrypted_iv.unpack("m").first, :salt => @user.ssn_encrypted_salt.unpack("m").first )
+ assert_equal encrypted, @user.ssn_encrypted
+ end
+
+ def test_should_evaluate_a_key_passed_as_a_proc
+ @user = User.new
+ assert_nil @user.crypted_password_test
+ @user.password = 'testing'
+ refute_nil @user.crypted_password_test
+ encrypted = Encryptor.encrypt(:value => 'testing', :key => SECRET_KEY, :iv => @user.crypted_password_test_iv.unpack("m").first, :salt => @user.crypted_password_test_salt.unpack("m").first)
+ assert_equal encrypted, @user.crypted_password_test
+ end
+
+ def test_should_use_options_found_in_the_attr_encrypted_options_attribute
+ @user = User.new
+ assert_nil @user.crypted_password_test
+ @user.password = 'testing'
+ refute_nil @user.crypted_password_test
+ encrypted = Encryptor.encrypt(:value => 'testing', :key => SECRET_KEY, :iv => @user.crypted_password_test_iv.unpack("m").first, :salt => @user.crypted_password_test_salt.unpack("m").first)
+ assert_equal encrypted, @user.crypted_password_test
+ end
+
+ def test_should_inherit_encrypted_attributes
+ assert_equal [User.encrypted_attributes.keys, :testing].flatten.collect { |key| key.to_s }.sort, Admin.encrypted_attributes.keys.collect { |key| key.to_s }.sort
+ end
+
+ def test_should_inherit_attr_encrypted_options
+ assert !User.attr_encrypted_options.empty?
+ assert_equal User.attr_encrypted_options, Admin.attr_encrypted_options
+ end
+
+ def test_should_not_inherit_unrelated_attributes
+ assert SomeOtherClass.attr_encrypted_options.empty?
+ assert SomeOtherClass.encrypted_attributes.empty?
+ end
+
+ def test_should_evaluate_a_symbol_option
+ assert_equal SomeOtherClass, SomeOtherClass.new.send(:evaluate_attr_encrypted_option, :class)
+ end
+
+ def test_should_evaluate_a_proc_option
+ assert_equal SomeOtherClass, SomeOtherClass.new.send(:evaluate_attr_encrypted_option, proc { |object| object.class })
+ end
+
+ def test_should_evaluate_a_lambda_option
+ assert_equal SomeOtherClass, SomeOtherClass.new.send(:evaluate_attr_encrypted_option, lambda { |object| object.class })
+ end
+
+ def test_should_evaluate_a_method_option
+ assert_equal SomeOtherClass, SomeOtherClass.new.send(:evaluate_attr_encrypted_option, SomeOtherClass.method(:call))
+ end
+
+ def test_should_return_a_string_option
+ class_string = 'SomeOtherClass'
+ assert_equal class_string, SomeOtherClass.new.send(:evaluate_attr_encrypted_option, class_string)
+ end
+
+ def test_should_encrypt_with_true_if
+ @user = User.new
+ assert_nil @user.encrypted_with_true_if
+ @user.with_true_if = 'testing'
+ refute_nil @user.encrypted_with_true_if
+ encrypted = Encryptor.encrypt(:value => 'testing', :key => SECRET_KEY, :iv => @user.encrypted_with_true_if_iv.unpack("m").first, :salt => @user.encrypted_with_true_if_salt.unpack("m").first)
+ assert_equal encrypted, @user.encrypted_with_true_if
+ end
+
+ def test_should_not_encrypt_with_false_if
+ @user = User.new
+ assert_nil @user.encrypted_with_false_if
+ @user.with_false_if = 'testing'
+ refute_nil @user.encrypted_with_false_if
+ assert_equal 'testing', @user.encrypted_with_false_if
+ end
+
+ def test_should_encrypt_with_false_unless
+ @user = User.new
+ assert_nil @user.encrypted_with_false_unless
+ @user.with_false_unless = 'testing'
+ refute_nil @user.encrypted_with_false_unless
+ encrypted = Encryptor.encrypt(:value => 'testing', :key => SECRET_KEY, :iv => @user.encrypted_with_false_unless_iv.unpack("m").first, :salt => @user.encrypted_with_false_unless_salt.unpack("m").first)
+ assert_equal encrypted, @user.encrypted_with_false_unless
+ end
+
+ def test_should_not_encrypt_with_true_unless
+ @user = User.new
+ assert_nil @user.encrypted_with_true_unless
+ @user.with_true_unless = 'testing'
+ refute_nil @user.encrypted_with_true_unless
+ assert_equal 'testing', @user.encrypted_with_true_unless
+ end
+
+ def test_should_encrypt_empty_with_truthy_allow_empty_value_option
+ @user = User.new
+ assert_nil @user.encrypted_with_allow_empty_value
+ @user.with_allow_empty_value = ''
+ refute_nil @user.encrypted_with_allow_empty_value
+ assert_equal '', @user.with_allow_empty_value
+ @user = User.new
+ @user.with_allow_empty_value = nil
+ refute_nil @user.encrypted_with_allow_empty_value
+ assert_nil @user.with_allow_empty_value
+ end
+
+ def test_should_work_with_aliased_attr_encryptor
+ assert User.encrypted_attributes.include?(:aliased)
+ end
+
+ def test_should_always_reset_options
+ @user = User.new
+ @user.with_if_changed = "encrypt_stuff"
+
+ @user = User.new
+ @user.should_encrypt = false
+ @user.with_if_changed = "not_encrypted_stuff"
+ assert_equal "not_encrypted_stuff", @user.with_if_changed
+ assert_equal "not_encrypted_stuff", @user.encrypted_with_if_changed
+ end
+
+ def test_should_cast_values_as_strings_before_encrypting
+ string_encrypted_email = User.encrypt_email('3', iv: @iv)
+ assert_equal string_encrypted_email, User.encrypt_email(3, iv: @iv)
+ assert_equal '3', User.decrypt_email(string_encrypted_email, iv: @iv)
+ end
+
+ def test_should_create_query_accessor
+ @user = User.new
+ assert !@user.email?
+ @user.email = ''
+ assert !@user.email?
+ @user.email = 'test@example.com'
+ assert @user.email?
+ end
+
+ def test_should_vary_iv_per_attribute
+ @user = User.new
+ @user.email = 'email@example.com'
+ @user.password = 'p455w0rd'
+ refute_equal @user.encrypted_email_iv, @user.crypted_password_test_iv
+ end
+
+ def test_should_generate_iv_per_attribute_by_default
+ thing = YetAnotherClass.new(email: 'thing@thing.com')
+ refute_nil thing.encrypted_email_iv
+ end
+
+ def test_should_vary_iv_per_instance
+ @user1 = User.new
+ @user1.email = 'email@example.com'
+ @user2 = User.new
+ @user2.email = 'email@example.com'
+ refute_equal @user1.encrypted_email_iv, @user2.encrypted_email_iv
+ refute_equal @user1.encrypted_email, @user2.encrypted_email
+ end
+
+ def test_should_vary_salt_per_attribute
+ @user = User.new
+ @user.email = 'email@example.com'
+ @user.password = 'p455w0rd'
+ refute_equal @user.encrypted_email_salt, @user.crypted_password_test_salt
+ end
+
+ def test_should_vary_salt_per_instance
+ @user1 = User.new
+ @user1.email = 'email@example.com'
+ @user2 = User.new
+ @user2.email = 'email@example.com'
+ refute_equal @user1.encrypted_email_salt, @user2.encrypted_email_salt
+ end
+
+ def test_should_not_generate_salt_per_attribute_by_default
+ thing = YetAnotherClass.new(email: 'thing@thing.com')
+ assert_nil thing.encrypted_email_salt
+ end
+
+ def test_should_decrypt_second_record
+ @user1 = User.new
+ @user1.email = 'test@example.com'
+
+ @user2 = User.new
+ @user2.email = 'test@example.com'
+
+ assert_equal 'test@example.com', @user1.decrypt(:email, @user1.encrypted_email)
+ end
+
+ def test_should_specify_the_default_algorithm
+ assert YetAnotherClass.encrypted_attributes[:email][:algorithm]
+ assert_equal YetAnotherClass.encrypted_attributes[:email][:algorithm], 'aes-256-gcm'
+ end
+
+ def test_should_not_encode_iv_when_encode_iv_is_false
+ email = 'thing@thing.com'
+ thing = YetAnotherClass.new(email: email)
+ refute thing.encrypted_email_iv =~ base64_encoding_regex
+ assert_equal thing.email, email
+ end
+
+ def test_should_base64_encode_iv_by_default
+ phone_number = '555-555-5555'
+ thing = YetAnotherClass.new
+ thing.phone_number = phone_number
+ assert thing.encrypted_phone_number_iv =~ base64_encoding_regex
+ assert_equal thing.phone_number, phone_number
+ end
+
+ def test_should_generate_unique_iv_for_every_encrypt_operation
+ user = User.new
+ user.email = 'initial_value@test.com'
+ original_iv = user.encrypted_email_iv
+ user.email = 'revised_value@test.com'
+ refute_equal original_iv, user.encrypted_email_iv
+ end
+
+ def test_should_not_generate_iv_for_attribute_when_if_option_is_false
+ user = User.new
+ user.with_false_if = 'derp'
+ assert_nil user.encrypted_with_false_if_iv
+ end
+
+ def test_should_generate_iv_for_attribute_when_if_option_is_true
+ user = User.new
+ user.with_true_if = 'derp'
+ refute_nil user.encrypted_with_true_if_iv
+
+ user.with_true_if = Object.new
+ refute_nil user.encrypted_with_true_if_iv
+ end
+
+ def test_should_not_generate_salt_for_attribute_when_if_option_is_false
+ user = User.new
+ user.with_false_if = 'derp'
+ assert_nil user.encrypted_with_false_if_salt
+ end
+
+ def test_should_generate_salt_for_attribute_when_if_option_is_true
+ user = User.new
+ user.with_true_if = 'derp'
+ refute_nil user.encrypted_with_true_if_salt
+ end
+
+ def test_should_generate_iv_for_attribute_when_unless_option_is_false
+ user = User.new
+ user.with_false_unless = 'derp'
+ refute_nil user.encrypted_with_false_unless_iv
+ end
+
+ def test_should_not_generate_iv_for_attribute_when_unless_option_is_true
+ user = User.new
+ user.with_true_unless = 'derp'
+ assert_nil user.encrypted_with_true_unless_iv
+ end
+
+ def test_should_generate_salt_for_attribute_when_unless_option_is_false
+ user = User.new
+ user.with_false_unless = 'derp'
+ refute_nil user.encrypted_with_false_unless_salt
+ end
+
+ def test_should_not_generate_salt_for_attribute_when_unless_option_is_true
+ user = User.new
+ user.with_true_unless = 'derp'
+ assert_nil user.encrypted_with_true_unless_salt
+ end
+
+ def test_should_not_by_default_generate_iv_when_attribute_is_empty
+ user = User.new
+ user.with_true_if = nil
+ assert_nil user.encrypted_with_true_if_iv
+ end
+
+ def test_encrypted_attributes_state_is_not_shared
+ user = User.new
+ user.ssn = '123456789'
+
+ another_user = User.new
+
+ assert_equal :encrypting, user.encrypted_attributes[:ssn][:operation]
+ assert_nil another_user.encrypted_attributes[:ssn][:operation]
+ end
+
+ def test_should_not_by_default_generate_key_when_attribute_is_empty
+ user = User.new
+ calls = 0
+ user.stub(:secret_key, lambda { calls += 1; SECRET_KEY }) do
+ user.ssn
+ end
+ assert_equal 0, calls
+ end
+end
diff --git a/vendor/gems/attr_encrypted/test/compatibility_test.rb b/vendor/gems/attr_encrypted/test/compatibility_test.rb
new file mode 100644
index 00000000000..7585895e16e
--- /dev/null
+++ b/vendor/gems/attr_encrypted/test/compatibility_test.rb
@@ -0,0 +1,109 @@
+# frozen_string_literal: true
+
+# -*- encoding: utf-8 -*-
+require_relative 'test_helper'
+
+# Test to ensure that existing representations in database do not break on
+# migrating to new versions of this gem. This ensures that future versions of
+# this gem will retain backwards compatibility with data generated by earlier
+# versions.
+class CompatibilityTest < Minitest::Test
+ class NonmarshallingPet < ActiveRecord::Base
+ PET_NICKNAME_SALT = Digest::SHA256.hexdigest('my-really-really-secret-pet-nickname-salt')
+ PET_NICKNAME_KEY = 'my-really-really-secret-pet-nickname-key'
+ PET_BIRTHDATE_SALT = Digest::SHA256.hexdigest('my-really-really-secret-pet-birthdate-salt')
+ PET_BIRTHDATE_KEY = 'my-really-really-secret-pet-birthdate-key'
+
+ self.attr_encrypted_options[:mode] = :per_attribute_iv_and_salt
+ self.attr_encrypted_options[:algorithm] = 'aes-256-cbc'
+ self.attr_encrypted_options[:insecure_mode] = true
+
+ attr_encrypted :nickname,
+ :key => proc { Encryptor.encrypt(:value => PET_NICKNAME_SALT, :key => PET_NICKNAME_KEY, insecure_mode: true, algorithm: 'aes-256-cbc') }
+ attr_encrypted :birthdate,
+ :key => proc { Encryptor.encrypt(:value => PET_BIRTHDATE_SALT, :key => PET_BIRTHDATE_KEY, insecure_mode: true, algorithm: 'aes-256-cbc') }
+ end
+
+ class MarshallingPet < ActiveRecord::Base
+ PET_NICKNAME_SALT = Digest::SHA256.hexdigest('my-really-really-secret-pet-nickname-salt')
+ PET_NICKNAME_KEY = 'my-really-really-secret-pet-nickname-key'
+ PET_BIRTHDATE_SALT = Digest::SHA256.hexdigest('my-really-really-secret-pet-birthdate-salt')
+ PET_BIRTHDATE_KEY = 'my-really-really-secret-pet-birthdate-key'
+
+ self.attr_encrypted_options[:mode] = :per_attribute_iv_and_salt
+ self.attr_encrypted_options[:algorithm] = 'aes-256-cbc'
+ self.attr_encrypted_options[:insecure_mode] = true
+
+ attr_encrypted :nickname,
+ :key => proc { Encryptor.encrypt(:value => PET_NICKNAME_SALT, :key => PET_NICKNAME_KEY, insecure_mode: true, algorithm: 'aes-256-cbc') },
+ :marshal => true
+ attr_encrypted :birthdate,
+ :key => proc { Encryptor.encrypt(:value => PET_BIRTHDATE_SALT, :key => PET_BIRTHDATE_KEY, insecure_mode: true, algorithm: 'aes-256-cbc') },
+ :marshal => true
+ end
+
+ def setup
+ drop_all_tables
+ create_tables
+ end
+
+ def test_nonmarshalling_backwards_compatibility
+ pet = NonmarshallingPet.create!(
+ :name => 'Fido',
+ :encrypted_nickname => 'E4lJTxFG/EfkfPg5MpnriQ==',
+ :encrypted_nickname_iv => 'z4Q8deE4h7f6S8NNZcbPNg==',
+ :encrypted_nickname_salt => 'adcd833001a873db',
+ :encrypted_birthdate => '6uKEAiFVdJw+N5El+U6Gow==',
+ :encrypted_birthdate_iv => 'zxtc1XPssL4s2HwA69nORQ==',
+ :encrypted_birthdate_salt => '4f879270045eaad7'
+ )
+
+ assert_equal 'Fido', pet.name
+ assert_equal 'Fido the Dog', pet.nickname
+ assert_equal '2011-07-09', pet.birthdate
+ end
+
+ def test_marshalling_backwards_compatibility
+ pet = MarshallingPet.create!(
+ :name => 'Fido',
+ :encrypted_nickname => 'EsQScJYkPw80vVGvKWkE37Px99HHpXPFjoEPTNa4rbs=',
+ :encrypted_nickname_iv => 'fNq1OZcGvty4KfcvGTcFSw==',
+ :encrypted_nickname_salt => '733b459b7d34c217',
+ :encrypted_birthdate => '+VUlKQGfNWkOgCwI4hv+3qlGIwh9h6cJ/ranJlaxvU+xxQdL3H3cOzTcI2rkYkdR',
+ :encrypted_birthdate_iv => 'Ka+zF/SwEYZKwVa24lvFfA==',
+ :encrypted_birthdate_salt => 'd5e892d5bbd81566'
+ )
+
+ assert_equal 'Fido', pet.name
+ assert_equal 'Mummy\'s little helper', pet.nickname
+
+ assert_equal Date.new(2011, 7, 9), pet.birthdate
+ end
+
+ private
+
+ def create_tables
+ ActiveRecord::Schema.define(:version => 1) do
+ create_table :nonmarshalling_pets do |t|
+ t.string :name
+ t.string :encrypted_nickname
+ t.string :encrypted_nickname_iv
+ t.string :encrypted_nickname_salt
+ t.string :encrypted_birthdate
+ t.string :encrypted_birthdate_iv
+ t.string :encrypted_birthdate_salt
+ end
+ create_table :marshalling_pets do |t|
+ t.string :name
+ t.string :encrypted_nickname
+ t.string :encrypted_nickname_iv
+ t.string :encrypted_nickname_salt
+ t.string :encrypted_birthdate
+ t.string :encrypted_birthdate_iv
+ t.string :encrypted_birthdate_salt
+ end
+ end
+ end
+end
+
+ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => ':memory:'
diff --git a/vendor/gems/attr_encrypted/test/data_mapper_test.rb b/vendor/gems/attr_encrypted/test/data_mapper_test.rb
new file mode 100644
index 00000000000..3fb284a6ca4
--- /dev/null
+++ b/vendor/gems/attr_encrypted/test/data_mapper_test.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+require_relative 'test_helper'
+
+DataMapper.setup(:default, 'sqlite3::memory:')
+
+class Client
+ include DataMapper::Resource
+
+ property :id, Serial
+ property :encrypted_email, String
+ property :encrypted_email_iv, String
+ property :encrypted_email_salt, String
+
+ property :encrypted_credentials, Text
+ property :encrypted_credentials_iv, Text
+ property :encrypted_credentials_salt, Text
+
+ self.attr_encrypted_options[:mode] = :per_attribute_iv_and_salt
+
+ attr_encrypted :email, :key => SECRET_KEY
+ attr_encrypted :credentials, :key => SECRET_KEY, :marshal => true
+
+ def initialize(attrs = {})
+ super attrs
+ self.credentials ||= { :username => 'example', :password => 'test' }
+ end
+end
+
+DataMapper.auto_migrate!
+
+class DataMapperTest < Minitest::Test
+
+ def setup
+ Client.all.each(&:destroy)
+ end
+
+ def test_should_encrypt_email
+ @client = Client.new :email => 'test@example.com'
+ assert @client.save
+ refute_nil @client.encrypted_email
+ refute_equal @client.email, @client.encrypted_email
+ assert_equal @client.email, Client.first.email
+ end
+
+ def test_should_marshal_and_encrypt_credentials
+ @client = Client.new
+ assert @client.save
+ refute_nil @client.encrypted_credentials
+ refute_equal @client.credentials, @client.encrypted_credentials
+ assert_equal @client.credentials, Client.first.credentials
+ assert Client.first.credentials.is_a?(Hash)
+ end
+
+ def test_should_encode_by_default
+ assert Client.attr_encrypted_options[:encode]
+ end
+
+end
diff --git a/vendor/gems/attr_encrypted/test/legacy_active_record_test.rb b/vendor/gems/attr_encrypted/test/legacy_active_record_test.rb
new file mode 100644
index 00000000000..802318570fa
--- /dev/null
+++ b/vendor/gems/attr_encrypted/test/legacy_active_record_test.rb
@@ -0,0 +1,120 @@
+# frozen_string_literal: true
+
+# -*- encoding: utf-8 -*-
+require_relative 'test_helper'
+
+ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => ':memory:'
+
+def create_people_table
+ ActiveRecord::Schema.define(:version => 1) do
+ create_table :legacy_people do |t|
+ t.string :encrypted_email
+ t.string :password
+ t.string :encrypted_credentials
+ t.string :salt
+ end
+ end
+end
+
+# The table needs to exist before defining the class
+create_people_table
+
+ActiveRecord::MissingAttributeError = ActiveModel::MissingAttributeError unless defined?(ActiveRecord::MissingAttributeError)
+
+class LegacyPerson < ActiveRecord::Base
+ self.attr_encrypted_options[:insecure_mode] = true
+ self.attr_encrypted_options[:algorithm] = 'aes-256-cbc'
+ self.attr_encrypted_options[:mode] = :single_iv_and_salt
+
+ attr_encrypted :email, :key => 'a secret key'
+ attr_encrypted :credentials, :key => Proc.new { |user| Encryptor.encrypt(:value => user.salt, :key => 'some private key', insecure_mode: true, algorithm: 'aes-256-cbc') }, :marshal => true
+
+ ActiveSupport::Deprecation.silenced = true
+ def after_initialize; end
+ ActiveSupport::Deprecation.silenced = false
+
+ after_initialize :initialize_salt_and_credentials
+
+ protected
+
+ def initialize_salt_and_credentials
+ self.salt ||= Digest::SHA256.hexdigest((Time.now.to_i * rand(5)).to_s)
+ self.credentials ||= { :username => 'example', :password => 'test' }
+ rescue ActiveRecord::MissingAttributeError
+ end
+end
+
+class LegacyPersonWithValidation < LegacyPerson
+ validates_presence_of :email
+ validates_uniqueness_of :encrypted_email
+end
+
+class LegacyActiveRecordTest < Minitest::Test
+
+ def setup
+ drop_all_tables
+ create_people_table
+ end
+
+ def test_should_decrypt_with_correct_encoding
+ if defined?(Encoding)
+ @person = LegacyPerson.create :email => 'test@example.com'
+ assert_equal 'UTF-8', LegacyPerson.first.email.encoding.name
+ end
+ end
+
+ def test_should_encrypt_email
+ @person = LegacyPerson.create :email => 'test@example.com'
+ refute_nil @person.encrypted_email
+ refute_equal @person.email, @person.encrypted_email
+ assert_equal @person.email, LegacyPerson.first.email
+ end
+
+ def test_should_marshal_and_encrypt_credentials
+ @person = LegacyPerson.create
+ refute_nil @person.encrypted_credentials
+ refute_equal @person.credentials, @person.encrypted_credentials
+ assert_equal @person.credentials, LegacyPerson.first.credentials
+ end
+
+ def test_should_find_by_email
+ @person = LegacyPerson.create(:email => 'test@example.com')
+ assert_equal @person, LegacyPerson.find_by_email('test@example.com')
+ end
+
+ def test_should_find_by_email_and_password
+ LegacyPerson.create(:email => 'test@example.com', :password => 'invalid')
+ @person = LegacyPerson.create(:email => 'test@example.com', :password => 'test')
+ assert_equal @person, LegacyPerson.find_by_email_and_password('test@example.com', 'test')
+ end
+
+ def test_should_scope_by_email
+ @person = LegacyPerson.create(:email => 'test@example.com')
+ assert_equal @person, LegacyPerson.scoped_by_email('test@example.com').first rescue NoMethodError
+ end
+
+ def test_should_scope_by_email_and_password
+ LegacyPerson.create(:email => 'test@example.com', :password => 'invalid')
+ @person = LegacyPerson.create(:email => 'test@example.com', :password => 'test')
+ assert_equal @person, LegacyPerson.scoped_by_email_and_password('test@example.com', 'test').first rescue NoMethodError
+ end
+
+ def test_should_encode_by_default
+ assert LegacyPerson.attr_encrypted_options[:encode]
+ end
+
+ def test_should_validate_presence_of_email
+ @person = LegacyPersonWithValidation.new
+ assert !@person.valid?
+ assert !@person.errors[:email].empty? || @person.errors.on(:email)
+ end
+
+ def test_should_validate_uniqueness_of_email
+ @person = LegacyPersonWithValidation.new :email => 'test@example.com'
+ assert @person.save
+ @person2 = LegacyPersonWithValidation.new :email => @person.email
+ assert !@person2.valid?
+ assert !@person2.errors[:encrypted_email].empty? || @person2.errors.on(:encrypted_email)
+ end
+
+end
diff --git a/vendor/gems/attr_encrypted/test/legacy_attr_encrypted_test.rb b/vendor/gems/attr_encrypted/test/legacy_attr_encrypted_test.rb
new file mode 100644
index 00000000000..875086d2351
--- /dev/null
+++ b/vendor/gems/attr_encrypted/test/legacy_attr_encrypted_test.rb
@@ -0,0 +1,300 @@
+# frozen_string_literal: true
+
+# -*- encoding: utf-8 -*-
+require_relative 'test_helper'
+
+class LegacySillyEncryptor
+ def self.silly_encrypt(options)
+ (options[:value] + options[:some_arg]).reverse
+ end
+
+ def self.silly_decrypt(options)
+ options[:value].reverse.gsub(/#{options[:some_arg]}$/, '')
+ end
+end
+
+class LegacyUser
+ extend AttrEncrypted
+ self.attr_encrypted_options[:key] = Proc.new { |user| user.class.to_s } # default key
+ self.attr_encrypted_options[:insecure_mode] = true
+ self.attr_encrypted_options[:algorithm] = 'aes-256-cbc'
+ self.attr_encrypted_options[:mode] = :single_iv_and_salt
+
+ attr_encrypted :email, :without_encoding, :key => 'secret key'
+ attr_encrypted :password, :prefix => 'crypted_', :suffix => '_test'
+ attr_encrypted :ssn, :key => :salt, :attribute => 'ssn_encrypted'
+ attr_encrypted :credit_card, :encryptor => LegacySillyEncryptor, :encrypt_method => :silly_encrypt, :decrypt_method => :silly_decrypt, :some_arg => 'test'
+ attr_encrypted :with_encoding, :key => 'secret key', :encode => true
+ attr_encrypted :with_custom_encoding, :key => 'secret key', :encode => 'm'
+ attr_encrypted :with_marshaling, :key => 'secret key', :marshal => true
+ attr_encrypted :with_true_if, :key => 'secret key', :if => true
+ attr_encrypted :with_false_if, :key => 'secret key', :if => false
+ attr_encrypted :with_true_unless, :key => 'secret key', :unless => true
+ attr_encrypted :with_false_unless, :key => 'secret key', :unless => false
+ attr_encrypted :with_if_changed, :key => 'secret key', :if => :should_encrypt
+
+ attr_encryptor :aliased, :key => 'secret_key'
+
+ attr_accessor :salt
+ attr_accessor :should_encrypt
+
+ def initialize
+ self.salt = Time.now.to_i.to_s
+ self.should_encrypt = true
+ end
+end
+
+class LegacyAdmin < LegacyUser
+ attr_encrypted :testing
+end
+
+class LegacySomeOtherClass
+ extend AttrEncrypted
+ def self.call(object)
+ object.class
+ end
+end
+
+class LegacyAttrEncryptedTest < Minitest::Test
+
+ def test_should_store_email_in_encrypted_attributes
+ assert LegacyUser.encrypted_attributes.include?(:email)
+ end
+
+ def test_should_not_store_salt_in_encrypted_attributes
+ assert !LegacyUser.encrypted_attributes.include?(:salt)
+ end
+
+ def test_attr_encrypted_should_return_true_for_email
+ assert LegacyUser.attr_encrypted?('email')
+ end
+
+ def test_attr_encrypted_should_not_use_the_same_attribute_name_for_two_attributes_in_the_same_line
+ refute_equal LegacyUser.encrypted_attributes[:email][:attribute], LegacyUser.encrypted_attributes[:without_encoding][:attribute]
+ end
+
+ def test_attr_encrypted_should_return_false_for_salt
+ assert !LegacyUser.attr_encrypted?('salt')
+ end
+
+ def test_should_generate_an_encrypted_attribute
+ assert LegacyUser.new.respond_to?(:encrypted_email)
+ end
+
+ def test_should_generate_an_encrypted_attribute_with_a_prefix_and_suffix
+ assert LegacyUser.new.respond_to?(:crypted_password_test)
+ end
+
+ def test_should_generate_an_encrypted_attribute_with_the_attribute_option
+ assert LegacyUser.new.respond_to?(:ssn_encrypted)
+ end
+
+ def test_should_not_encrypt_nil_value
+ assert_nil LegacyUser.encrypt_email(nil)
+ end
+
+ def test_should_not_encrypt_empty_string
+ assert_equal '', LegacyUser.encrypt_email('')
+ end
+
+ def test_should_encrypt_email
+ refute_nil LegacyUser.encrypt_email('test@example.com')
+ refute_equal 'test@example.com', LegacyUser.encrypt_email('test@example.com')
+ end
+
+ def test_should_encrypt_email_when_modifying_the_attr_writer
+ @user = LegacyUser.new
+ assert_nil @user.encrypted_email
+ @user.email = 'test@example.com'
+ refute_nil @user.encrypted_email
+ assert_equal LegacyUser.encrypt_email('test@example.com'), @user.encrypted_email
+ end
+
+ def test_should_not_decrypt_nil_value
+ assert_nil LegacyUser.decrypt_email(nil)
+ end
+
+ def test_should_not_decrypt_empty_string
+ assert_equal '', LegacyUser.decrypt_email('')
+ end
+
+ def test_should_decrypt_email
+ encrypted_email = LegacyUser.encrypt_email('test@example.com')
+ refute_equal 'test@test.com', encrypted_email
+ assert_equal 'test@example.com', LegacyUser.decrypt_email(encrypted_email)
+ end
+
+ def test_should_decrypt_email_when_reading
+ @user = LegacyUser.new
+ assert_nil @user.email
+ @user.encrypted_email = LegacyUser.encrypt_email('test@example.com')
+ assert_equal 'test@example.com', @user.email
+ end
+
+ def test_should_encrypt_with_encoding
+ assert_equal LegacyUser.encrypt_with_encoding('test'), [LegacyUser.encrypt_without_encoding('test')].pack('m')
+ end
+
+ def test_should_decrypt_with_encoding
+ encrypted = LegacyUser.encrypt_with_encoding('test')
+ assert_equal 'test', LegacyUser.decrypt_with_encoding(encrypted)
+ assert_equal LegacyUser.decrypt_with_encoding(encrypted), LegacyUser.decrypt_without_encoding(encrypted.unpack('m').first)
+ end
+
+ def test_should_decrypt_utf8_with_encoding
+ encrypted = LegacyUser.encrypt_with_encoding("test\xC2\xA0utf-8\xC2\xA0text")
+ assert_equal "test\xC2\xA0utf-8\xC2\xA0text", LegacyUser.decrypt_with_encoding(encrypted)
+ assert_equal LegacyUser.decrypt_with_encoding(encrypted), LegacyUser.decrypt_without_encoding(encrypted.unpack('m').first)
+ end
+
+ def test_should_encrypt_with_custom_encoding
+ assert_equal LegacyUser.encrypt_with_custom_encoding('test'), [LegacyUser.encrypt_without_encoding('test')].pack('m')
+ end
+
+ def test_should_decrypt_with_custom_encoding
+ encrypted = LegacyUser.encrypt_with_custom_encoding('test')
+ assert_equal 'test', LegacyUser.decrypt_with_custom_encoding(encrypted)
+ assert_equal LegacyUser.decrypt_with_custom_encoding(encrypted), LegacyUser.decrypt_without_encoding(encrypted.unpack('m').first)
+ end
+
+ def test_should_encrypt_with_marshaling
+ @user = LegacyUser.new
+ @user.with_marshaling = [1, 2, 3]
+ refute_nil @user.encrypted_with_marshaling
+ assert_equal LegacyUser.encrypt_with_marshaling([1, 2, 3]), @user.encrypted_with_marshaling
+ end
+
+ def test_should_decrypt_with_marshaling
+ encrypted = LegacyUser.encrypt_with_marshaling([1, 2, 3])
+ @user = LegacyUser.new
+ assert_nil @user.with_marshaling
+ @user.encrypted_with_marshaling = encrypted
+ assert_equal [1, 2, 3], @user.with_marshaling
+ end
+
+ def test_should_use_custom_encryptor_and_crypt_method_names_and_arguments
+ assert_equal LegacySillyEncryptor.silly_encrypt(:value => 'testing', :some_arg => 'test'), LegacyUser.encrypt_credit_card('testing')
+ end
+
+ def test_should_evaluate_a_key_passed_as_a_symbol
+ @user = LegacyUser.new
+ assert_nil @user.ssn_encrypted
+ @user.ssn = 'testing'
+ refute_nil @user.ssn_encrypted
+ assert_equal Encryptor.encrypt(:value => 'testing', :key => @user.salt, insecure_mode: true, algorithm: 'aes-256-cbc'), @user.ssn_encrypted
+ end
+
+ def test_should_evaluate_a_key_passed_as_a_proc
+ @user = LegacyUser.new
+ assert_nil @user.crypted_password_test
+ @user.password = 'testing'
+ refute_nil @user.crypted_password_test
+ assert_equal Encryptor.encrypt(:value => 'testing', :key => 'LegacyUser', insecure_mode: true, algorithm: 'aes-256-cbc'), @user.crypted_password_test
+ end
+
+ def test_should_use_options_found_in_the_attr_encrypted_options_attribute
+ @user = LegacyUser.new
+ assert_nil @user.crypted_password_test
+ @user.password = 'testing'
+ refute_nil @user.crypted_password_test
+ assert_equal Encryptor.encrypt(:value => 'testing', :key => 'LegacyUser', insecure_mode: true, algorithm: 'aes-256-cbc'), @user.crypted_password_test
+ end
+
+ def test_should_inherit_encrypted_attributes
+ assert_equal [LegacyUser.encrypted_attributes.keys, :testing].flatten.collect { |key| key.to_s }.sort, LegacyAdmin.encrypted_attributes.keys.collect { |key| key.to_s }.sort
+ end
+
+ def test_should_inherit_attr_encrypted_options
+ assert !LegacyUser.attr_encrypted_options.empty?
+ assert_equal LegacyUser.attr_encrypted_options, LegacyAdmin.attr_encrypted_options
+ end
+
+ def test_should_not_inherit_unrelated_attributes
+ assert LegacySomeOtherClass.attr_encrypted_options.empty?
+ assert LegacySomeOtherClass.encrypted_attributes.empty?
+ end
+
+ def test_should_evaluate_a_symbol_option
+ assert_equal LegacySomeOtherClass, LegacySomeOtherClass.new.send(:evaluate_attr_encrypted_option, :class)
+ end
+
+ def test_should_evaluate_a_proc_option
+ assert_equal LegacySomeOtherClass, LegacySomeOtherClass.new.send(:evaluate_attr_encrypted_option, proc { |object| object.class })
+ end
+
+ def test_should_evaluate_a_lambda_option
+ assert_equal LegacySomeOtherClass, LegacySomeOtherClass.new.send(:evaluate_attr_encrypted_option, lambda { |object| object.class })
+ end
+
+ def test_should_evaluate_a_method_option
+ assert_equal LegacySomeOtherClass, LegacySomeOtherClass.new.send(:evaluate_attr_encrypted_option, LegacySomeOtherClass.method(:call))
+ end
+
+ def test_should_return_a_string_option
+ class_string = 'LegacySomeOtherClass'
+ assert_equal class_string, LegacySomeOtherClass.new.send(:evaluate_attr_encrypted_option, class_string)
+ end
+
+ def test_should_encrypt_with_true_if
+ @user = LegacyUser.new
+ assert_nil @user.encrypted_with_true_if
+ @user.with_true_if = 'testing'
+ refute_nil @user.encrypted_with_true_if
+ assert_equal Encryptor.encrypt(:value => 'testing', :key => 'secret key', insecure_mode: true, algorithm: 'aes-256-cbc'), @user.encrypted_with_true_if
+ end
+
+ def test_should_not_encrypt_with_false_if
+ @user = LegacyUser.new
+ assert_nil @user.encrypted_with_false_if
+ @user.with_false_if = 'testing'
+ refute_nil @user.encrypted_with_false_if
+ assert_equal 'testing', @user.encrypted_with_false_if
+ end
+
+ def test_should_encrypt_with_false_unless
+ @user = LegacyUser.new
+ assert_nil @user.encrypted_with_false_unless
+ @user.with_false_unless = 'testing'
+ refute_nil @user.encrypted_with_false_unless
+ assert_equal Encryptor.encrypt(:value => 'testing', :key => 'secret key', insecure_mode: true, algorithm: 'aes-256-cbc'), @user.encrypted_with_false_unless
+ end
+
+ def test_should_not_encrypt_with_true_unless
+ @user = LegacyUser.new
+ assert_nil @user.encrypted_with_true_unless
+ @user.with_true_unless = 'testing'
+ refute_nil @user.encrypted_with_true_unless
+ assert_equal 'testing', @user.encrypted_with_true_unless
+ end
+
+ def test_should_work_with_aliased_attr_encryptor
+ assert LegacyUser.encrypted_attributes.include?(:aliased)
+ end
+
+ def test_should_always_reset_options
+ @user = LegacyUser.new
+ @user.with_if_changed = "encrypt_stuff"
+
+ @user = LegacyUser.new
+ @user.should_encrypt = false
+ @user.with_if_changed = "not_encrypted_stuff"
+ assert_equal "not_encrypted_stuff", @user.with_if_changed
+ assert_equal "not_encrypted_stuff", @user.encrypted_with_if_changed
+ end
+
+ def test_should_cast_values_as_strings_before_encrypting
+ string_encrypted_email = LegacyUser.encrypt_email('3')
+ assert_equal string_encrypted_email, LegacyUser.encrypt_email(3)
+ assert_equal '3', LegacyUser.decrypt_email(string_encrypted_email)
+ end
+
+ def test_should_create_query_accessor
+ @user = LegacyUser.new
+ assert !@user.email?
+ @user.email = ''
+ assert !@user.email?
+ @user.email = 'test@example.com'
+ assert @user.email?
+ end
+
+end
diff --git a/vendor/gems/attr_encrypted/test/legacy_compatibility_test.rb b/vendor/gems/attr_encrypted/test/legacy_compatibility_test.rb
new file mode 100644
index 00000000000..68985816f94
--- /dev/null
+++ b/vendor/gems/attr_encrypted/test/legacy_compatibility_test.rb
@@ -0,0 +1,95 @@
+# frozen_string_literal: true
+
+# -*- encoding: utf-8 -*-
+require_relative 'test_helper'
+
+# Test to ensure that existing representations in database do not break on
+# migrating to new versions of this gem. This ensures that future versions of
+# this gem will retain backwards compatibility with data generated by earlier
+# versions.
+class LegacyCompatibilityTest < Minitest::Test
+ class LegacyNonmarshallingPet < ActiveRecord::Base
+ PET_NICKNAME_SALT = Digest::SHA256.hexdigest('my-really-really-secret-pet-nickname-salt')
+ PET_NICKNAME_KEY = 'my-really-really-secret-pet-nickname-key'
+ PET_BIRTHDATE_SALT = Digest::SHA256.hexdigest('my-really-really-secret-pet-birthdate-salt')
+ PET_BIRTHDATE_KEY = 'my-really-really-secret-pet-birthdate-key'
+
+ self.attr_encrypted_options[:insecure_mode] = true
+ self.attr_encrypted_options[:algorithm] = 'aes-256-cbc'
+ self.attr_encrypted_options[:mode] = :single_iv_and_salt
+
+ attr_encrypted :nickname,
+ :key => proc { Encryptor.encrypt(:value => PET_NICKNAME_SALT, :key => PET_NICKNAME_KEY, insecure_mode: true, algorithm: 'aes-256-cbc') }
+ attr_encrypted :birthdate,
+ :key => proc { Encryptor.encrypt(:value => PET_BIRTHDATE_SALT, :key => PET_BIRTHDATE_KEY, insecure_mode: true, algorithm: 'aes-256-cbc') }
+ end
+
+ class LegacyMarshallingPet < ActiveRecord::Base
+ PET_NICKNAME_SALT = Digest::SHA256.hexdigest('my-really-really-secret-pet-nickname-salt')
+ PET_NICKNAME_KEY = 'my-really-really-secret-pet-nickname-key'
+ PET_BIRTHDATE_SALT = Digest::SHA256.hexdigest('my-really-really-secret-pet-birthdate-salt')
+ PET_BIRTHDATE_KEY = 'my-really-really-secret-pet-birthdate-key'
+
+ self.attr_encrypted_options[:insecure_mode] = true
+ self.attr_encrypted_options[:algorithm] = 'aes-256-cbc'
+ self.attr_encrypted_options[:mode] = :single_iv_and_salt
+
+ attr_encrypted :nickname,
+ :key => proc { Encryptor.encrypt(:value => PET_NICKNAME_SALT, :key => PET_NICKNAME_KEY, insecure_mode: true, algorithm: 'aes-256-cbc') },
+ :marshal => true
+ attr_encrypted :birthdate,
+ :key => proc { Encryptor.encrypt(:value => PET_BIRTHDATE_SALT, :key => PET_BIRTHDATE_KEY, insecure_mode: true, algorithm: 'aes-256-cbc') },
+ :marshal => true
+ end
+
+ def setup
+ drop_all_tables
+ create_tables
+ end
+
+ def test_nonmarshalling_backwards_compatibility
+ pet = LegacyNonmarshallingPet.create!(
+ :name => 'Fido',
+ :encrypted_nickname => 'uSUB6KGzta87yxesyVc3DA==',
+ :encrypted_birthdate => 'I3d691B2PtFXLx15kO067g=='
+ )
+
+ assert_equal 'Fido', pet.name
+ assert_equal 'Fido the Dog', pet.nickname
+ assert_equal '2011-07-09', pet.birthdate
+ end
+
+ def test_marshalling_backwards_compatibility
+ pet = LegacyMarshallingPet.create!(
+ :name => 'Fido',
+ :encrypted_nickname => '7RwoT64in4H+fGVBPYtRcN0K4RtriIy1EP4nDojUa8g=',
+ :encrypted_birthdate => 'bSp9sJhXQSp2QlNZHiujtcK4lRVBE8HQhn1y7moQ63bGJR20hvRSZ73ePAmm+wc5'
+ )
+
+ assert_equal 'Fido', pet.name
+ assert_equal 'Mummy\'s little helper', pet.nickname
+
+ assert_equal Date.new(2011, 7, 9), pet.birthdate
+ end
+
+ private
+
+ def create_tables
+ ActiveRecord::Schema.define(:version => 1) do
+ create_table :legacy_nonmarshalling_pets do |t|
+ t.string :name
+ t.string :encrypted_nickname
+ t.string :encrypted_birthdate
+ t.string :salt
+ end
+ create_table :legacy_marshalling_pets do |t|
+ t.string :name
+ t.string :encrypted_nickname
+ t.string :encrypted_birthdate
+ t.string :salt
+ end
+ end
+ end
+end
+
+ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => ':memory:'
diff --git a/vendor/gems/attr_encrypted/test/legacy_data_mapper_test.rb b/vendor/gems/attr_encrypted/test/legacy_data_mapper_test.rb
new file mode 100644
index 00000000000..03916dd9728
--- /dev/null
+++ b/vendor/gems/attr_encrypted/test/legacy_data_mapper_test.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+require_relative 'test_helper'
+
+DataMapper.setup(:default, 'sqlite3::memory:')
+
+class LegacyClient
+ include DataMapper::Resource
+ self.attr_encrypted_options[:insecure_mode] = true
+ self.attr_encrypted_options[:algorithm] = 'aes-256-cbc'
+ self.attr_encrypted_options[:mode] = :single_iv_and_salt
+
+ property :id, Serial
+ property :encrypted_email, String
+ property :encrypted_credentials, Text
+ property :salt, String
+
+ attr_encrypted :email, :key => 'a secret key', mode: :single_iv_and_salt
+ attr_encrypted :credentials, :key => Proc.new { |client| Encryptor.encrypt(:value => client.salt, :key => 'some private key', insecure_mode: true, algorithm: 'aes-256-cbc') }, :marshal => true, mode: :single_iv_and_salt
+
+ def initialize(attrs = {})
+ super attrs
+ self.salt ||= Digest::SHA1.hexdigest((Time.now.to_i * rand(5)).to_s)
+ self.credentials ||= { :username => 'example', :password => 'test' }
+ end
+end
+
+DataMapper.auto_migrate!
+
+class LegacyDataMapperTest < Minitest::Test
+
+ def setup
+ LegacyClient.all.each(&:destroy)
+ end
+
+ def test_should_encrypt_email
+ @client = LegacyClient.new :email => 'test@example.com'
+ assert @client.save
+ refute_nil @client.encrypted_email
+ refute_equal @client.email, @client.encrypted_email
+ assert_equal @client.email, LegacyClient.first.email
+ end
+
+ def test_should_marshal_and_encrypt_credentials
+ @client = LegacyClient.new
+ assert @client.save
+ refute_nil @client.encrypted_credentials
+ refute_equal @client.credentials, @client.encrypted_credentials
+ assert_equal @client.credentials, LegacyClient.first.credentials
+ assert LegacyClient.first.credentials.is_a?(Hash)
+ end
+
+ def test_should_encode_by_default
+ assert LegacyClient.attr_encrypted_options[:encode]
+ end
+
+end
diff --git a/vendor/gems/attr_encrypted/test/legacy_sequel_test.rb b/vendor/gems/attr_encrypted/test/legacy_sequel_test.rb
new file mode 100644
index 00000000000..fd46301e25e
--- /dev/null
+++ b/vendor/gems/attr_encrypted/test/legacy_sequel_test.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+require_relative 'test_helper'
+
+DB.create_table :legacy_humans do
+ primary_key :id
+ column :encrypted_email, :string
+ column :password, :string
+ column :encrypted_credentials, :string
+ column :salt, :string
+end
+
+class LegacyHuman < Sequel::Model(:legacy_humans)
+ self.attr_encrypted_options[:insecure_mode] = true
+ self.attr_encrypted_options[:algorithm] = 'aes-256-cbc'
+ self.attr_encrypted_options[:mode] = :single_iv_and_salt
+
+ attr_encrypted :email, :key => 'a secret key', mode: :single_iv_and_salt
+ attr_encrypted :credentials, :key => Proc.new { |human| Encryptor.encrypt(:value => human.salt, :key => 'some private key', insecure_mode: true, algorithm: 'aes-256-cbc') }, :marshal => true, mode: :single_iv_and_salt
+
+ def after_initialize(attrs = {})
+ self.salt ||= Digest::SHA1.hexdigest((Time.now.to_i * rand(5)).to_s)
+ self.credentials ||= { :username => 'example', :password => 'test' }
+ end
+end
+
+class LegacySequelTest < Minitest::Test
+
+ def setup
+ LegacyHuman.all.each(&:destroy)
+ end
+
+ def test_should_encrypt_email
+ @human = LegacyHuman.new :email => 'test@example.com'
+ assert @human.save
+ refute_nil @human.encrypted_email
+ refute_equal @human.email, @human.encrypted_email
+ assert_equal @human.email, LegacyHuman.first.email
+ end
+
+ def test_should_marshal_and_encrypt_credentials
+ @human = LegacyHuman.new
+ assert @human.save
+ refute_nil @human.encrypted_credentials
+ refute_equal @human.credentials, @human.encrypted_credentials
+ assert_equal @human.credentials, LegacyHuman.first.credentials
+ assert LegacyHuman.first.credentials.is_a?(Hash)
+ end
+
+ def test_should_encode_by_default
+ assert LegacyHuman.attr_encrypted_options[:encode]
+ end
+
+end
diff --git a/vendor/gems/attr_encrypted/test/run.sh b/vendor/gems/attr_encrypted/test/run.sh
new file mode 100755
index 00000000000..7e9b777eebf
--- /dev/null
+++ b/vendor/gems/attr_encrypted/test/run.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/env sh -e
+
+for RUBY in 1.9.3 2.0.0 2.1 2.2
+do
+ for RAILS in 2.3.8 3.0.0 3.1.0 3.2.0 4.0.0 4.1.0 4.2.0
+ do
+ if [[ $RUBY -gt 1.9.3 && $RAILS -lt 4.0.0 ]]; then
+ continue
+ fi
+ RBENV_VERSION=$RUBY ACTIVERECORD=$RAILS bundle && bundle exec rake
+ done
+done
diff --git a/vendor/gems/attr_encrypted/test/sequel_test.rb b/vendor/gems/attr_encrypted/test/sequel_test.rb
new file mode 100644
index 00000000000..1df520319b1
--- /dev/null
+++ b/vendor/gems/attr_encrypted/test/sequel_test.rb
@@ -0,0 +1,55 @@
+# frozen_string_literal: true
+
+require_relative 'test_helper'
+
+DB.create_table :humans do
+ primary_key :id
+ column :encrypted_email, :string
+ column :encrypted_email_salt, String
+ column :encrypted_email_iv, :string
+ column :password, :string
+ column :encrypted_credentials, :string
+ column :encrypted_credentials_iv, :string
+ column :encrypted_credentials_salt, String
+end
+
+class Human < Sequel::Model(:humans)
+ self.attr_encrypted_options[:mode] = :per_attribute_iv_and_salt
+
+ attr_encrypted :email, :key => SECRET_KEY
+ attr_encrypted :credentials, :key => SECRET_KEY, :marshal => true
+
+ def after_initialize(attrs = {})
+ self.credentials ||= { :username => 'example', :password => 'test' }
+ end
+end
+
+class SequelTest < Minitest::Test
+
+ def setup
+ Human.all.each(&:destroy)
+ end
+
+ def test_should_encrypt_email
+ @human = Human.new :email => 'test@example.com'
+ assert @human.save
+ refute_nil @human.encrypted_email
+ refute_equal @human.email, @human.encrypted_email
+ assert_equal @human.email, Human.first.email
+ end
+
+ def test_should_marshal_and_encrypt_credentials
+
+ @human = Human.new :credentials => { :username => 'example', :password => 'test' }
+ assert @human.save
+ refute_nil @human.encrypted_credentials
+ refute_equal @human.credentials, @human.encrypted_credentials
+ assert_equal @human.credentials, Human.first.credentials
+ assert Human.first.credentials.is_a?(Hash)
+ end
+
+ def test_should_encode_by_default
+ assert Human.attr_encrypted_options[:encode]
+ end
+
+end
diff --git a/vendor/gems/attr_encrypted/test/test_helper.rb b/vendor/gems/attr_encrypted/test/test_helper.rb
new file mode 100644
index 00000000000..091e81bb9d7
--- /dev/null
+++ b/vendor/gems/attr_encrypted/test/test_helper.rb
@@ -0,0 +1,63 @@
+# frozen_string_literal: true
+
+require 'simplecov'
+require 'simplecov-rcov'
+require "codeclimate-test-reporter"
+
+SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(
+ [
+ SimpleCov::Formatter::HTMLFormatter,
+ SimpleCov::Formatter::RcovFormatter,
+ CodeClimate::TestReporter::Formatter
+ ]
+)
+
+# Disabling for now since there are issues with Ruby 3 support.
+# See https://gitlab.com/gitlab-org/ruby/gems/attr_encrypted/-/merge_requests/1
+#
+# SimpleCov.start do
+# add_filter 'test'
+# end
+
+CodeClimate::TestReporter.start
+
+require 'minitest/autorun'
+
+# Rails 4.0.x pins to an old minitest
+unless defined?(MiniTest::Test)
+ MiniTest::Test = MiniTest::Unit::TestCase
+end
+
+require 'active_record'
+require 'data_mapper'
+require 'digest/sha2'
+require 'sequel'
+ActiveSupport::Deprecation.behavior = :raise
+
+$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
+$:.unshift(File.dirname(__FILE__))
+require 'attr_encrypted'
+
+DB = if defined?(RUBY_ENGINE) && RUBY_ENGINE.to_sym == :jruby
+ Sequel.jdbc('jdbc:sqlite::memory:')
+else
+ Sequel.sqlite
+end
+
+# The :after_initialize hook was removed in Sequel 4.0
+# and had been deprecated for a while before that:
+# http://sequel.rubyforge.org/rdoc-plugins/classes/Sequel/Plugins/AfterInitialize.html
+# This plugin re-enables it.
+Sequel::Model.plugin :after_initialize
+
+SECRET_KEY = SecureRandom.random_bytes(32)
+
+def base64_encoding_regex
+ /^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{4})$/
+end
+
+def drop_all_tables
+ connection = ActiveRecord::Base.connection
+ tables = (ActiveRecord::VERSION::MAJOR >= 5 ? connection.data_sources : connection.tables)
+ tables.each { |table| ActiveRecord::Base.connection.drop_table(table) }
+end
diff --git a/vendor/gems/bundler-checksum/test/project_with_checksum_lock/Gemfile.checksum b/vendor/gems/bundler-checksum/test/project_with_checksum_lock/Gemfile.checksum
index cf70611c97a..1670ac8e688 100644
--- a/vendor/gems/bundler-checksum/test/project_with_checksum_lock/Gemfile.checksum
+++ b/vendor/gems/bundler-checksum/test/project_with_checksum_lock/Gemfile.checksum
@@ -21,6 +21,7 @@
{"name":"marcel","version":"1.0.2","platform":"ruby","checksum":"a013b677ef46cbcb49fd5c59b3d35803d2ee04dd75d8bfdc43533fc5a31f7e4e"},
{"name":"method_source","version":"1.0.0","platform":"ruby","checksum":"d779455a2b5666a079ce58577bfad8534f571af7cec8107f4dce328f0981dede"},
{"name":"mini_mime","version":"1.1.2","platform":"ruby","checksum":"a54aec0cc7438a03a850adb00daca2bdb60747f839e28186994df057cea87151"},
+{"name":"mini_portile2","version":"2.8.0","platform":"ruby","checksum":"1e06b286ff19b73cfc9193cb3dd2bd80416f8262443564b25b23baea74a05765"},
{"name":"minitest","version":"5.16.2","platform":"ruby","checksum":"c1be0c6b57fab451faa08e74ffa71e7d6a259b90f4bacb881c7f4808ec8b4991"},
{"name":"nio4r","version":"2.5.8","platform":"java","checksum":"b2b1800f6bf7ce4b797ca8b639ad278a99c9c904fb087a91d944f38e4bd71401"},
{"name":"nio4r","version":"2.5.8","platform":"ruby","checksum":"3becb4ad95ab8ac0a9bd2e1b16466869402be62848082bf6329ae9091f276676"},
diff --git a/vendor/gems/bundler-checksum/test/project_with_checksum_lock/Gemfile.lock b/vendor/gems/bundler-checksum/test/project_with_checksum_lock/Gemfile.lock
index 8f4bb5fa40d..d633184e300 100644
--- a/vendor/gems/bundler-checksum/test/project_with_checksum_lock/Gemfile.lock
+++ b/vendor/gems/bundler-checksum/test/project_with_checksum_lock/Gemfile.lock
@@ -76,11 +76,11 @@ GEM
marcel (1.0.2)
method_source (1.0.0)
mini_mime (1.1.2)
+ mini_portile2 (2.8.0)
minitest (5.16.2)
nio4r (2.5.8)
- nokogiri (1.13.8-arm64-darwin)
- racc (~> 1.4)
- nokogiri (1.13.8-x86_64-linux)
+ nokogiri (1.13.8)
+ mini_portile2 (~> 2.8.0)
racc (~> 1.4)
racc (1.6.0)
rack (2.2.4)
@@ -129,11 +129,10 @@ GEM
zeitwerk (2.6.0)
PLATFORMS
- arm64-darwin-21
- x86_64-linux
+ ruby
DEPENDENCIES
rails (~> 6.1.6.1)
BUNDLED WITH
- 2.3.19
+ 2.3.22
diff --git a/vendor/gems/devise-pbkdf2-encryptable/Gemfile.lock b/vendor/gems/devise-pbkdf2-encryptable/Gemfile.lock
index ce0cb0c1025..617ee7d91f5 100644
--- a/vendor/gems/devise-pbkdf2-encryptable/Gemfile.lock
+++ b/vendor/gems/devise-pbkdf2-encryptable/Gemfile.lock
@@ -3,6 +3,7 @@ PATH
specs:
devise-pbkdf2-encryptable (0.0.0)
devise (~> 4.0)
+ devise-two-factor (~> 4.0)
GEM
remote: https://rubygems.org/
@@ -28,6 +29,8 @@ GEM
minitest (>= 5.1)
tzinfo (~> 2.0)
zeitwerk (~> 2.3)
+ attr_encrypted (3.1.0)
+ encryptor (~> 3.0.0)
bcrypt (3.1.18)
builder (3.2.4)
concurrent-ruby (1.1.10)
@@ -38,7 +41,14 @@ GEM
railties (>= 4.1.0)
responders
warden (~> 1.2.3)
+ devise-two-factor (4.0.2)
+ activesupport (< 7.1)
+ attr_encrypted (>= 1.3, < 4, != 2)
+ devise (~> 4.0)
+ railties (< 7.1)
+ rotp (~> 6.0)
diff-lcs (1.5.0)
+ encryptor (3.0.0)
erubi (1.10.0)
i18n (1.10.0)
concurrent-ruby (~> 1.0)
@@ -71,6 +81,7 @@ GEM
responders (3.0.1)
actionpack (>= 5.0)
railties (>= 5.0)
+ rotp (6.2.0)
rspec (3.10.0)
rspec-core (~> 3.10.0)
rspec-expectations (~> 3.10.0)
diff --git a/vendor/gems/devise-pbkdf2-encryptable/devise-pbkdf2-encryptable.gemspec b/vendor/gems/devise-pbkdf2-encryptable/devise-pbkdf2-encryptable.gemspec
index e507633c0bf..9c7e3dd5af5 100644
--- a/vendor/gems/devise-pbkdf2-encryptable/devise-pbkdf2-encryptable.gemspec
+++ b/vendor/gems/devise-pbkdf2-encryptable/devise-pbkdf2-encryptable.gemspec
@@ -19,6 +19,7 @@ Gem::Specification.new do |spec|
spec.version = '0.0.0'
spec.add_runtime_dependency 'devise', '~> 4.0'
+ spec.add_runtime_dependency 'devise-two-factor', '~> 4.0'
spec.add_development_dependency 'activemodel', '~> 6.1', '< 8'
spec.add_development_dependency 'rspec', '~> 3.10.0'
diff --git a/vendor/gems/devise-pbkdf2-encryptable/lib/devise-pbkdf2-encryptable.rb b/vendor/gems/devise-pbkdf2-encryptable/lib/devise-pbkdf2-encryptable.rb
index 4db9b82052f..3f635fde280 100644
--- a/vendor/gems/devise-pbkdf2-encryptable/lib/devise-pbkdf2-encryptable.rb
+++ b/vendor/gems/devise-pbkdf2-encryptable/lib/devise-pbkdf2-encryptable.rb
@@ -1 +1,2 @@
require "devise/pbkdf2_encryptable/encryptable"
+require "devise/models/two_factor_backupable_pbkdf2"
diff --git a/vendor/gems/devise-pbkdf2-encryptable/lib/devise/models/two_factor_backupable_pbkdf2.rb b/vendor/gems/devise-pbkdf2-encryptable/lib/devise/models/two_factor_backupable_pbkdf2.rb
new file mode 100644
index 00000000000..eef906f5377
--- /dev/null
+++ b/vendor/gems/devise-pbkdf2-encryptable/lib/devise/models/two_factor_backupable_pbkdf2.rb
@@ -0,0 +1,58 @@
+module Devise
+ module Models
+ module TwoFactorBackupablePbkdf2
+ extend ActiveSupport::Concern
+
+ # 1) Invalidates all existing backup codes
+ # 2) Generates otp_number_of_backup_codes backup codes
+ # 3) Stores the hashed backup codes in the database
+ # 4) Returns a plaintext array of the generated backup codes
+ #
+ def generate_otp_backup_codes_pbkdf2!
+ codes = []
+ number_of_codes = self.class.otp_number_of_backup_codes
+ code_length = self.class.otp_backup_code_length
+
+ number_of_codes.times do
+ codes << SecureRandom.hex(code_length / 2) # Hexstring has length 2*n
+ end
+
+ hashed_codes = codes.map do |code|
+ Devise::Pbkdf2Encryptable::Encryptors::Pbkdf2Sha512.digest(
+ code,
+ Devise::Pbkdf2Encryptable::Encryptors::Pbkdf2Sha512::STRETCHES,
+ Devise.friendly_token[0, 16])
+ end
+
+ self.otp_backup_codes = hashed_codes
+
+ codes
+ end
+
+ # Returns true and invalidates the given code if that code is a valid
+ # backup code.
+ #
+ def invalidate_otp_backup_code_pdkdf2!(code)
+ codes = self.otp_backup_codes || []
+
+ codes.each do |backup_code|
+ next unless Devise::Pbkdf2Encryptable::Encryptors::Pbkdf2Sha512.compare(backup_code, code)
+
+ codes.delete(backup_code)
+ self.otp_backup_codes = codes
+ return true
+ end
+
+ false
+ end
+
+ protected
+
+ module ClassMethods
+ Devise::Models.config(self, :otp_backup_code_length,
+ :otp_number_of_backup_codes,
+ :pepper)
+ end
+ end
+ end
+end
diff --git a/vendor/gems/devise-pbkdf2-encryptable/spec/lib/models/two_factor_backupable_pbkdf2_spec.rb b/vendor/gems/devise-pbkdf2-encryptable/spec/lib/models/two_factor_backupable_pbkdf2_spec.rb
new file mode 100644
index 00000000000..bc1e6c47109
--- /dev/null
+++ b/vendor/gems/devise-pbkdf2-encryptable/spec/lib/models/two_factor_backupable_pbkdf2_spec.rb
@@ -0,0 +1,100 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require 'active_model'
+
+class TwoFactorBackupablePbkdf2Double
+ extend ::ActiveModel::Callbacks
+ include ::ActiveModel::Validations::Callbacks
+ extend ::Devise::Models
+
+ # stub out the ::ActiveRecord::Encryption::EncryptableRecord API
+ attr_accessor :otp_secret
+ def self.encrypts(*attrs)
+ nil
+ end
+
+ define_model_callbacks :update
+
+ devise :two_factor_backupable, otp_number_of_backup_codes: 10
+ devise :two_factor_backupable_pbkdf2
+
+ attr_accessor :otp_backup_codes
+end
+
+module Gitlab
+ class FIPS
+ def enabled?
+ end
+ end
+end
+
+RSpec.describe ::Devise::Models::TwoFactorBackupablePbkdf2 do
+ subject { TwoFactorBackupablePbkdf2Double.new }
+
+ describe '#generate_otp_backup_codes_pbkdf2!' do
+ context 'with no existing recovery codes' do
+ before do
+ @plaintext_codes = subject.generate_otp_backup_codes_pbkdf2!
+ end
+
+ it 'generates the correct number of new recovery codes' do
+ expect(subject.otp_backup_codes.length).to eq(subject.class.otp_number_of_backup_codes)
+ end
+
+ it 'generates recovery codes of the correct length' do
+ @plaintext_codes.each do |code|
+ expect(code.length).to eq(subject.class.otp_backup_code_length)
+ end
+ end
+
+ it 'generates distinct recovery codes' do
+ expect(@plaintext_codes.uniq).to contain_exactly(*@plaintext_codes)
+ end
+
+ it 'stores the codes as pbkdf2 hashes' do
+ subject.otp_backup_codes.each do |code|
+ expect(code.start_with?("$pbkdf2-sha512$")).to be_truthy
+ end
+ end
+ end
+ end
+
+ describe '#invalidate_otp_backup_code_pdkdf2!' do
+ before do
+ @plaintext_codes = subject.generate_otp_backup_codes_pbkdf2!
+ end
+
+ context 'given an invalid recovery code' do
+ it 'returns false' do
+ expect(subject.invalidate_otp_backup_code_pdkdf2!('password')).to be false
+ end
+ end
+
+ context 'given a valid recovery code' do
+ it 'returns true' do
+ @plaintext_codes.each do |code|
+ expect(subject.invalidate_otp_backup_code_pdkdf2!(code)).to be true
+ end
+ end
+
+ it 'invalidates that recovery code' do
+ code = @plaintext_codes.sample
+
+ subject.invalidate_otp_backup_code_pdkdf2!(code)
+ expect(subject.invalidate_otp_backup_code_pdkdf2!(code)).to be false
+ end
+
+ it 'does not invalidate the other recovery codes' do
+ code = @plaintext_codes.sample
+ subject.invalidate_otp_backup_code_pdkdf2!(code)
+
+ @plaintext_codes.delete(code)
+
+ @plaintext_codes.each do |code|
+ expect(subject.invalidate_otp_backup_code_pdkdf2!(code)).to be true
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/gems/devise-pbkdf2-encryptable/spec/spec_helper.rb b/vendor/gems/devise-pbkdf2-encryptable/spec/spec_helper.rb
index ced0cf6fdab..932fd3b8452 100644
--- a/vendor/gems/devise-pbkdf2-encryptable/spec/spec_helper.rb
+++ b/vendor/gems/devise-pbkdf2-encryptable/spec/spec_helper.rb
@@ -1,4 +1,6 @@
# frozen_string_literal: true
require 'devise'
+require 'devise-two-factor'
require 'devise/pbkdf2_encryptable/encryptable'
+require 'devise/models/two_factor_backupable_pbkdf2'
diff --git a/vendor/gems/microsoft_graph_mailer/README.md b/vendor/gems/microsoft_graph_mailer/README.md
index dd9dfecfc56..c87748ffdf9 100644
--- a/vendor/gems/microsoft_graph_mailer/README.md
+++ b/vendor/gems/microsoft_graph_mailer/README.md
@@ -1,6 +1,6 @@
# microsoft_graph_mailer
-This gem allows delivery of emails using [Microsoft Graph API](https://docs.microsoft.com/en-us/graph/api/user-sendmail) with [OAuth 2.0 client credentials flow](https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow).
+This gem allows delivery of emails using [Microsoft Graph API](https://learn.microsoft.com/en-us/graph/api/user-sendmail) with [OAuth 2.0 client credentials flow](https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow).
## The reason for this gem
@@ -30,7 +30,7 @@ gem install microsoft_graph_mailer
To use the Microsoft Graph API to send mails, you will
need to create an application in the Azure Active Directory. See the
-[Microsoft instructions](https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app) for more details:
+[Microsoft instructions](https://learn.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app) for more details:
1. Sign in to the [Azure portal](https://portal.azure.com).
1. Search for and select `Azure Active Directory`.
diff --git a/vendor/gems/omniauth-gitlab/Gemfile.lock b/vendor/gems/omniauth-gitlab/Gemfile.lock
index b59ba59b95b..9f69874e124 100644
--- a/vendor/gems/omniauth-gitlab/Gemfile.lock
+++ b/vendor/gems/omniauth-gitlab/Gemfile.lock
@@ -3,7 +3,7 @@ PATH
specs:
omniauth-gitlab (4.0.0)
omniauth (~> 2.0)
- omniauth-oauth2 (~> 1.7.1)
+ omniauth-oauth2 (~> 1.8)
GEM
remote: https://rubygems.org/
@@ -28,9 +28,9 @@ GEM
hashie (>= 3.4.6)
rack (>= 2.2.3)
rack-protection
- omniauth-oauth2 (1.7.3)
+ omniauth-oauth2 (1.8.0)
oauth2 (>= 1.4, < 3)
- omniauth (>= 1.9, < 3)
+ omniauth (~> 2.0)
rack (2.2.4)
rack-protection (2.2.2)
rack
diff --git a/vendor/gems/omniauth-gitlab/omniauth-gitlab.gemspec b/vendor/gems/omniauth-gitlab/omniauth-gitlab.gemspec
index ca4b8d904f0..82f7c55ee02 100644
--- a/vendor/gems/omniauth-gitlab/omniauth-gitlab.gemspec
+++ b/vendor/gems/omniauth-gitlab/omniauth-gitlab.gemspec
@@ -17,7 +17,7 @@ Gem::Specification.new do |gem|
gem.require_paths = ['lib']
gem.add_dependency 'omniauth', '~> 2.0'
- gem.add_dependency 'omniauth-oauth2', '~> 1.7.1'
+ gem.add_dependency 'omniauth-oauth2', '~> 1.8'
gem.add_development_dependency 'rspec', '~> 3.1'
gem.add_development_dependency 'rspec-its', '~> 1.0'
gem.add_development_dependency 'simplecov'
diff --git a/vendor/gems/omniauth-google-oauth2/CHANGELOG.md b/vendor/gems/omniauth-google-oauth2/CHANGELOG.md
deleted file mode 100644
index 5b252048fd6..00000000000
--- a/vendor/gems/omniauth-google-oauth2/CHANGELOG.md
+++ /dev/null
@@ -1,354 +0,0 @@
-# Changelog
-All notable changes to this project will be documented in this file.
-
-## 1.0.1 - 2022-03-10
-
-### Added
-- Output granted scopes in credentials block of the auth hash.
-- Migrated to GitHub actions.
-
-### Deprecated
-- Nothing.
-
-### Removed
-- Nothing.
-
-### Fixed
-- Overriding the `redirect_uri` via params or JSON request body.
-
-## 1.0.0 - 2021-03-14
-
-### Added
-- Support for Omniauth 2.x!
-
-### Deprecated
-- Nothing.
-
-### Removed
-- Support for Omniauth 1.x.
-
-### Fixed
-- Nothing.
-
-## 0.8.2 - 2021-03-14
-
-### Added
-- Constrains the version to Omniauth 1.x.
-
-### Deprecated
-- Nothing.
-
-### Removed
-- Nothing.
-
-### Fixed
-- Nothing.
-
-## 0.8.1 - 2020-12-12
-
-### Added
-- Support reading the access token from a json request body.
-
-### Deprecated
-- Nothing.
-
-### Removed
-- No longer verify the iat claim for JWT.
-
-### Fixed
-- A few minor issues with .rubocop.yml.
-- Issues with image resizing code when the image came with size information from Google.
-
-## 0.8.0 - 2019-08-21
-
-### Added
-- Updated omniauth-oauth2 to v1.6.0 for security fixes.
-
-### Deprecated
-- Nothing.
-
-### Removed
-- Ruby 2.1 support.
-
-### Fixed
-- Nothing.
-
-## 0.7.0 - 2019-06-03
-
-### Added
-- Ensure `info[:email]` is always verified, and include `unverified_email`
-
-### Deprecated
-- Nothing.
-
-### Removed
-- Nothing.
-
-### Fixed
-- Nothing.
-
-## 0.6.1 - 2019-03-07
-
-### Added
-- Return `email` and `email_verified` keys in response.
-
-### Deprecated
-- Nothing.
-
-### Removed
-- Nothing.
-
-### Fixed
-- Nothing.
-
-## 0.6.0 - 2018-12-28
-
-### Added
-- Support for JWT 2.x.
-
-### Deprecated
-- Nothing.
-
-### Removed
-- Support for JWT 1.x.
-- Support for `raw_friend_info` and `raw_image_info`.
-- Stop using Google+ API endpoints.
-
-### Fixed
-- Nothing.
-
-## 0.5.4 - 2018-12-07
-
-### Added
-- New recommended endpoints for Google OAuth.
-
-### Deprecated
-- Nothing.
-
-### Removed
-- Nothing.
-
-### Fixed
-- Nothing.
-
-## 0.5.3 - 2018-01-25
-
-### Added
-- Added support for the JWT 2.x gem.
-- Now fully qualifies the `JWT` class to prevent conflicts with the `Omniauth::JWT` strategy.
-
-### Deprecated
-- Nothing.
-
-### Removed
-- Removed the `multijson` dependency.
-- Support for versions of `omniauth-oauth2` < 1.5.
-
-### Fixed
-- Nothing.
-
-## 0.5.2 - 2017-07-30
-
-### Added
-- Nothing.
-
-### Deprecated
-- Nothing.
-
-### Removed
-- New `authorize_url` and `token_url` endpoints are reverted until JWT 2.0 ships.
-
-### Fixed
-- Nothing.
-
-## 0.5.1 - 2017-07-19
-
-### Added
-- *Breaking* JWT iss verification can be enabled/disabled with the `verify_iss` flag - see the README for more details.
-- Authorize options now includes `device_id` and `device_name` for private ip ranges.
-
-### Deprecated
-- Nothing.
-
-### Removed
-- Nothing.
-
-### Fixed
-- Updated `authorize_url` and `token_url` to new endpoints.
-
-## 0.5.0 - 2017-05-29
-
-### Added
-- Rubocop checks to specs.
-- Defaulted dev environment to ruby 2.3.4.
-
-### Deprecated
-- Nothing.
-
-### Removed
-- Testing support for older versions of ruby not supported by OmniAuth 1.5.
-- Key `[:urls]['Google']` no longer exists, it has been renamed to `[:urls][:google]`.
-
-### Fixed
-- Updated all code to rubocop conventions. This includes the Ruby 1.9 hash syntax when appropriate.
-- Example javascript flow now picks up ENV vars for google key and secret.
-
-## 0.4.1 - 2016-03-14
-
-### Added
-- Nothing.
-
-### Deprecated
-- Nothing.
-
-### Removed
-- Nothing.
-
-### Fixed
-- Fixed JWT iat leeway by requiring ruby-jwt 1.5.2
-
-## 0.4.0 - 2016-03-11
-
-### Added
-- Addedd ability to specify multiple hosted domains.
-- Added a default leeway of 1 minute to JWT token validation.
-- Now requires ruby-jwt 1.5.x.
-
-### Deprecated
-- Nothing.
-
-### Removed
-- Removed support for ruby 1.9.3 as ruby-jwt 1.5.x does not support it.
-
-### Fixed
-- Nothing.
-
-## 0.3.1 - 2016-01-28
-
-### Added
-- Verify Hosted Domain if hd is set in options.
-
-### Deprecated
-- Nothing.
-
-### Removed
-- Dependency on addressable.
-
-### Fixed
-- Nothing.
-
-## 0.3.0 - 2016-01-09
-
-### Added
-- Updated verify_token to use the v3 tokeninfo endpoint.
-
-### Deprecated
-- Nothing.
-
-### Removed
-- Nothing.
-
-### Fixed
-- Compatibility with omniauth-oauth2 1.4.0
-
-## 0.2.10 - 2015-11-05
-
-### Added
-- Nothing.
-
-### Deprecated
-- Nothing.
-
-### Removed
-- Removed some checks on the id_token. Now only parses the id_token in the JWT processing.
-
-### Fixed
-- Nothing.
-
-## 0.2.9 - 2015-10-29
-
-### Added
-- Nothing.
-
-### Deprecated
-- Nothing.
-
-### Removed
-- Nothing.
-
-### Fixed
-- Issue with omniauth-oauth2 where redirect_uri was handled improperly. We now lock the dependency to ~> 1.3.1
-
-## 0.2.8 - 2015-10-01
-
-### Added
-- Added skip_jwt option to bypass JWT decoding in case you get decoding errors.
-
-### Deprecated
-- Nothing.
-
-### Removed
-- Nothing.
-
-### Fixed
-- Resolved JWT::InvalidIatError. https://github.com/zquestz/omniauth-google-oauth2/issues/195
-
-## 0.2.7 - 2015-09-25
-
-### Added
-- Now strips out the 'sz' parameter from profile image urls.
-- Now uses 'addressable' gem for URI actions.
-- Added image data to extras hash.
-- Override validation on JWT token for open_id token.
-- Handle authorization codes coming from an installed applications.
-
-### Deprecated
-- Nothing.
-
-### Removed
-- Nothing.
-
-### Fixed
-- Fixes double slashes in google image urls.
-
-## 0.2.6 - 2014-10-26
-
-### Added
-- Nothing.
-
-### Deprecated
-- Nothing.
-
-### Removed
-- Nothing.
-
-### Fixed
-- Hybrid authorization issues due to bad method alias.
-
-## 0.2.5 - 2014-07-09
-
-### Added
-- Support for versions of omniauth past 1.0.x.
-
-### Deprecated
-- Nothing.
-
-### Removed
-- Nothing.
-
-### Fixed
-- Nothing.
-
-## 0.2.4 - 2014-04-25
-
-### Added
-- Now requiring the "Contacts API" and "Google+ API" to be enabled in your Google API console.
-
-### Deprecated
-- The old Google OAuth API support was removed without deprecation.
-
-### Removed
-- Support for the old Google OAuth API. `OAuth2::Error` will be thrown and state that access is not configured when you attempt to authenticate using the old API. See Added section for this release.
-
-### Fixed
-- Nothing.
diff --git a/vendor/gems/omniauth-google-oauth2/Gemfile.lock b/vendor/gems/omniauth-google-oauth2/Gemfile.lock
deleted file mode 100644
index 6c3f5ff3f68..00000000000
--- a/vendor/gems/omniauth-google-oauth2/Gemfile.lock
+++ /dev/null
@@ -1,87 +0,0 @@
-PATH
- remote: .
- specs:
- omniauth-google-oauth2 (1.0.1)
- jwt (>= 2.0)
- oauth2 (~> 2.0)
- omniauth (~> 2.0)
- omniauth-oauth2 (~> 1.7.1)
-
-GEM
- remote: https://rubygems.org/
- specs:
- ast (2.4.2)
- diff-lcs (1.5.0)
- faraday (2.5.2)
- faraday-net_http (>= 2.0, < 3.1)
- ruby2_keywords (>= 0.0.4)
- faraday-net_http (3.0.0)
- hashie (5.0.0)
- jwt (2.4.1)
- multi_xml (0.6.0)
- oauth2 (2.0.3)
- faraday (>= 0.17.3, < 3.0)
- jwt (>= 1.0, < 3.0)
- multi_xml (~> 0.5)
- rack (>= 1.2, < 3)
- rash_alt (>= 0.4, < 1)
- version_gem (~> 1.0)
- omniauth (2.1.0)
- hashie (>= 3.4.6)
- rack (>= 2.2.3)
- rack-protection
- omniauth-oauth2 (1.7.3)
- oauth2 (>= 1.4, < 3)
- omniauth (>= 1.9, < 3)
- parallel (1.22.1)
- parser (3.1.2.0)
- ast (~> 2.4.1)
- rack (2.2.4)
- rack-protection (2.2.2)
- rack
- rainbow (3.1.1)
- rake (12.3.3)
- rash_alt (0.4.12)
- hashie (>= 3.4)
- regexp_parser (2.5.0)
- rexml (3.2.5)
- rspec (3.11.0)
- rspec-core (~> 3.11.0)
- rspec-expectations (~> 3.11.0)
- rspec-mocks (~> 3.11.0)
- rspec-core (3.11.0)
- rspec-support (~> 3.11.0)
- rspec-expectations (3.11.0)
- diff-lcs (>= 1.2.0, < 2.0)
- rspec-support (~> 3.11.0)
- rspec-mocks (3.11.1)
- diff-lcs (>= 1.2.0, < 2.0)
- rspec-support (~> 3.11.0)
- rspec-support (3.11.0)
- rubocop (0.93.1)
- parallel (~> 1.10)
- parser (>= 2.7.1.5)
- rainbow (>= 2.2.2, < 4.0)
- regexp_parser (>= 1.8)
- rexml
- rubocop-ast (>= 0.6.0)
- ruby-progressbar (~> 1.7)
- unicode-display_width (>= 1.4.0, < 2.0)
- rubocop-ast (1.19.1)
- parser (>= 3.1.1.0)
- ruby-progressbar (1.11.0)
- ruby2_keywords (0.0.5)
- unicode-display_width (1.8.0)
- version_gem (1.1.0)
-
-PLATFORMS
- ruby
-
-DEPENDENCIES
- omniauth-google-oauth2!
- rake (~> 12.0)
- rspec (~> 3.6)
- rubocop (~> 0.49)
-
-BUNDLED WITH
- 2.3.21
diff --git a/vendor/gems/omniauth-google-oauth2/README.md b/vendor/gems/omniauth-google-oauth2/README.md
deleted file mode 100644
index 80c611392ca..00000000000
--- a/vendor/gems/omniauth-google-oauth2/README.md
+++ /dev/null
@@ -1,368 +0,0 @@
-[![Gem Version](https://badge.fury.io/rb/omniauth-google-oauth2.svg)](https://badge.fury.io/rb/omniauth-google-oauth2)
-
-# OmniAuth Google OAuth2 Strategy
-
-Strategy to authenticate with Google via OAuth2 in OmniAuth.
-
-Get your API key at: https://code.google.com/apis/console/ Note the Client ID and the Client Secret.
-
-For more details, read the Google docs: https://developers.google.com/accounts/docs/OAuth2
-
-## Installation
-
-Add to your `Gemfile`:
-
-```ruby
-gem 'omniauth-google-oauth2'
-```
-
-Then `bundle install`.
-
-## Google API Setup
-
-* Go to 'https://console.developers.google.com'
-* Select your project.
-* Go to Credentials, then select the "OAuth consent screen" tab on top, and provide an 'EMAIL ADDRESS' and a 'PRODUCT NAME'
-* Wait 10 minutes for changes to take effect.
-
-## Usage
-
-Here's an example for adding the middleware to a Rails app in `config/initializers/omniauth.rb`:
-
-```ruby
-Rails.application.config.middleware.use OmniAuth::Builder do
- provider :google_oauth2, ENV['GOOGLE_CLIENT_ID'], ENV['GOOGLE_CLIENT_SECRET']
-end
-OmniAuth.config.allowed_request_methods = %i[get]
-```
-
-You can now access the OmniAuth Google OAuth2 URL: `/auth/google_oauth2`
-
-For more examples please check out `examples/omni_auth.rb`
-
-NOTE: While developing your application, if you change the scope in the initializer you will need to restart your app server. Remember that either the 'email' or 'profile' scope is required!
-
-## Configuration
-
-You can configure several options, which you pass in to the `provider` method via a hash:
-
-* `scope`: A comma-separated list of permissions you want to request from the user. See the [Google OAuth 2.0 Playground](https://developers.google.com/oauthplayground/) for a full list of available permissions. Caveats:
- * The `email` and `profile` scopes are used by default. By defining your own `scope`, you override these defaults, but Google requires at least one of `email` or `profile`, so make sure to add at least one of them to your scope!
- * Scopes starting with `https://www.googleapis.com/auth/` do not need that prefix specified. So while you can use the smaller scope `books` since that permission starts with the mentioned prefix, you should use the full scope URL `https://docs.google.com/feeds/` to access a user's docs, for example.
-
-* `redirect_uri`: Override the redirect_uri used by the gem.
-
-* `prompt`: A space-delimited list of string values that determines whether the user is re-prompted for authentication and/or consent. Possible values are:
- * `none`: No authentication or consent pages will be displayed; it will return an error if the user is not already authenticated and has not pre-configured consent for the requested scopes. This can be used as a method to check for existing authentication and/or consent.
- * `consent`: The user will always be prompted for consent, even if they have previously allowed access a given set of scopes.
- * `select_account`: The user will always be prompted to select a user account. This allows a user who has multiple current account sessions to select one amongst them.
-
- If no value is specified, the user only sees the authentication page if they are not logged in and only sees the consent page the first time they authorize a given set of scopes.
-
-* `image_aspect_ratio`: The shape of the user's profile picture. Possible values are:
- * `original`: Picture maintains its original aspect ratio.
- * `square`: Picture presents equal width and height.
-
- Defaults to `original`.
-
-* `image_size`: The size of the user's profile picture. The image returned will have width equal to the given value and variable height, according to the `image_aspect_ratio` chosen. Additionally, a picture with specific width and height can be requested by setting this option to a hash with `width` and `height` as keys. If only `width` or `height` is specified, a picture whose width or height is closest to the requested size and requested aspect ratio will be returned. Defaults to the original width and height of the picture.
-
-* `name`: The name of the strategy. The default name is `google_oauth2` but it can be changed to any value, for example `google`. The OmniAuth URL will thus change to `/auth/google` and the `provider` key in the auth hash will then return `google`.
-
-* `access_type`: Defaults to `offline`, so a refresh token is sent to be used when the user is not present at the browser. Can be set to `online`. More about [offline access](https://developers.google.com/identity/protocols/OAuth2WebServer#offline)
-
-* `hd`: (Optional) Limit sign-in to a particular Google Apps hosted domain. This can be simply string `'domain.com'` or an array `%w(domain.com domain.co)`. More information at: https://developers.google.com/accounts/docs/OpenIDConnect#hd-param
-
-* `jwt_leeway`: Number of seconds passed to the JWT library as leeway. Defaults to 60 seconds. Note this only works if you use jwt 2.1, as the leeway option was removed in later versions.
-
-* `skip_jwt`: Skip JWT processing. This is for users who are seeing JWT decoding errors with the `iat` field. Always try adjusting the leeway before disabling JWT processing.
-
-* `login_hint`: When your app knows which user it is trying to authenticate, it can provide this parameter as a hint to the authentication server. Passing this hint suppresses the account chooser and either pre-fill the email box on the sign-in form, or select the proper session (if the user is using multiple sign-in), which can help you avoid problems that occur if your app logs in the wrong user account. The value can be either an email address or the sub string, which is equivalent to the user's Google+ ID.
-
-* `include_granted_scopes`: If this is provided with the value true, and the authorization request is granted, the authorization will include any previous authorizations granted to this user/application combination for other scopes. See Google's [Incremental Authorization](https://developers.google.com/accounts/docs/OAuth2WebServer#incrementalAuth) for additional details.
-
-* `openid_realm`: Set the OpenID realm value, to allow upgrading from OpenID based authentication to OAuth 2 based authentication. When this is set correctly an `openid_id` value will be set in `['extra']['id_info']` in the authentication hash with the value of the user's OpenID ID URL.
-
-* `provider_ignores_state`: You will need to set this to `true` when using the `One-time Code Flow` below. In this flow there is no server side redirect that would set the state.
-
-Here's an example of a possible configuration where the strategy name is changed, the user is asked for extra permissions, the user is always prompted to select their account when logging in and the user's profile picture is returned as a thumbnail:
-
-```ruby
-Rails.application.config.middleware.use OmniAuth::Builder do
- provider :google_oauth2, ENV['GOOGLE_CLIENT_ID'], ENV['GOOGLE_CLIENT_SECRET'],
- {
- scope: 'userinfo.email, userinfo.profile, http://gdata.youtube.com',
- prompt: 'select_account',
- image_aspect_ratio: 'square',
- image_size: 50
- }
-end
-```
-
-## Auth Hash
-
-Here's an example of an authentication hash available in the callback by accessing `request.env['omniauth.auth']`:
-
-```ruby
-{
- "provider" => "google_oauth2",
- "uid" => "100000000000000000000",
- "info" => {
- "name" => "John Smith",
- "email" => "john@example.com",
- "first_name" => "John",
- "last_name" => "Smith",
- "image" => "https://lh4.googleusercontent.com/photo.jpg",
- "urls" => {
- "google" => "https://plus.google.com/+JohnSmith"
- }
- },
- "credentials" => {
- "token" => "TOKEN",
- "refresh_token" => "REFRESH_TOKEN",
- "expires_at" => 1496120719,
- "expires" => true
- },
- "extra" => {
- "id_token" => "ID_TOKEN",
- "id_info" => {
- "azp" => "APP_ID",
- "aud" => "APP_ID",
- "sub" => "100000000000000000000",
- "email" => "john@example.com",
- "email_verified" => true,
- "at_hash" => "HK6E_P6Dh8Y93mRNtsDB1Q",
- "iss" => "accounts.google.com",
- "iat" => 1496117119,
- "exp" => 1496120719
- },
- "raw_info" => {
- "sub" => "100000000000000000000",
- "name" => "John Smith",
- "given_name" => "John",
- "family_name" => "Smith",
- "profile" => "https://plus.google.com/+JohnSmith",
- "picture" => "https://lh4.googleusercontent.com/photo.jpg?sz=50",
- "email" => "john@example.com",
- "email_verified" => "true",
- "locale" => "en",
- "hd" => "company.com"
- }
- }
-}
-```
-
-### Devise
-
-First define your application id and secret in `config/initializers/devise.rb`. Do not use the snippet mentioned in the [Usage](https://github.com/zquestz/omniauth-google-oauth2#usage) section.
-
-Configuration options can be passed as the last parameter here as key/value pairs.
-
-```ruby
-config.omniauth :google_oauth2, 'GOOGLE_CLIENT_ID', 'GOOGLE_CLIENT_SECRET', {}
-```
-NOTE: If you are using this gem with devise with above snippet in `config/initializers/devise.rb` then do not create `config/initializers/omniauth.rb` which will conflict with devise configurations.
-
-Then add the following to 'config/routes.rb' so the callback routes are defined.
-
-```ruby
-devise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks' }
-```
-
-Make sure your model is omniauthable. Generally this is "/app/models/user.rb"
-
-```ruby
-devise :omniauthable, omniauth_providers: [:google_oauth2]
-```
-
-Then make sure your callbacks controller is setup.
-
-```ruby
-# app/controllers/users/omniauth_callbacks_controller.rb:
-
-class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
- def google_oauth2
- # You need to implement the method below in your model (e.g. app/models/user.rb)
- @user = User.from_omniauth(request.env['omniauth.auth'])
-
- if @user.persisted?
- flash[:notice] = I18n.t 'devise.omniauth_callbacks.success', kind: 'Google'
- sign_in_and_redirect @user, event: :authentication
- else
- session['devise.google_data'] = request.env['omniauth.auth'].except('extra') # Removing extra as it can overflow some session stores
- redirect_to new_user_registration_url, alert: @user.errors.full_messages.join("\n")
- end
- end
-end
-```
-
-and bind to or create the user
-
-```ruby
-def self.from_omniauth(access_token)
- data = access_token.info
- user = User.where(email: data['email']).first
-
- # Uncomment the section below if you want users to be created if they don't exist
- # unless user
- # user = User.create(name: data['name'],
- # email: data['email'],
- # password: Devise.friendly_token[0,20]
- # )
- # end
- user
-end
-```
-
-For your views you can login using:
-
-```erb
-<%# omniauth-google-oauth2 1.0.x uses OmniAuth 2 and requires using HTTP Post to initiate authentication: %>
-<%= link_to "Sign in with Google", user_google_oauth2_omniauth_authorize_path, method: :post %>
-
-<%# omniauth-google-oauth2 prior 1.0.0: %>
-<%= link_to "Sign in with Google", user_google_oauth2_omniauth_authorize_path %>
-
-<%# Devise prior 4.1.0: %>
-<%= link_to "Sign in with Google", user_omniauth_authorize_path(:google_oauth2) %>
-```
-
-An overview is available at https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview
-
-### One-time Code Flow (Hybrid Authentication)
-
-Google describes the One-time Code Flow [here](https://developers.google.com/identity/sign-in/web/server-side-flow). This hybrid authentication flow has significant functional and security advantages over a pure server-side or pure client-side flow. The following steps occur in this flow:
-
-1. The client (web browser) authenticates the user directly via Google's JS API. During this process assorted modals may be rendered by Google.
-2. On successful authentication, Google returns a one-time use code, which requires the Google client secret (which is only available server-side).
-3. Using a AJAX request, the code is POSTed to the Omniauth Google OAuth2 callback.
-4. The Omniauth Google OAuth2 gem will validate the code via a server-side request to Google. If the code is valid, then Google will return an access token and, if this is the first time this user is authenticating against this application, a refresh token. Both of these should be stored on the server. The response to the AJAX request indicates the success or failure of this process.
-
-This flow is immune to replay attacks, and conveys no useful information to a man in the middle.
-
-The omniauth-google-oauth2 gem supports this mode of operation when `provider_ignores_state` is set to `true`. Implementors simply need to add the appropriate JavaScript to their web page, and they can take advantage of this flow. An example JavaScript snippet follows.
-
-```javascript
-// Basic hybrid auth example following the pattern at:
-// https://developers.google.com/identity/sign-in/web/reference
-
-<script src="https://apis.google.com/js/platform.js?onload=init" async defer></script>
-
-...
-
-function init() {
- gapi.load('auth2', function() {
- // Ready.
- $('.google-login-button').click(function(e) {
- e.preventDefault();
-
- gapi.auth2.authorize({
- client_id: 'YOUR_CLIENT_ID',
- cookie_policy: 'single_host_origin',
- scope: 'email profile',
- response_type: 'code'
- }, function(response) {
- if (response && !response.error) {
- // google authentication succeed, now post data to server.
- jQuery.ajax({type: 'POST', url: '/auth/google_oauth2/callback', data: response,
- success: function(data) {
- // response from server
- }
- });
- } else {
- // google authentication failed
- }
- });
- });
- });
-};
-```
-
-#### Note about mobile clients (iOS, Android)
-
-The documentation at https://developers.google.com/identity/sign-in/ios/offline-access specifies the _REDIRECT_URI_ to be either a set value or an EMPTY string for mobile logins to work. Else, you will run into _redirect_uri_mismatch_ errors.
-
-In that case, ensure to send an additional parameter `redirect_uri=` (empty string) to the `/auth/google_oauth2/callback` URL from your mobile device.
-
-#### Note about CORS
-
-If you're making POST requests to `/auth/google_oauth2/callback` from another domain, then you need to make sure `'X-Requested-With': 'XMLHttpRequest'` header is included with your request, otherwise your server might respond with `OAuth2::Error, : Invalid Value` error.
-
-#### Getting around the `redirect_uri_mismatch` error (See [Issue #365](https://github.com/zquestz/omniauth-google-oauth2/issues/365))
-
-If you are struggling with a persistent `redirect_uri_mismatch`, you can instead pass the `access_token` from [`getAuthResponse`](https://developers.google.com/identity/sign-in/web/reference#googleusergetauthresponseincludeauthorizationdata) directly to the `auth/google_oauth2/callback` endpoint, like so:
-
-```javascript
-// Initialize the GoogleAuth object
-let googleAuth;
-gapi.load('client:auth2', async () => {
- await gapi.client.init({ scope: '...', client_id: '...' });
- googleAuth = gapi.auth2.getAuthInstance();
-});
-
-// Call this when the Google Sign In button is clicked
-async function signInGoogle() {
- const googleUser = await googleAuth.signIn(); // wait for the user to authorize through the modal
- const { access_token } = googleUser.getAuthResponse();
-
- const data = new FormData();
- data.append('access_token', access_token);
-
- const response = await api.post('/auth/google_oauth2/callback', data)
- console.log(response);
-}
-```
-
-#### Using Axios
-If you're making a GET resquests from another domain using `access_token`.
-```
-axios
- .get(
- 'url(path to your callback}',
- { params: { access_token: 'token' } },
- headers....
- )
-```
-
-If you're making a POST resquests from another domain using `access_token`.
-```
-axios
- .post(
- 'url(path to your callback}',
- { access_token: 'token' },
- headers....
- )
-
---OR--
-
-axios
- .post(
- 'url(path to your callback}',
- null,
- {
- params: {
- access_token: 'token'
- },
- headers....
- }
- )
-```
-
-## Fixing Protocol Mismatch for `redirect_uri` in Rails
-
-Just set the `full_host` in OmniAuth based on the Rails.env.
-
-```
-# config/initializers/omniauth.rb
-OmniAuth.config.full_host = Rails.env.production? ? 'https://domain.com' : 'http://localhost:3000'
-```
-
-## License
-
-Copyright (c) 2018 by Josh Ellithorpe
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/gems/omniauth-google-oauth2/Rakefile b/vendor/gems/omniauth-google-oauth2/Rakefile
deleted file mode 100644
index db36369bc12..00000000000
--- a/vendor/gems/omniauth-google-oauth2/Rakefile
+++ /dev/null
@@ -1,8 +0,0 @@
-# frozen_string_literal: true
-
-require File.join('bundler', 'gem_tasks')
-require File.join('rspec', 'core', 'rake_task')
-
-RSpec::Core::RakeTask.new(:spec)
-
-task default: :spec
diff --git a/vendor/gems/omniauth-google-oauth2/examples/Gemfile b/vendor/gems/omniauth-google-oauth2/examples/Gemfile
deleted file mode 100644
index ba019344a67..00000000000
--- a/vendor/gems/omniauth-google-oauth2/examples/Gemfile
+++ /dev/null
@@ -1,8 +0,0 @@
-# frozen_string_literal: true
-
-source 'https://rubygems.org'
-
-gem 'omniauth-google-oauth2', '~> 0.8.1'
-gem 'rubocop'
-gem 'sinatra', '~> 1.4'
-gem 'webrick'
diff --git a/vendor/gems/omniauth-google-oauth2/examples/Gemfile.lock b/vendor/gems/omniauth-google-oauth2/examples/Gemfile.lock
new file mode 100644
index 00000000000..5ac8f1be5e0
--- /dev/null
+++ b/vendor/gems/omniauth-google-oauth2/examples/Gemfile.lock
@@ -0,0 +1,72 @@
+GEM
+ remote: https://rubygems.org/
+ specs:
+ ast (2.4.2)
+ faraday (2.5.2)
+ faraday-net_http (>= 2.0, < 3.1)
+ ruby2_keywords (>= 0.0.4)
+ faraday-net_http (3.0.0)
+ hashie (5.0.0)
+ json (2.6.2)
+ jwt (2.5.0)
+ multi_json (1.15.0)
+ multi_xml (0.6.0)
+ oauth2 (1.4.11)
+ faraday (>= 0.17.3, < 3.0)
+ jwt (>= 1.0, < 3.0)
+ multi_json (~> 1.3)
+ multi_xml (~> 0.5)
+ rack (>= 1.2, < 4)
+ omniauth (1.9.2)
+ hashie (>= 3.4.6)
+ rack (>= 1.6.2, < 3)
+ omniauth-google-oauth2 (0.8.2)
+ jwt (>= 2.0)
+ oauth2 (~> 1.1)
+ omniauth (~> 1.1)
+ omniauth-oauth2 (>= 1.6)
+ omniauth-oauth2 (1.7.3)
+ oauth2 (>= 1.4, < 3)
+ omniauth (>= 1.9, < 3)
+ parallel (1.22.1)
+ parser (3.1.2.1)
+ ast (~> 2.4.1)
+ rack (1.6.13)
+ rack-protection (1.5.5)
+ rack
+ rainbow (3.1.1)
+ regexp_parser (2.6.0)
+ rexml (3.2.5)
+ rubocop (1.36.0)
+ json (~> 2.3)
+ parallel (~> 1.10)
+ parser (>= 3.1.2.1)
+ rainbow (>= 2.2.2, < 4.0)
+ regexp_parser (>= 1.8, < 3.0)
+ rexml (>= 3.2.5, < 4.0)
+ rubocop-ast (>= 1.20.1, < 2.0)
+ ruby-progressbar (~> 1.7)
+ unicode-display_width (>= 1.4.0, < 3.0)
+ rubocop-ast (1.21.0)
+ parser (>= 3.1.1.0)
+ ruby-progressbar (1.11.0)
+ ruby2_keywords (0.0.5)
+ sinatra (1.4.8)
+ rack (~> 1.5)
+ rack-protection (~> 1.4)
+ tilt (>= 1.3, < 3)
+ tilt (2.0.11)
+ unicode-display_width (2.3.0)
+ webrick (1.7.0)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ omniauth-google-oauth2 (~> 0.8.1)
+ rubocop
+ sinatra (~> 1.4)
+ webrick
+
+BUNDLED WITH
+ 2.3.22
diff --git a/vendor/gems/omniauth-google-oauth2/examples/config.ru b/vendor/gems/omniauth-google-oauth2/examples/config.ru
deleted file mode 100644
index ee17929094c..00000000000
--- a/vendor/gems/omniauth-google-oauth2/examples/config.ru
+++ /dev/null
@@ -1,120 +0,0 @@
-# frozen_string_literal: true
-
-# Sample app for Google OAuth2 Strategy
-# Make sure to setup the ENV variables GOOGLE_KEY and GOOGLE_SECRET
-# Run with "bundle exec rackup"
-
-require 'rubygems'
-require 'bundler'
-require 'sinatra'
-require 'omniauth'
-require 'omniauth-google-oauth2'
-
-# Do not use for production code.
-# This is only to make setup easier when running through the sample.
-#
-# If you do have issues with certs in production code, this could help:
-# http://railsapps.github.io/openssl-certificate-verify-failed.html
-OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE
-
-# Main example app for omniauth-google-oauth2
-class App < Sinatra::Base
- get '/' do
- <<-HTML
- <!DOCTYPE html>
- <html>
- <head>
- <title>Google OAuth2 Example</title>
- <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
- <script>
- jQuery(function() {
- return $.ajax({
- url: 'https://apis.google.com/js/client:plus.js?onload=gpAsyncInit',
- dataType: 'script',
- cache: true
- });
- });
-
- window.gpAsyncInit = function() {
- gapi.auth.authorize({
- immediate: true,
- response_type: 'code',
- cookie_policy: 'single_host_origin',
- client_id: '#{ENV['GOOGLE_KEY']}',
- scope: 'email profile'
- }, function(response) {
- return;
- });
- $('.googleplus-login').click(function(e) {
- e.preventDefault();
- gapi.auth.authorize({
- immediate: false,
- response_type: 'code',
- cookie_policy: 'single_host_origin',
- client_id: '#{ENV['GOOGLE_KEY']}',
- scope: 'email profile'
- }, function(response) {
- if (response && !response.error) {
- // google authentication succeed, now post data to server.
- jQuery.ajax({type: 'POST', url: "/auth/google_oauth2/callback", data: response,
- success: function(data) {
- // Log the data returning from google.
- console.log(data)
- }
- });
- } else {
- // google authentication failed.
- console.log("FAILED")
- }
- });
- });
- };
- </script>
- </head>
- <body>
- <ul>
- <li><a href='/auth/google_oauth2'>Sign in with Google</a></li>
- <li><a href='#' class="googleplus-login">Sign in with Google via AJAX</a></li>
- </ul>
- </body>
- </html>
- HTML
- end
-
- post '/auth/:provider/callback' do
- content_type 'text/plain'
- begin
- request.env['omniauth.auth'].to_hash.inspect
- rescue StandardError
- 'No Data'
- end
- end
-
- get '/auth/:provider/callback' do
- content_type 'text/plain'
- begin
- request.env['omniauth.auth'].to_hash.inspect
- rescue StandardError
- 'No Data'
- end
- end
-
- get '/auth/failure' do
- content_type 'text/plain'
- begin
- request.env['omniauth.auth'].to_hash.inspect
- rescue StandardError
- 'No Data'
- end
- end
-end
-
-use Rack::Session::Cookie, secret: ENV['RACK_COOKIE_SECRET']
-
-use OmniAuth::Builder do
- # For additional provider examples please look at 'omni_auth.rb'
- # The key provider_ignores_state is only for AJAX flows. It is not recommended for normal logins.
- provider :google_oauth2, ENV['GOOGLE_KEY'], ENV['GOOGLE_SECRET'], access_type: 'offline', prompt: 'consent', provider_ignores_state: true, scope: 'email,profile,calendar'
-end
-
-run App.new
diff --git a/vendor/gems/omniauth-google-oauth2/examples/omni_auth.rb b/vendor/gems/omniauth-google-oauth2/examples/omni_auth.rb
deleted file mode 100644
index 0a94164d766..00000000000
--- a/vendor/gems/omniauth-google-oauth2/examples/omni_auth.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-# frozen_string_literal: true
-
-# Google's OAuth2 docs. Make sure you are familiar with all the options
-# before attempting to configure this gem.
-# https://developers.google.com/accounts/docs/OAuth2Login
-
-Rails.application.config.middleware.use OmniAuth::Builder do
- # Default usage, this will give you offline access and a refresh token
- # using default scopes 'email' and 'profile'
- #
- provider :google_oauth2, ENV['GOOGLE_KEY'], ENV['GOOGLE_SECRET'], scope: 'email,profile'
-
- # Custom redirect_uri
- #
- # provider :google_oauth2, ENV['GOOGLE_KEY'], ENV['GOOGLE_SECRET'], scope: 'email,profile', redirect_uri: 'https://localhost:3000/redirect'
-
- # Manual setup for offline access with a refresh token.
- #
- # provider :google_oauth2, ENV['GOOGLE_KEY'], ENV['GOOGLE_SECRET'], access_type: 'offline'
-
- # Custom scope supporting youtube. If you are customizing scopes, remember
- # to include the default scopes 'email' and 'profile'
- #
- # provider :google_oauth2, ENV['GOOGLE_KEY'], ENV['GOOGLE_SECRET'], scope: 'http://gdata.youtube.com,email,profile,plus.me'
-
- # Custom scope for users only using Google for account creation/auth and do not require a refresh token.
- #
- # provider :google_oauth2, ENV['GOOGLE_KEY'], ENV['GOOGLE_SECRET'], access_type: 'online', prompt: ''
-
- # To include information about people in your circles you must include the 'plus.login' scope.
- #
- # provider :google_oauth2, ENV['GOOGLE_KEY'], ENV['GOOGLE_SECRET'], skip_friends: false, scope: 'email,profile,plus.login'
-
- # If you need to acquire whether user picture is a default one or uploaded by user.
- #
- # provider :google_oauth2, ENV['GOOGLE_KEY'], ENV['GOOGLE_SECRET'], skip_image_info: false
-end
diff --git a/vendor/gems/omniauth-google-oauth2/lib/omniauth-google-oauth2.rb b/vendor/gems/omniauth-google-oauth2/lib/omniauth-google-oauth2.rb
deleted file mode 100644
index a5cc57ab4c9..00000000000
--- a/vendor/gems/omniauth-google-oauth2/lib/omniauth-google-oauth2.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-# frozen_string_literal: true
-
-require 'omniauth/google_oauth2'
diff --git a/vendor/gems/omniauth-google-oauth2/lib/omniauth/google_oauth2.rb b/vendor/gems/omniauth-google-oauth2/lib/omniauth/google_oauth2.rb
deleted file mode 100644
index 594c9a4eed9..00000000000
--- a/vendor/gems/omniauth-google-oauth2/lib/omniauth/google_oauth2.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-# frozen_string_literal: true
-
-require 'omniauth/strategies/google_oauth2'
diff --git a/vendor/gems/omniauth-google-oauth2/lib/omniauth/google_oauth2/version.rb b/vendor/gems/omniauth-google-oauth2/lib/omniauth/google_oauth2/version.rb
deleted file mode 100644
index 93ae5e9e990..00000000000
--- a/vendor/gems/omniauth-google-oauth2/lib/omniauth/google_oauth2/version.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-# frozen_string_literal: true
-
-module OmniAuth
- module GoogleOauth2
- VERSION = '1.0.1'
- end
-end
diff --git a/vendor/gems/omniauth-google-oauth2/lib/omniauth/strategies/google_oauth2.rb b/vendor/gems/omniauth-google-oauth2/lib/omniauth/strategies/google_oauth2.rb
deleted file mode 100644
index 4ce32eb80d1..00000000000
--- a/vendor/gems/omniauth-google-oauth2/lib/omniauth/strategies/google_oauth2.rb
+++ /dev/null
@@ -1,254 +0,0 @@
-# frozen_string_literal: true
-
-require 'jwt'
-require 'oauth2'
-require 'omniauth/strategies/oauth2'
-require 'uri'
-
-module OmniAuth
- module Strategies
- # Main class for Google OAuth2 strategy.
- class GoogleOauth2 < OmniAuth::Strategies::OAuth2
- ALLOWED_ISSUERS = ['accounts.google.com', 'https://accounts.google.com'].freeze
- BASE_SCOPE_URL = 'https://www.googleapis.com/auth/'
- BASE_SCOPES = %w[profile email openid].freeze
- DEFAULT_SCOPE = 'email,profile'
- USER_INFO_URL = 'https://www.googleapis.com/oauth2/v3/userinfo'
- IMAGE_SIZE_REGEXP = /(s\d+(-c)?)|(w\d+-h\d+(-c)?)|(w\d+(-c)?)|(h\d+(-c)?)|c/
-
- option :name, 'google_oauth2'
- option :skip_friends, true
- option :skip_image_info, true
- option :skip_jwt, false
- option :jwt_leeway, 60
- option :authorize_options, %i[access_type hd login_hint prompt request_visible_actions scope state redirect_uri include_granted_scopes openid_realm device_id device_name]
- option :authorized_client_ids, []
-
- option :client_options,
- site: 'https://oauth2.googleapis.com',
- authorize_url: 'https://accounts.google.com/o/oauth2/auth',
- token_url: '/token'
-
- def authorize_params
- super.tap do |params|
- options[:authorize_options].each do |k|
- params[k] = request.params[k.to_s] unless [nil, ''].include?(request.params[k.to_s])
- end
-
- params[:scope] = get_scope(params)
- params[:access_type] = 'offline' if params[:access_type].nil?
- params['openid.realm'] = params.delete(:openid_realm) unless params[:openid_realm].nil?
-
- session['omniauth.state'] = params[:state] if params[:state]
- end
- end
-
- uid { raw_info['sub'] }
-
- info do
- prune!(
- name: raw_info['name'],
- email: verified_email,
- unverified_email: raw_info['email'],
- email_verified: raw_info['email_verified'],
- first_name: raw_info['given_name'],
- last_name: raw_info['family_name'],
- image: image_url,
- urls: {
- google: raw_info['profile']
- }
- )
- end
-
- credentials do
- # Tokens and expiration will be used from OAuth2 strategy credentials block
- prune!({ 'scope' => token_info(access_token.token)['scope'] })
- end
-
- extra do
- hash = {}
- hash[:id_token] = access_token['id_token']
- if !options[:skip_jwt] && !access_token['id_token'].nil?
- decoded = ::JWT.decode(access_token['id_token'], nil, false).first
-
- # We have to manually verify the claims because the third parameter to
- # JWT.decode is false since no verification key is provided.
- ::JWT::Verify.verify_claims(decoded,
- verify_iss: true,
- iss: ALLOWED_ISSUERS,
- verify_aud: true,
- aud: options.client_id,
- verify_sub: false,
- verify_expiration: true,
- verify_not_before: true,
- verify_iat: false,
- verify_jti: false,
- leeway: options[:jwt_leeway])
-
- hash[:id_info] = decoded
- end
- hash[:raw_info] = raw_info unless skip_info?
- prune! hash
- end
-
- def raw_info
- @raw_info ||= access_token.get(USER_INFO_URL).parsed
- end
-
- def custom_build_access_token
- access_token = get_access_token(request)
-
- verify_hd(access_token)
- access_token
- end
-
- alias build_access_token custom_build_access_token
-
- private
-
- def callback_url
- options[:redirect_uri] || (full_host + callback_path)
- end
-
- def get_access_token(request)
- verifier = request.params['code']
- redirect_uri = request.params['redirect_uri']
- access_token = request.params['access_token']
- if verifier && request.xhr?
- client_get_token(verifier, redirect_uri || 'postmessage')
- elsif verifier
- client_get_token(verifier, redirect_uri || callback_url)
- elsif access_token && verify_token(access_token)
- ::OAuth2::AccessToken.from_hash(client, request.params.dup)
- elsif request.content_type =~ /json/i
- begin
- body = JSON.parse(request.body.read)
- request.body.rewind # rewind request body for downstream middlewares
- verifier = body && body['code']
- access_token = body && body['access_token']
- redirect_uri ||= body && body['redirect_uri']
- if verifier
- client_get_token(verifier, redirect_uri || 'postmessage')
- elsif verify_token(access_token)
- ::OAuth2::AccessToken.from_hash(client, body.dup)
- end
- rescue JSON::ParserError => e
- warn "[omniauth google-oauth2] JSON parse error=#{e}"
- end
- end
- end
-
- def client_get_token(verifier, redirect_uri)
- client.auth_code.get_token(verifier, get_token_options(redirect_uri), get_token_params)
- end
-
- def get_token_params
- deep_symbolize(options.auth_token_params || {})
- end
-
- def get_scope(params)
- raw_scope = params[:scope] || DEFAULT_SCOPE
- scope_list = raw_scope.split(' ').map { |item| item.split(',') }.flatten
- scope_list.map! { |s| s =~ %r{^https?://} || BASE_SCOPES.include?(s) ? s : "#{BASE_SCOPE_URL}#{s}" }
- scope_list.join(' ')
- end
-
- def verified_email
- raw_info['email_verified'] ? raw_info['email'] : nil
- end
-
- def get_token_options(redirect_uri = '')
- { redirect_uri: redirect_uri }.merge(token_params.to_hash(symbolize_keys: true))
- end
-
- def prune!(hash)
- hash.delete_if do |_, v|
- prune!(v) if v.is_a?(Hash)
- v.nil? || (v.respond_to?(:empty?) && v.empty?)
- end
- end
-
- def image_url
- return nil unless raw_info['picture']
-
- u = URI.parse(raw_info['picture'].gsub('https:https', 'https'))
-
- path_index = u.path.to_s.index('/photo.jpg')
-
- if path_index && image_size_opts_passed?
- u.path.insert(path_index, image_params)
- u.path = u.path.gsub('//', '/')
-
- # Check if the image is already sized!
- split_path = u.path.split('/')
- u.path = u.path.sub("/#{split_path[-3]}", '') if split_path[-3] =~ IMAGE_SIZE_REGEXP
- end
-
- u.query = strip_unnecessary_query_parameters(u.query)
-
- u.to_s
- end
-
- def image_size_opts_passed?
- options[:image_size] || options[:image_aspect_ratio]
- end
-
- def image_params
- image_params = []
- if options[:image_size].is_a?(Integer)
- image_params << "s#{options[:image_size]}"
- elsif options[:image_size].is_a?(Hash)
- image_params << "w#{options[:image_size][:width]}" if options[:image_size][:width]
- image_params << "h#{options[:image_size][:height]}" if options[:image_size][:height]
- end
- image_params << 'c' if options[:image_aspect_ratio] == 'square'
-
- '/' + image_params.join('-')
- end
-
- def strip_unnecessary_query_parameters(query_parameters)
- # strip `sz` parameter (defaults to sz=50) which overrides `image_size` options
- return nil if query_parameters.nil?
-
- params = CGI.parse(query_parameters)
- stripped_params = params.delete_if { |key| key == 'sz' }
-
- # don't return an empty Hash since that would result
- # in URLs with a trailing ? character: http://image.url?
- return nil if stripped_params.empty?
-
- URI.encode_www_form(stripped_params)
- end
-
- def token_info(access_token)
- return nil unless access_token
-
- @token_info ||= Hash.new do |h, k|
- h[k] = client.request(:get, 'https://www.googleapis.com/oauth2/v3/tokeninfo', params: { access_token: access_token }).parsed
- end
-
- @token_info[access_token]
- end
-
- def verify_token(access_token)
- return false unless access_token
-
- token_info = token_info(access_token)
- token_info['aud'] == options.client_id || options.authorized_client_ids.include?(token_info['aud'])
- end
-
- def verify_hd(access_token)
- return true unless options.hd
-
- @raw_info ||= access_token.get(USER_INFO_URL).parsed
-
- options.hd = options.hd.call if options.hd.is_a? Proc
- allowed_hosted_domains = Array(options.hd)
-
- raise CallbackError.new(:invalid_hd, 'Invalid Hosted Domain') unless allowed_hosted_domains.include?(@raw_info['hd']) || options.hd == '*'
-
- true
- end
- end
- end
-end
diff --git a/vendor/gems/omniauth-google-oauth2/omniauth-google-oauth2.gemspec b/vendor/gems/omniauth-google-oauth2/omniauth-google-oauth2.gemspec
deleted file mode 100644
index a50d67bc9a0..00000000000
--- a/vendor/gems/omniauth-google-oauth2/omniauth-google-oauth2.gemspec
+++ /dev/null
@@ -1,31 +0,0 @@
-# frozen_string_literal: true
-
-require File.expand_path(
- File.join('..', 'lib', 'omniauth', 'google_oauth2', 'version'),
- __FILE__
-)
-
-Gem::Specification.new do |gem|
- gem.name = 'omniauth-google-oauth2'
- gem.version = OmniAuth::GoogleOauth2::VERSION
- gem.license = 'MIT'
- gem.summary = %(A Google OAuth2 strategy for OmniAuth 1.x)
- gem.description = %(A Google OAuth2 strategy for OmniAuth 1.x. This allows you to login to Google with your ruby app.)
- gem.authors = ['Josh Ellithorpe', 'Yury Korolev']
- gem.email = ['quest@mac.com']
- gem.homepage = 'https://github.com/zquestz/omniauth-google-oauth2'
-
- gem.files = Dir.glob("lib/**/*.*")
- gem.require_paths = ['lib']
-
- gem.required_ruby_version = '>= 2.2'
-
- gem.add_runtime_dependency 'jwt', '>= 2.0'
- gem.add_runtime_dependency 'oauth2', '~> 2.0'
- gem.add_runtime_dependency 'omniauth', '~> 2.0'
- gem.add_runtime_dependency 'omniauth-oauth2', '~> 1.7.1'
-
- gem.add_development_dependency 'rake', '~> 12.0'
- gem.add_development_dependency 'rspec', '~> 3.6'
- gem.add_development_dependency 'rubocop', '~> 0.49'
-end
diff --git a/vendor/gems/omniauth-google-oauth2/spec/omniauth/strategies/google_oauth2_spec.rb b/vendor/gems/omniauth-google-oauth2/spec/omniauth/strategies/google_oauth2_spec.rb
deleted file mode 100644
index 3a2bcf07e54..00000000000
--- a/vendor/gems/omniauth-google-oauth2/spec/omniauth/strategies/google_oauth2_spec.rb
+++ /dev/null
@@ -1,850 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-require 'json'
-require 'omniauth-google-oauth2'
-require 'stringio'
-
-describe OmniAuth::Strategies::GoogleOauth2 do
- let(:request) { double('Request', params: {}, cookies: {}, env: {}) }
- let(:app) do
- lambda do
- [200, {}, ['Hello.']]
- end
- end
-
- subject do
- OmniAuth::Strategies::GoogleOauth2.new(app, 'appid', 'secret', @options || {}).tap do |strategy|
- allow(strategy).to receive(:request) do
- request
- end
- end
- end
-
- before do
- OmniAuth.config.test_mode = true
- end
-
- after do
- OmniAuth.config.test_mode = false
- end
-
- describe '#client_options' do
- it 'has correct site' do
- expect(subject.client.site).to eq('https://oauth2.googleapis.com')
- end
-
- it 'has correct authorize_url' do
- expect(subject.client.options[:authorize_url]).to eq('https://accounts.google.com/o/oauth2/auth')
- end
-
- it 'has correct token_url' do
- expect(subject.client.options[:token_url]).to eq('/token')
- end
-
- describe 'overrides' do
- context 'as strings' do
- it 'should allow overriding the site' do
- @options = { client_options: { 'site' => 'https://example.com' } }
- expect(subject.client.site).to eq('https://example.com')
- end
-
- it 'should allow overriding the authorize_url' do
- @options = { client_options: { 'authorize_url' => 'https://example.com' } }
- expect(subject.client.options[:authorize_url]).to eq('https://example.com')
- end
-
- it 'should allow overriding the token_url' do
- @options = { client_options: { 'token_url' => 'https://example.com' } }
- expect(subject.client.options[:token_url]).to eq('https://example.com')
- end
- end
-
- context 'as symbols' do
- it 'should allow overriding the site' do
- @options = { client_options: { site: 'https://example.com' } }
- expect(subject.client.site).to eq('https://example.com')
- end
-
- it 'should allow overriding the authorize_url' do
- @options = { client_options: { authorize_url: 'https://example.com' } }
- expect(subject.client.options[:authorize_url]).to eq('https://example.com')
- end
-
- it 'should allow overriding the token_url' do
- @options = { client_options: { token_url: 'https://example.com' } }
- expect(subject.client.options[:token_url]).to eq('https://example.com')
- end
- end
- end
- end
-
- describe '#authorize_options' do
- %i[access_type hd login_hint prompt scope state device_id device_name].each do |k|
- it "should support #{k}" do
- @options = { k => 'http://someval' }
- expect(subject.authorize_params[k.to_s]).to eq('http://someval')
- end
- end
-
- describe 'redirect_uri' do
- it 'should default to nil' do
- @options = {}
- expect(subject.authorize_params['redirect_uri']).to eq(nil)
- end
-
- it 'should set the redirect_uri parameter if present' do
- @options = { redirect_uri: 'https://example.com' }
- expect(subject.authorize_params['redirect_uri']).to eq('https://example.com')
- end
- end
-
- describe 'access_type' do
- it 'should default to "offline"' do
- @options = {}
- expect(subject.authorize_params['access_type']).to eq('offline')
- end
-
- it 'should set the access_type parameter if present' do
- @options = { access_type: 'online' }
- expect(subject.authorize_params['access_type']).to eq('online')
- end
- end
-
- describe 'hd' do
- it 'should default to nil' do
- expect(subject.authorize_params['hd']).to eq(nil)
- end
-
- it 'should set the hd (hosted domain) parameter if present' do
- @options = { hd: 'example.com' }
- expect(subject.authorize_params['hd']).to eq('example.com')
- end
-
- it 'should set the hd parameter and work with nil hd (gmail)' do
- @options = { hd: nil }
- expect(subject.authorize_params['hd']).to eq(nil)
- end
-
- it 'should set the hd parameter to * if set (only allows G Suite emails)' do
- @options = { hd: '*' }
- expect(subject.authorize_params['hd']).to eq('*')
- end
- end
-
- describe 'login_hint' do
- it 'should default to nil' do
- expect(subject.authorize_params['login_hint']).to eq(nil)
- end
-
- it 'should set the login_hint parameter if present' do
- @options = { login_hint: 'john@example.com' }
- expect(subject.authorize_params['login_hint']).to eq('john@example.com')
- end
- end
-
- describe 'prompt' do
- it 'should default to nil' do
- expect(subject.authorize_params['prompt']).to eq(nil)
- end
-
- it 'should set the prompt parameter if present' do
- @options = { prompt: 'consent select_account' }
- expect(subject.authorize_params['prompt']).to eq('consent select_account')
- end
- end
-
- describe 'request_visible_actions' do
- it 'should default to nil' do
- expect(subject.authorize_params['request_visible_actions']).to eq(nil)
- end
-
- it 'should set the request_visible_actions parameter if present' do
- @options = { request_visible_actions: 'something' }
- expect(subject.authorize_params['request_visible_actions']).to eq('something')
- end
- end
-
- describe 'include_granted_scopes' do
- it 'should default to nil' do
- expect(subject.authorize_params['include_granted_scopes']).to eq(nil)
- end
-
- it 'should set the include_granted_scopes parameter if present' do
- @options = { include_granted_scopes: 'true' }
- expect(subject.authorize_params['include_granted_scopes']).to eq('true')
- end
- end
-
- describe 'scope' do
- it 'should expand scope shortcuts' do
- @options = { scope: 'calendar' }
- expect(subject.authorize_params['scope']).to eq('https://www.googleapis.com/auth/calendar')
- end
-
- it 'should leave base scopes as is' do
- @options = { scope: 'profile' }
- expect(subject.authorize_params['scope']).to eq('profile')
- end
-
- it 'should join scopes' do
- @options = { scope: 'profile,email' }
- expect(subject.authorize_params['scope']).to eq('profile email')
- end
-
- it 'should deal with whitespace when joining scopes' do
- @options = { scope: 'profile, email' }
- expect(subject.authorize_params['scope']).to eq('profile email')
- end
-
- it 'should set default scope to email,profile' do
- expect(subject.authorize_params['scope']).to eq('email profile')
- end
-
- it 'should support space delimited scopes' do
- @options = { scope: 'profile email' }
- expect(subject.authorize_params['scope']).to eq('profile email')
- end
-
- it 'should support extremely badly formed scopes' do
- @options = { scope: 'profile email,foo,steve yeah http://example.com' }
- expect(subject.authorize_params['scope']).to eq('profile email https://www.googleapis.com/auth/foo https://www.googleapis.com/auth/steve https://www.googleapis.com/auth/yeah http://example.com')
- end
- end
-
- describe 'state' do
- it 'should set the state parameter' do
- @options = { state: 'some_state' }
- expect(subject.authorize_params['state']).to eq('some_state')
- expect(subject.authorize_params[:state]).to eq('some_state')
- expect(subject.session['omniauth.state']).to eq('some_state')
- end
-
- it 'should set the omniauth.state dynamically' do
- allow(subject).to receive(:request) { double('Request', params: { 'state' => 'some_state' }, env: {}) }
- expect(subject.authorize_params['state']).to eq('some_state')
- expect(subject.authorize_params[:state]).to eq('some_state')
- expect(subject.session['omniauth.state']).to eq('some_state')
- end
- end
-
- describe 'overrides' do
- it 'should include top-level options that are marked as :authorize_options' do
- @options = { authorize_options: %i[scope foo request_visible_actions], scope: 'http://bar', foo: 'baz', hd: 'wow', request_visible_actions: 'something' }
- expect(subject.authorize_params['scope']).to eq('http://bar')
- expect(subject.authorize_params['foo']).to eq('baz')
- expect(subject.authorize_params['hd']).to eq(nil)
- expect(subject.authorize_params['request_visible_actions']).to eq('something')
- end
-
- describe 'request overrides' do
- %i[access_type hd login_hint prompt scope state].each do |k|
- context "authorize option #{k}" do
- let(:request) { double('Request', params: { k.to_s => 'http://example.com' }, cookies: {}, env: {}) }
-
- it "should set the #{k} authorize option dynamically in the request" do
- @options = { k: '' }
- expect(subject.authorize_params[k.to_s]).to eq('http://example.com')
- end
- end
- end
-
- describe 'custom authorize_options' do
- let(:request) { double('Request', params: { 'foo' => 'something' }, cookies: {}, env: {}) }
-
- it 'should support request overrides from custom authorize_options' do
- @options = { authorize_options: [:foo], foo: '' }
- expect(subject.authorize_params['foo']).to eq('something')
- end
- end
- end
- end
- end
-
- describe '#authorize_params' do
- it 'should include any authorize params passed in the :authorize_params option' do
- @options = { authorize_params: { request_visible_actions: 'something', foo: 'bar', baz: 'zip' }, hd: 'wow', bad: 'not_included' }
- expect(subject.authorize_params['request_visible_actions']).to eq('something')
- expect(subject.authorize_params['foo']).to eq('bar')
- expect(subject.authorize_params['baz']).to eq('zip')
- expect(subject.authorize_params['hd']).to eq('wow')
- expect(subject.authorize_params['bad']).to eq(nil)
- end
- end
-
- describe '#token_params' do
- it 'should include any token params passed in the :token_params option' do
- @options = { token_params: { foo: 'bar', baz: 'zip' } }
- expect(subject.token_params['foo']).to eq('bar')
- expect(subject.token_params['baz']).to eq('zip')
- end
- end
-
- describe '#token_options' do
- it 'should include top-level options that are marked as :token_options' do
- @options = { token_options: %i[scope foo], scope: 'bar', foo: 'baz', bad: 'not_included' }
- expect(subject.token_params['scope']).to eq('bar')
- expect(subject.token_params['foo']).to eq('baz')
- expect(subject.token_params['bad']).to eq(nil)
- end
- end
-
- describe '#callback_url' do
- let(:base_url) { 'https://example.com' }
-
- it 'has the correct default callback path' do
- allow(subject).to receive(:full_host) { base_url }
- allow(subject).to receive(:script_name) { '' }
- expect(subject.send(:callback_url)).to eq(base_url + '/auth/google_oauth2/callback')
- end
-
- it 'should set the callback path with script_name if present' do
- allow(subject).to receive(:full_host) { base_url }
- allow(subject).to receive(:script_name) { '/v1' }
- expect(subject.send(:callback_url)).to eq(base_url + '/v1/auth/google_oauth2/callback')
- end
-
- it 'should set the callback_path parameter if present' do
- @options = { callback_path: '/auth/foo/callback' }
- allow(subject).to receive(:full_host) { base_url }
- allow(subject).to receive(:script_name) { '' }
- expect(subject.send(:callback_url)).to eq(base_url + '/auth/foo/callback')
- end
- end
-
- describe '#info' do
- let(:client) do
- OAuth2::Client.new('abc', 'def') do |builder|
- builder.request :url_encoded
- builder.adapter :test do |stub|
- stub.get('/oauth2/v3/userinfo') { [200, { 'content-type' => 'application/json' }, response_hash.to_json] }
- end
- end
- end
- let(:access_token) { OAuth2::AccessToken.from_hash(client, {}) }
- before { allow(subject).to receive(:access_token).and_return(access_token) }
-
- context 'with verified email' do
- let(:response_hash) do
- { email: 'something@domain.invalid', email_verified: true }
- end
-
- it 'should return equal email and unverified_email' do
- expect(subject.info[:email]).to eq('something@domain.invalid')
- expect(subject.info[:unverified_email]).to eq('something@domain.invalid')
- end
- end
-
- context 'with unverified email' do
- let(:response_hash) do
- { email: 'something@domain.invalid', email_verified: false }
- end
-
- it 'should return nil email, and correct unverified email' do
- expect(subject.info[:email]).to eq(nil)
- expect(subject.info[:unverified_email]).to eq('something@domain.invalid')
- end
- end
- end
-
- describe '#credentials' do
- let(:client) { OAuth2::Client.new('abc', 'def') }
- let(:access_token) { OAuth2::AccessToken.from_hash(client, access_token: 'valid_access_token', expires_at: 123_456_789, refresh_token: 'valid_refresh_token') }
- before(:each) do
- allow(subject).to receive(:access_token).and_return(access_token)
- subject.options.client_options[:connection_build] = proc do |builder|
- builder.request :url_encoded
- builder.adapter :test do |stub|
- stub.get('/oauth2/v3/tokeninfo?access_token=valid_access_token') do
- [200, { 'Content-Type' => 'application/json; charset=UTF-8' }, JSON.dump(
- aud: '000000000000.apps.googleusercontent.com',
- sub: '123456789',
- scope: 'profile email'
- )]
- end
- end
- end
- end
-
- it 'should return access token and (optionally) refresh token' do
- expect(subject.credentials.to_h).to \
- match(hash_including(
- 'token' => 'valid_access_token',
- 'refresh_token' => 'valid_refresh_token',
- 'scope' => 'profile email',
- 'expires_at' => 123_456_789,
- 'expires' => true
- ))
- end
- end
-
- describe '#extra' do
- let(:client) do
- OAuth2::Client.new('abc', 'def') do |builder|
- builder.request :url_encoded
- builder.adapter :test do |stub|
- stub.get('/oauth2/v3/userinfo') { [200, { 'content-type' => 'application/json' }, '{"sub": "12345"}'] }
- end
- end
- end
- let(:access_token) { OAuth2::AccessToken.from_hash(client, {}) }
-
- before { allow(subject).to receive(:access_token).and_return(access_token) }
-
- describe 'id_token' do
- shared_examples 'id_token issued by valid issuer' do |issuer|
- context 'when the id_token is passed into the access token' do
- let(:token_info) do
- {
- 'abc' => 'xyz',
- 'exp' => Time.now.to_i + 3600,
- 'nbf' => Time.now.to_i - 60,
- 'iat' => Time.now.to_i,
- 'aud' => 'appid',
- 'iss' => issuer
- }
- end
- let(:id_token) { JWT.encode(token_info, 'secret') }
- let(:access_token) { OAuth2::AccessToken.from_hash(client, 'id_token' => id_token) }
-
- it 'should include id_token when set on the access_token' do
- expect(subject.extra).to include(id_token: id_token)
- end
-
- it 'should include id_info when id_token is set on the access_token and skip_jwt is false' do
- subject.options[:skip_jwt] = false
- expect(subject.extra).to include(id_info: token_info)
- end
-
- it 'should not include id_info when id_token is set on the access_token and skip_jwt is true' do
- subject.options[:skip_jwt] = true
- expect(subject.extra).not_to have_key(:id_info)
- end
-
- it 'should include id_info when id_token is set on the access_token by default' do
- expect(subject.extra).to include(id_info: token_info)
- end
- end
- end
-
- it_behaves_like 'id_token issued by valid issuer', 'accounts.google.com'
- it_behaves_like 'id_token issued by valid issuer', 'https://accounts.google.com'
-
- context 'when the id_token is issued by an invalid issuer' do
- let(:token_info) do
- {
- 'abc' => 'xyz',
- 'exp' => Time.now.to_i + 3600,
- 'nbf' => Time.now.to_i - 60,
- 'iat' => Time.now.to_i,
- 'aud' => 'appid',
- 'iss' => 'fake.google.com'
- }
- end
- let(:id_token) { JWT.encode(token_info, 'secret') }
- let(:access_token) { OAuth2::AccessToken.from_hash(client, 'id_token' => id_token) }
-
- it 'raises JWT::InvalidIssuerError' do
- expect { subject.extra }.to raise_error(JWT::InvalidIssuerError)
- end
- end
-
- context 'when the id_token is missing' do
- it 'should not include id_token' do
- expect(subject.extra).not_to have_key(:id_token)
- end
-
- it 'should not include id_info' do
- expect(subject.extra).not_to have_key(:id_info)
- end
- end
- end
-
- describe 'raw_info' do
- context 'when skip_info is true' do
- before { subject.options[:skip_info] = true }
-
- it 'should not include raw_info' do
- expect(subject.extra).not_to have_key(:raw_info)
- end
- end
-
- context 'when skip_info is false' do
- before { subject.options[:skip_info] = false }
-
- it 'should include raw_info' do
- expect(subject.extra[:raw_info]).to eq('sub' => '12345')
- end
- end
- end
- end
-
- describe 'populate auth hash urls' do
- it 'should populate url map in auth hash if link present in raw_info' do
- allow(subject).to receive(:raw_info) { { 'name' => 'Foo', 'profile' => 'https://plus.google.com/123456' } }
- expect(subject.info[:urls][:google]).to eq('https://plus.google.com/123456')
- end
-
- it 'should not populate url map in auth hash if no link present in raw_info' do
- allow(subject).to receive(:raw_info) { { 'name' => 'Foo' } }
- expect(subject.info).not_to have_key(:urls)
- end
- end
-
- describe 'image options' do
- it 'should have no image if a picture is not present' do
- @options = { image_aspect_ratio: 'square' }
- allow(subject).to receive(:raw_info) { { 'name' => 'User Without Pic' } }
- expect(subject.info[:image]).to be_nil
- end
-
- describe 'when a picture is returned from google' do
- it 'should return the image with size specified in the `image_size` option' do
- @options = { image_size: 50 }
- allow(subject).to receive(:raw_info) { { 'picture' => 'https://lh3.googleusercontent.com/url/photo.jpg' } }
- expect(subject.info[:image]).to eq('https://lh3.googleusercontent.com/url/s50/photo.jpg')
- end
-
- it 'should return the image with size specified in the `image_size` option when sizing is in the picture' do
- @options = { image_size: 50 }
- allow(subject).to receive(:raw_info) { { 'picture' => 'https://lh4.googleusercontent.com/url/s96-c/photo.jpg' } }
- expect(subject.info[:image]).to eq('https://lh4.googleusercontent.com/url/s50/photo.jpg')
- end
-
- it 'should handle a picture with too many slashes correctly' do
- @options = { image_size: 50 }
- allow(subject).to receive(:raw_info) { { 'picture' => 'https://lh3.googleusercontent.com/url//photo.jpg' } }
- expect(subject.info[:image]).to eq('https://lh3.googleusercontent.com/url/s50/photo.jpg')
- end
-
- it 'should handle a picture with a size query parameter correctly' do
- @options = { image_size: 50 }
- allow(subject).to receive(:raw_info) { { 'picture' => 'https://lh3.googleusercontent.com/url/photo.jpg?sz=50' } }
- expect(subject.info[:image]).to eq('https://lh3.googleusercontent.com/url/s50/photo.jpg')
- end
-
- it 'should handle a picture with a size query parameter and other valid query parameters correctly' do
- @options = { image_size: 50 }
- allow(subject).to receive(:raw_info) { { 'picture' => 'https://lh3.googleusercontent.com/url/photo.jpg?sz=50&hello=true&life=42' } }
- expect(subject.info[:image]).to eq('https://lh3.googleusercontent.com/url/s50/photo.jpg?hello=true&life=42')
- end
-
- it 'should handle a picture with other valid query parameters correctly' do
- @options = { image_size: 50 }
- allow(subject).to receive(:raw_info) { { 'picture' => 'https://lh3.googleusercontent.com/url/photo.jpg?hello=true&life=42' } }
- expect(subject.info[:image]).to eq('https://lh3.googleusercontent.com/url/s50/photo.jpg?hello=true&life=42')
- end
-
- it 'should return the image with width and height specified in the `image_size` option' do
- @options = { image_size: { width: 50, height: 40 } }
- allow(subject).to receive(:raw_info) { { 'picture' => 'https://lh3.googleusercontent.com/url/photo.jpg' } }
- expect(subject.info[:image]).to eq('https://lh3.googleusercontent.com/url/w50-h40/photo.jpg')
- end
-
- it 'should return the image with width and height specified in the `image_size` option when sizing is in the picture' do
- @options = { image_size: { width: 50, height: 40 } }
- allow(subject).to receive(:raw_info) { { 'picture' => 'https://lh3.googleusercontent.com/url/w100-h80-c/photo.jpg' } }
- expect(subject.info[:image]).to eq('https://lh3.googleusercontent.com/url/w50-h40/photo.jpg')
- end
-
- it 'should return square image when `image_aspect_ratio` is specified' do
- @options = { image_aspect_ratio: 'square' }
- allow(subject).to receive(:raw_info) { { 'picture' => 'https://lh3.googleusercontent.com/url/photo.jpg' } }
- expect(subject.info[:image]).to eq('https://lh3.googleusercontent.com/url/c/photo.jpg')
- end
-
- it 'should return square image when `image_aspect_ratio` is specified and sizing is in the picture' do
- @options = { image_aspect_ratio: 'square' }
- allow(subject).to receive(:raw_info) { { 'picture' => 'https://lh3.googleusercontent.com/url/c/photo.jpg' } }
- expect(subject.info[:image]).to eq('https://lh3.googleusercontent.com/url/c/photo.jpg')
- end
-
- it 'should return square sized image when `image_aspect_ratio` and `image_size` is set' do
- @options = { image_aspect_ratio: 'square', image_size: 50 }
- allow(subject).to receive(:raw_info) { { 'picture' => 'https://lh3.googleusercontent.com/url/photo.jpg' } }
- expect(subject.info[:image]).to eq('https://lh3.googleusercontent.com/url/s50-c/photo.jpg')
- end
-
- it 'should return square sized image when `image_aspect_ratio` and `image_size` is set and sizing is in the picture' do
- @options = { image_aspect_ratio: 'square', image_size: 50 }
- allow(subject).to receive(:raw_info) { { 'picture' => 'https://lh3.googleusercontent.com/url/s90/photo.jpg' } }
- expect(subject.info[:image]).to eq('https://lh3.googleusercontent.com/url/s50-c/photo.jpg')
- end
-
- it 'should return square sized image when `image_aspect_ratio` and `image_size` has height and width' do
- @options = { image_aspect_ratio: 'square', image_size: { width: 50, height: 40 } }
- allow(subject).to receive(:raw_info) { { 'picture' => 'https://lh3.googleusercontent.com/url/photo.jpg' } }
- expect(subject.info[:image]).to eq('https://lh3.googleusercontent.com/url/w50-h40-c/photo.jpg')
- end
-
- it 'should return square sized image when `image_aspect_ratio` and `image_size` has height and width and sizing is in the picture' do
- @options = { image_aspect_ratio: 'square', image_size: { width: 50, height: 40 } }
- allow(subject).to receive(:raw_info) { { 'picture' => 'https://lh3.googleusercontent.com/url/w100-h80/photo.jpg' } }
- expect(subject.info[:image]).to eq('https://lh3.googleusercontent.com/url/w50-h40-c/photo.jpg')
- end
-
- it 'should return original image if image url does not end in `photo.jpg`' do
- @options = { image_size: 50 }
- allow(subject).to receive(:raw_info) { { 'picture' => 'https://lh3.googleusercontent.com/url/photograph.jpg' } }
- expect(subject.info[:image]).to eq('https://lh3.googleusercontent.com/url/photograph.jpg')
- end
- end
-
- it 'should return original image if no options are provided' do
- allow(subject).to receive(:raw_info) { { 'picture' => 'https://lh3.googleusercontent.com/url/photo.jpg' } }
- expect(subject.info[:image]).to eq('https://lh3.googleusercontent.com/url/photo.jpg')
- end
-
- it 'should return correct image if google image url has double https' do
- allow(subject).to receive(:raw_info) { { 'picture' => 'https:https://lh3.googleusercontent.com/url/photo.jpg' } }
- expect(subject.info[:image]).to eq('https://lh3.googleusercontent.com/url/photo.jpg')
- end
- end
-
- describe 'build_access_token' do
- it 'should use a hybrid authorization request_uri if this is an AJAX request with a code parameter' do
- allow(request).to receive(:xhr?).and_return(true)
- allow(request).to receive(:params).and_return('code' => 'valid_code')
-
- client = double(:client)
- auth_code = double(:auth_code)
- allow(client).to receive(:auth_code).and_return(auth_code)
- expect(subject).to receive(:client).and_return(client)
- expect(auth_code).to receive(:get_token).with('valid_code', { redirect_uri: 'postmessage' }, {})
-
- expect(subject).not_to receive(:orig_build_access_token)
- subject.build_access_token
- end
-
- it 'should use a hybrid authorization request_uri if this is an AJAX request (mobile) with a code parameter' do
- allow(request).to receive(:xhr?).and_return(true)
- allow(request).to receive(:params).and_return('code' => 'valid_code', 'redirect_uri' => '')
-
- client = double(:client)
- auth_code = double(:auth_code)
- allow(client).to receive(:auth_code).and_return(auth_code)
- expect(subject).to receive(:client).and_return(client)
- expect(auth_code).to receive(:get_token).with('valid_code', { redirect_uri: '' }, {})
-
- expect(subject).not_to receive(:orig_build_access_token)
- subject.build_access_token
- end
-
- it 'should use the request_uri from params if this not an AJAX request (request from installed app) with a code parameter' do
- allow(request).to receive(:xhr?).and_return(false)
- allow(request).to receive(:params).and_return('code' => 'valid_code', 'redirect_uri' => 'redirect_uri')
-
- client = double(:client)
- auth_code = double(:auth_code)
- allow(client).to receive(:auth_code).and_return(auth_code)
- expect(subject).to receive(:client).and_return(client)
- expect(auth_code).to receive(:get_token).with('valid_code', { redirect_uri: 'redirect_uri' }, {})
-
- expect(subject).not_to receive(:orig_build_access_token)
- subject.build_access_token
- end
-
- it 'should read access_token from hash if this is not an AJAX request with a code parameter' do
- allow(request).to receive(:xhr?).and_return(false)
- allow(request).to receive(:params).and_return('access_token' => 'valid_access_token')
- expect(subject).to receive(:verify_token).with('valid_access_token').and_return true
- expect(subject).to receive(:client).and_return(:client)
-
- token = subject.build_access_token
- expect(token).to be_instance_of(::OAuth2::AccessToken)
- expect(token.token).to eq('valid_access_token')
- expect(token.client).to eq(:client)
- end
-
- it 'reads the code from a json request body' do
- body = StringIO.new(%({"code":"json_access_token"}))
- client = double(:client)
- auth_code = double(:auth_code)
-
- allow(request).to receive(:xhr?).and_return(false)
- allow(request).to receive(:content_type).and_return('application/json')
- allow(request).to receive(:body).and_return(body)
- allow(client).to receive(:auth_code).and_return(auth_code)
- expect(subject).to receive(:client).and_return(client)
-
- expect(auth_code).to receive(:get_token).with('json_access_token', { redirect_uri: 'postmessage' }, {})
-
- subject.build_access_token
- end
-
- it 'reads the redirect uri from a json request body' do
- body = StringIO.new(%({"code":"json_access_token", "redirect_uri":"sample"}))
- client = double(:client)
- auth_code = double(:auth_code)
-
- allow(request).to receive(:xhr?).and_return(false)
- allow(request).to receive(:content_type).and_return('application/json')
- allow(request).to receive(:body).and_return(body)
- allow(client).to receive(:auth_code).and_return(auth_code)
- expect(subject).to receive(:client).and_return(client)
-
- expect(auth_code).to receive(:get_token).with('json_access_token', { redirect_uri: 'sample' }, {})
-
- subject.build_access_token
- end
-
- it 'reads the access token from a json request body' do
- body = StringIO.new(%({"access_token":"valid_access_token"}))
-
- allow(request).to receive(:xhr?).and_return(false)
- allow(request).to receive(:content_type).and_return('application/json')
- allow(request).to receive(:body).and_return(body)
- expect(subject).to receive(:client).and_return(:client)
-
- expect(subject).to receive(:verify_token).with('valid_access_token').and_return true
-
- token = subject.build_access_token
- expect(token).to be_instance_of(::OAuth2::AccessToken)
- expect(token.token).to eq('valid_access_token')
- expect(token.client).to eq(:client)
- end
-
- it 'should use callback_url without query_string if this is not an AJAX request' do
- allow(request).to receive(:xhr?).and_return(false)
- allow(request).to receive(:params).and_return('code' => 'valid_code')
- allow(request).to receive(:content_type).and_return('application/x-www-form-urlencoded')
-
- client = double(:client)
- auth_code = double(:auth_code)
- allow(client).to receive(:auth_code).and_return(auth_code)
- allow(subject).to receive(:callback_url).and_return('redirect_uri_without_query_string')
-
- expect(subject).to receive(:client).and_return(client)
- expect(auth_code).to receive(:get_token).with('valid_code', { redirect_uri: 'redirect_uri_without_query_string' }, {})
- subject.build_access_token
- end
- end
-
- describe 'verify_token' do
- before(:each) do
- subject.options.client_options[:connection_build] = proc do |builder|
- builder.request :url_encoded
- builder.adapter :test do |stub|
- stub.get('/oauth2/v3/tokeninfo?access_token=valid_access_token') do
- [200, { 'Content-Type' => 'application/json; charset=UTF-8' }, JSON.dump(
- aud: '000000000000.apps.googleusercontent.com',
- sub: '123456789',
- email_verified: 'true',
- email: 'example@example.com',
- access_type: 'offline',
- scope: 'profile email',
- expires_in: 436
- )]
- end
- stub.get('/oauth2/v3/tokeninfo?access_token=invalid_access_token') do
- [400, { 'Content-Type' => 'application/json; charset=UTF-8' }, JSON.dump(error_description: 'Invalid Value')]
- end
- end
- end
- end
-
- it 'should verify token if access_token is valid and app_id equals' do
- subject.options.client_id = '000000000000.apps.googleusercontent.com'
- expect(subject.send(:verify_token, 'valid_access_token')).to eq(true)
- end
-
- it 'should verify token if access_token is valid and app_id authorized' do
- subject.options.authorized_client_ids = ['000000000000.apps.googleusercontent.com']
- expect(subject.send(:verify_token, 'valid_access_token')).to eq(true)
- end
-
- it 'should not verify token if access_token is valid but app_id is false' do
- expect(subject.send(:verify_token, 'valid_access_token')).to eq(false)
- end
-
- it 'should raise error if access_token is invalid' do
- expect do
- subject.send(:verify_token, 'invalid_access_token')
- end.to raise_error(OAuth2::Error)
- end
- end
-
- describe 'verify_hd' do
- let(:client) do
- OAuth2::Client.new('abc', 'def') do |builder|
- builder.request :url_encoded
- builder.adapter :test do |stub|
- stub.get('/oauth2/v3/userinfo') do
- [200, { 'Content-Type' => 'application/json; charset=UTF-8' }, JSON.dump(
- hd: 'example.com'
- )]
- end
- end
- end
- end
- let(:access_token) { OAuth2::AccessToken.from_hash(client, {}) }
-
- context 'when domain is nil' do
- let(:client) do
- OAuth2::Client.new('abc', 'def') do |builder|
- builder.request :url_encoded
- builder.adapter :test do |stub|
- stub.get('/oauth2/v3/userinfo') do
- [200, { 'Content-Type' => 'application/json; charset=UTF-8' }, JSON.dump({})]
- end
- end
- end
- end
-
- it 'should verify hd if options hd is set and correct' do
- subject.options.hd = nil
- expect(subject.send(:verify_hd, access_token)).to eq(true)
- end
-
- it 'should verify hd if options hd is set as an array and is correct' do
- subject.options.hd = ['example.com', 'example.co', nil]
- expect(subject.send(:verify_hd, access_token)).to eq(true)
- end
-
- it 'should raise an exception if nil is not included' do
- subject.options.hd = ['example.com', 'example.co']
- expect do
- subject.send(:verify_hd, access_token)
- end.to raise_error(OmniAuth::Strategies::OAuth2::CallbackError)
- end
- end
-
- it 'should verify hd if options hd is not set' do
- expect(subject.send(:verify_hd, access_token)).to eq(true)
- end
-
- it 'should verify hd if options hd is set and correct' do
- subject.options.hd = 'example.com'
- expect(subject.send(:verify_hd, access_token)).to eq(true)
- end
-
- it 'should verify hd if options hd is set as an array and is correct' do
- subject.options.hd = ['example.com', 'example.co', nil]
- expect(subject.send(:verify_hd, access_token)).to eq(true)
- end
-
- it 'should verify hd if options hd is set as an Proc and is correct' do
- subject.options.hd = proc { 'example.com' }
- expect(subject.send(:verify_hd, access_token)).to eq(true)
- end
-
- it 'should verify hd if options hd is set as an Proc returning an array and is correct' do
- subject.options.hd = proc { ['example.com', 'example.co'] }
- expect(subject.send(:verify_hd, access_token)).to eq(true)
- end
-
- it 'should raise error if options hd is set and wrong' do
- subject.options.hd = 'invalid.com'
- expect do
- subject.send(:verify_hd, access_token)
- end.to raise_error(OmniAuth::Strategies::GoogleOauth2::CallbackError)
- end
-
- it 'should raise error if options hd is set as an array and is not correct' do
- subject.options.hd = ['invalid.com', 'invalid.co']
- expect do
- subject.send(:verify_hd, access_token)
- end.to raise_error(OmniAuth::Strategies::GoogleOauth2::CallbackError)
- end
- end
-end
diff --git a/vendor/gems/omniauth-google-oauth2/spec/spec_helper.rb b/vendor/gems/omniauth-google-oauth2/spec/spec_helper.rb
deleted file mode 100644
index 3c2325389c2..00000000000
--- a/vendor/gems/omniauth-google-oauth2/spec/spec_helper.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-# frozen_string_literal: true
-
-require File.join('bundler', 'setup')
-require 'rspec'