omniauth-identity 3.1.4 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/RUBOCOP.md ADDED
@@ -0,0 +1,71 @@
1
+ # RuboCop Usage Guide
2
+
3
+ ## Overview
4
+
5
+ A tale of two RuboCop plugin gems.
6
+
7
+ ### RuboCop Gradual
8
+
9
+ This project uses `rubocop_gradual` instead of vanilla RuboCop for code style checking. The `rubocop_gradual` tool allows for gradual adoption of RuboCop rules by tracking violations in a lock file.
10
+
11
+ ### RuboCop LTS
12
+
13
+ This project uses `rubocop-lts` to ensure, on a best-effort basis, compatibility with Ruby >= 1.9.2.
14
+ RuboCop rules are meticulously configured by the `rubocop-lts` family of gems to ensure that a project is compatible with a specific version of Ruby. See: https://rubocop-lts.gitlab.io for more.
15
+
16
+ ## Checking RuboCop Violations
17
+
18
+ To check for RuboCop violations in this project, always use:
19
+
20
+ ```bash
21
+ bundle exec rake rubocop_gradual:check
22
+ ```
23
+
24
+ **Do not use** the standard RuboCop commands like:
25
+ - `bundle exec rubocop`
26
+ - `rubocop`
27
+
28
+ ## Understanding the Lock File
29
+
30
+ The `.rubocop_gradual.lock` file tracks all current RuboCop violations in the project. This allows the team to:
31
+
32
+ 1. Prevent new violations while gradually fixing existing ones
33
+ 2. Track progress on code style improvements
34
+ 3. Ensure CI builds don't fail due to pre-existing violations
35
+
36
+ ## Common Commands
37
+
38
+ - **Check violations**
39
+ - `bundle exec rake rubocop_gradual`
40
+ - `bundle exec rake rubocop_gradual:check`
41
+ - **(Safe) Autocorrect violations, and update lockfile if no new violations**
42
+ - `bundle exec rake rubocop_gradual:autocorrect`
43
+ - **Force update the lock file (w/o autocorrect) to match violations present in code**
44
+ - `bundle exec rake rubocop_gradual:force_update`
45
+
46
+ ## Workflow
47
+
48
+ 1. Before submitting a PR, run `bundle exec rake rubocop_gradual:autocorrect`
49
+ a. or just the default `bundle exec rake`, as autocorrection is a pre-requisite of the default task.
50
+ 2. If there are new violations, either:
51
+ - Fix them in your code
52
+ - Run `bundle exec rake rubocop_gradual:force_update` to update the lock file (only for violations you can't fix immediately)
53
+ 3. Commit the updated `.rubocop_gradual.lock` file along with your changes
54
+
55
+ ## Never add inline RuboCop disables
56
+
57
+ Do not add inline `rubocop:disable` / `rubocop:enable` comments anywhere in the codebase (including specs, except when following the few existing `rubocop:disable` patterns for a rule already being disabled elsewhere in the code). We handle exceptions in two supported ways:
58
+
59
+ - Permanent/structural exceptions: prefer adjusting the RuboCop configuration (e.g., in `.rubocop.yml`) to exclude a rule for a path or file pattern when it makes sense project-wide.
60
+ - Temporary exceptions while improving code: record the current violations in `.rubocop_gradual.lock` via the gradual workflow:
61
+ - `bundle exec rake rubocop_gradual:autocorrect` (preferred; will autocorrect what it can and update the lock only if no new violations were introduced)
62
+ - If needed, `bundle exec rake rubocop_gradual:force_update` (as a last resort when you cannot fix the newly reported violations immediately)
63
+
64
+ In general, treat the rules as guidance to follow; fix violations rather than ignore them. For example, RSpec conventions in this project expect `described_class` to be used in specs that target a specific class under test.
65
+
66
+ ## Benefits of rubocop_gradual
67
+
68
+ - Allows incremental adoption of code style rules
69
+ - Prevents CI failures due to pre-existing violations
70
+ - Provides a clear record of code style debt
71
+ - Enables focused efforts on improving code quality over time
data/SECURITY.md CHANGED
@@ -2,13 +2,9 @@
2
2
 
3
3
  ## Supported Versions
4
4
 
5
- | Version | Supported |
6
- |---------|-----------|
7
- | 3.1.x | ✅ |
8
- | 3.0.x | ❌ |
9
- | 2.x | ❌ |
10
- | 1.x | ❌ |
11
- | 0.x | ❌ |
5
+ | Version | Supported |
6
+ |----------|-----------|
7
+ | 3.1.latest | ✅ |
12
8
 
13
9
  ## Security contact information
14
10
 
@@ -18,28 +14,8 @@ Tidelift will coordinate the fix and disclosure.
18
14
 
19
15
  ## Additional Support
20
16
 
21
- Interested in support for versions older than the latest release?
22
- Consider sponsoring the project / maintainer.
17
+ If you are interested in support for versions older than the latest release,
18
+ please consider sponsoring the project / maintainer @ https://liberapay.com/pboling/donate,
19
+ or find other sponsorship links in the [README].
23
20
 
24
- [![Liberapay Goal Progress][⛳liberapay-img]][⛳liberapay] [![Sponsor Me on Github][🖇sponsor-img]][🖇sponsor] [![Buy me a coffee][🖇buyme-small-img]][🖇buyme] [![Donate on Polar][🖇polar-img]][🖇polar] [![Donate to my FLOSS or refugee efforts at ko-fi.com][🖇kofi-img]][🖇kofi] [![Donate to my FLOSS or refugee efforts using Patreon][🖇patreon-img]][🖇patreon]
25
-
26
- [⛳liberapay-img]: https://img.shields.io/liberapay/goal/pboling.svg?logo=liberapay
27
- [⛳liberapay]: https://liberapay.com/pboling/donate
28
- [🖇sponsor-img]: https://img.shields.io/badge/Sponsor_Me!-pboling.svg?style=social&logo=github
29
- [🖇sponsor]: https://github.com/sponsors/pboling
30
- [🖇polar-img]: https://img.shields.io/badge/polar-donate-yellow.svg
31
- [🖇polar]: https://polar.sh/pboling
32
- [🖇kofi-img]: https://img.shields.io/badge/a_more_different_coffee-✓-yellow.svg
33
- [🖇kofi]: https://ko-fi.com/O5O86SNP4
34
- [🖇patreon-img]: https://img.shields.io/badge/patreon-donate-yellow.svg
35
- [🖇patreon]: https://patreon.com/galtzo
36
- [🖇buyme]: https://www.buymeacoffee.com/pboling
37
- [🖇buyme-small-img]: https://img.shields.io/badge/buy_me_a_coffee-✓-yellow.svg?style=flat
38
-
39
- ## Enterprise Support
40
-
41
- Available as part of the Tidelift Subscription.
42
-
43
- The maintainers of this library and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers for the exact packages you use. [Learn more.][tidelift-ref]
44
-
45
- [tidelift-ref]: https://tidelift.com/subscription/pkg/rubygems-omniauth-identity?utm_source=rubygems-omniauth-identity&utm_medium=referral&utm_campaign=enterprise&utm_term=repo
21
+ [README]: README.md
data/certs/pboling.pem ADDED
@@ -0,0 +1,27 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIEgDCCAuigAwIBAgIBATANBgkqhkiG9w0BAQsFADBDMRUwEwYDVQQDDAxwZXRl
3
+ ci5ib2xpbmcxFTATBgoJkiaJk/IsZAEZFgVnbWFpbDETMBEGCgmSJomT8ixkARkW
4
+ A2NvbTAeFw0yNTA1MDQxNTMzMDlaFw00NTA0MjkxNTMzMDlaMEMxFTATBgNVBAMM
5
+ DHBldGVyLmJvbGluZzEVMBMGCgmSJomT8ixkARkWBWdtYWlsMRMwEQYKCZImiZPy
6
+ LGQBGRYDY29tMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAruUoo0WA
7
+ uoNuq6puKWYeRYiZekz/nsDeK5x/0IEirzcCEvaHr3Bmz7rjo1I6On3gGKmiZs61
8
+ LRmQ3oxy77ydmkGTXBjruJB+pQEn7UfLSgQ0xa1/X3kdBZt6RmabFlBxnHkoaGY5
9
+ mZuZ5+Z7walmv6sFD9ajhzj+oIgwWfnEHkXYTR8I6VLN7MRRKGMPoZ/yvOmxb2DN
10
+ coEEHWKO9CvgYpW7asIihl/9GMpKiRkcYPm9dGQzZc6uTwom1COfW0+ZOFrDVBuV
11
+ FMQRPswZcY4Wlq0uEBLPU7hxnCL9nKK6Y9IhdDcz1mY6HZ91WImNslOSI0S8hRpj
12
+ yGOWxQIhBT3fqCBlRIqFQBudrnD9jSNpSGsFvbEijd5ns7Z9ZMehXkXDycpGAUj1
13
+ to/5cuTWWw1JqUWrKJYoifnVhtE1o1DZ+LkPtWxHtz5kjDG/zR3MG0Ula0UOavlD
14
+ qbnbcXPBnwXtTFeZ3C+yrWpE4pGnl3yGkZj9SMTlo9qnTMiPmuWKQDatAgMBAAGj
15
+ fzB9MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQWBBQE8uWvNbPVNRXZ
16
+ HlgPbc2PCzC4bjAhBgNVHREEGjAYgRZwZXRlci5ib2xpbmdAZ21haWwuY29tMCEG
17
+ A1UdEgQaMBiBFnBldGVyLmJvbGluZ0BnbWFpbC5jb20wDQYJKoZIhvcNAQELBQAD
18
+ ggGBAJbnUwfJQFPkBgH9cL7hoBfRtmWiCvdqdjeTmi04u8zVNCUox0A4gT982DE9
19
+ wmuN12LpdajxZONqbXuzZvc+nb0StFwmFYZG6iDwaf4BPywm2e/Vmq0YG45vZXGR
20
+ L8yMDSK1cQXjmA+ZBKOHKWavxP6Vp7lWvjAhz8RFwqF9GuNIdhv9NpnCAWcMZtpm
21
+ GUPyIWw/Cw/2wZp74QzZj6Npx+LdXoLTF1HMSJXZ7/pkxLCsB8m4EFVdb/IrW/0k
22
+ kNSfjtAfBHO8nLGuqQZVH9IBD1i9K6aSs7pT6TW8itXUIlkIUI2tg5YzW6OFfPzq
23
+ QekSkX3lZfY+HTSp/o+YvKkqWLUV7PQ7xh1ZYDtocpaHwgxe/j3bBqHE+CUPH2vA
24
+ 0V/FwdTRWcwsjVoOJTrYcff8pBZ8r2MvtAc54xfnnhGFzeRHfcltobgFxkAXdE6p
25
+ DVjBtqT23eugOqQ73umLcYDZkc36vnqGxUBSsXrzY9pzV5gGr2I8YUxMqf6ATrZt
26
+ L9nRqA==
27
+ -----END CERTIFICATE-----
@@ -1,7 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "auth_sanitizer/loader"
4
+
3
5
  module OmniAuth
4
6
  module Identity
7
+ AUTH_SANITIZER = AuthSanitizer::Loader.load_isolated unless const_defined?(:AUTH_SANITIZER, false)
8
+
5
9
  # This module provides an include-able interface for implementing the
6
10
  # necessary API for OmniAuth Identity to properly locate identities
7
11
  # and provide all necessary information.
@@ -9,22 +13,41 @@ module OmniAuth
9
13
  # All methods marked as abstract must be implemented in the
10
14
  # including class for things to work properly.
11
15
  #
12
- ### Singleton API
16
+ # ### Singleton API
13
17
  #
14
18
  # * locate(key)
15
19
  # * create(*args) - Deprecated in v3.0.5; Will be removed in v4.0
16
20
  #
17
- ### Instance API
21
+ # ### Instance API
18
22
  #
19
23
  # * save
20
24
  # * persisted?
21
25
  # * authenticate(password)
22
26
  #
27
+ # @example Including the Model
28
+ # class User
29
+ # include OmniAuth::Identity::Model
30
+ # # Implement required methods...
31
+ # end
23
32
  module Model
33
+ # @!attribute [r] SCHEMA_ATTRIBUTES
34
+ # Standard OmniAuth schema attributes that may be stored in the model.
35
+ # @return [Array<String>] List of attribute names.
24
36
  SCHEMA_ATTRIBUTES = %w[name email nickname first_name last_name location description image phone].freeze
37
+ FILTERED_INSPECT_ATTRIBUTES = %i[password password_confirmation password_digest].freeze
25
38
 
26
39
  class << self
40
+ # Called when this module is included in a model class.
41
+ #
42
+ # Extends the base class with ClassMethods and includes necessary APIs
43
+ # if they are not already defined.
44
+ #
45
+ # @param base [Class] the model class including this module
46
+ # @return [void]
27
47
  def included(base)
48
+ base.include(OmniAuth::Identity::AUTH_SANITIZER::FilteredAttributes)
49
+ base.prepend(OmniAuth::Identity::AUTH_SANITIZER::FilteredAttributes)
50
+ base.filtered_attributes(*FILTERED_INSPECT_ATTRIBUTES)
28
51
  base.extend(ClassMethods)
29
52
  base.extend(ClassCreateApi) unless base.respond_to?(:create)
30
53
  i_methods = base.instance_methods
@@ -33,12 +56,16 @@ module OmniAuth
33
56
  end
34
57
  end
35
58
 
59
+ # Class-level methods for OmniAuth Identity models.
36
60
  module ClassMethods
61
+ AUTH_KEY_MUTEX = Mutex.new
62
+ private_constant :AUTH_KEY_MUTEX
63
+
37
64
  # Authenticate a user with the given key and password.
38
65
  #
39
66
  # @param [String] conditions The unique login key provided for a given identity.
40
67
  # @param [String] password The presumed password for the identity.
41
- # @return [Model, false] An instance of the identity model class.
68
+ # @return [Model, false] An instance of the identity model class or false if authentication fails.
42
69
  def authenticate(conditions, password)
43
70
  instance = locate(conditions)
44
71
  return false unless instance
@@ -46,19 +73,28 @@ module OmniAuth
46
73
  instance.authenticate(password)
47
74
  end
48
75
 
76
+ def inherited(subclass)
77
+ super if defined?(super)
78
+ subclass.filtered_attributes(*filtered_attribute_names) if subclass.respond_to?(:filtered_attributes)
79
+ end
80
+
49
81
  # Used to set or retrieve the method that will be used to get
50
82
  # and set the user-supplied authentication key.
83
+ #
84
+ # @param method [String, Symbol, false] The method name to set, or false to retrieve.
51
85
  # @return [String] The method name.
52
86
  def auth_key(method = false)
53
- @auth_key = method.to_s unless method == false
54
- @auth_key = nil if !defined?(@auth_key) || @auth_key == ""
87
+ AUTH_KEY_MUTEX.synchronize do
88
+ @auth_key = method.to_s unless method == false
89
+ @auth_key = nil if !defined?(@auth_key) || @auth_key == ""
55
90
 
56
- @auth_key || "email"
91
+ @auth_key || "email"
92
+ end
57
93
  end
58
94
 
59
95
  # Locate an identity given its unique login key.
60
96
  #
61
- # @abstract
97
+ # @abstract Subclasses must implement this method.
62
98
  # @param [String] _key The unique login key.
63
99
  # @return [Model] An instance of the identity model class.
64
100
  def locate(_key)
@@ -66,6 +102,7 @@ module OmniAuth
66
102
  end
67
103
  end
68
104
 
105
+ # Provides a create method for models that don't have one.
69
106
  module ClassCreateApi
70
107
  # Persists a new Identity object to the ORM.
71
108
  # Only included if the class doesn't define create, as a reminder to define create.
@@ -81,6 +118,7 @@ module OmniAuth
81
118
  end
82
119
  end
83
120
 
121
+ # Provides a save method for models that don't have one.
84
122
  module InstanceSaveApi
85
123
  # Persists a new Identity object to the ORM.
86
124
  # Default raises an error. Override as needed per ORM.
@@ -88,6 +126,7 @@ module OmniAuth
88
126
  # since it is a pattern many ORMs follow
89
127
  #
90
128
  # @abstract
129
+ # @param _options [Hash] Options for saving.
91
130
  # @return [Model] An instance of the identity model class.
92
131
  # @since 3.0.5
93
132
  def save(**_options, &_block)
@@ -95,12 +134,13 @@ module OmniAuth
95
134
  end
96
135
  end
97
136
 
137
+ # Provides a persisted? method for models that don't have one.
98
138
  module InstancePersistedApi
99
139
  # Checks if the Identity object is persisted in the ORM.
100
140
  # Default raises an error. Override as needed per ORM.
101
141
  #
102
142
  # @abstract
103
- # @return [true or false] true if object exists, false if not.
143
+ # @return [true, false] true if object exists, false if not.
104
144
  # @since 3.0.5
105
145
  def persisted?
106
146
  raise NotImplementedError
@@ -110,9 +150,9 @@ module OmniAuth
110
150
  # Returns self if the provided password is correct, false
111
151
  # otherwise.
112
152
  #
113
- # @abstract
153
+ # @abstract Subclasses must implement this method.
114
154
  # @param [String] _password The password to check.
115
- # @return [self or false] Self if authenticated, false if not.
155
+ # @return [self, false] Self if authenticated, false if not.
116
156
  def authenticate(_password)
117
157
  raise NotImplementedError
118
158
  end
@@ -152,7 +192,7 @@ module OmniAuth
152
192
  # @param [String] value The value to which the auth key should be
153
193
  # set.
154
194
  def auth_key=(value)
155
- auth_key_setter = "#{self.class.auth_key}=".to_sym
195
+ auth_key_setter = :"#{self.class.auth_key}="
156
196
  if respond_to?(auth_key_setter)
157
197
  send(auth_key_setter, value)
158
198
  else
@@ -6,8 +6,34 @@ module OmniAuth
6
6
  module Identity
7
7
  module Models
8
8
  # ActiveRecord is an ORM for MySQL, PostgreSQL, and SQLite3:
9
- # https://guides.rubyonrails.org/active_record_basics.html
10
- # NOTE: ActiveRecord is based on ActiveModel.
9
+ # https://guides.rubyonrails.org/active_record_basics.html
10
+ #
11
+ # This class provides a base for OmniAuth Identity models using ActiveRecord,
12
+ # including secure password handling and authentication key management.
13
+ #
14
+ # @example Usage
15
+ # class User < OmniAuth::Identity::Models::ActiveRecord
16
+ # # Add your fields here, e.g.:
17
+ # # self.table_name = 'users'
18
+ # # has_many :posts
19
+ # end
20
+ #
21
+ # # Migration example:
22
+ # # create_table :users do |t|
23
+ # # t.string :email, null: false
24
+ # # t.string :password_digest, null: false
25
+ # # t.timestamps
26
+ # # end
27
+ #
28
+ # user = User.new(email: 'user@example.com', password: 'password')
29
+ # user.save
30
+ #
31
+ # # Authenticate a user
32
+ # authenticated_user = User.locate(email: 'user@example.com')
33
+ # authenticated_user.authenticate('password') # => user or false
34
+ #
35
+ # @note ActiveRecord is based on ActiveModel, so validations are enabled by default.
36
+ # @note This is an abstract class; inherit from it to create your user model.
11
37
  class ActiveRecord < ::ActiveRecord::Base
12
38
  include ::OmniAuth::Identity::Model
13
39
  include ::OmniAuth::Identity::SecurePassword
@@ -16,14 +42,34 @@ module OmniAuth
16
42
  # validations: true (default) incurs a dependency on ActiveModel, but ActiveRecord is ActiveModel based.
17
43
  has_secure_password
18
44
 
19
- def self.auth_key=(key)
20
- super
21
- validates_uniqueness_of(key, case_sensitive: false)
22
- end
45
+ # @!method self.auth_key=(key)
46
+ # Sets the authentication key for the model and adds uniqueness validation.
47
+ #
48
+ # @param key [Symbol, String] the attribute to use as the authentication key
49
+ # @return [void]
50
+ # @example
51
+ # class User < OmniAuth::Identity::Models::ActiveRecord
52
+ # self.auth_key = :email
53
+ # end
54
+ class << self
55
+ def auth_key=(key)
56
+ super
57
+ validates_uniqueness_of(key, case_sensitive: false)
58
+ end
23
59
 
24
- def self.locate(search_hash)
25
- search_hash = search_hash.reverse_merge!("provider" => "identity") if column_names.include?("provider")
26
- where(search_hash).first
60
+ # @!method self.locate(search_hash)
61
+ # Finds a record by the given search criteria.
62
+ #
63
+ # If the model has a 'provider' column, it defaults to 'identity'.
64
+ #
65
+ # @param search_hash [Hash] the attributes to search for
66
+ # @return [ActiveRecord::Base, nil] the first matching record or nil
67
+ # @example
68
+ # User.locate(email: 'user@example.com')
69
+ def locate(search_hash)
70
+ search_hash = search_hash.reverse_merge!("provider" => "identity") if column_names.include?("provider")
71
+ where(search_hash).first
72
+ end
27
73
  end
28
74
  end
29
75
  end
@@ -6,30 +6,86 @@ module OmniAuth
6
6
  module Identity
7
7
  module Models
8
8
  # CouchPotato is an ORM adapter for CouchDB:
9
- # https://github.com/langalex/couch_potato
10
- # NOTE: CouchPotato is based on ActiveModel.
11
- # NOTE: CouchPotato::Persistence must be included before OmniAuth::Identity::Models::CouchPotatoModule
12
- # NOTE: Includes "Module" in the name for invalid legacy reasons. Rename only with a major version bump.
9
+ # https://github.com/langalex/couch_potato
10
+ #
11
+ # This module provides OmniAuth Identity functionality for CouchPotato models,
12
+ # including secure password handling and authentication key management.
13
+ #
14
+ # @example Usage
15
+ # class User
16
+ # include CouchPotato::Persistence
17
+ #
18
+ # include OmniAuth::Identity::Models::CouchPotatoModule
19
+ #
20
+ # property :email
21
+ # property :password_digest
22
+ # end
23
+ #
24
+ # user = User.new(email: 'user@example.com', password: 'password')
25
+ # user.save
26
+ #
27
+ # # Authenticate a user
28
+ # authenticated_user = User.locate(email: 'user@example.com')
29
+ # authenticated_user.authenticate('password') # => user or false
30
+ #
31
+ # @note CouchPotato is based on ActiveModel, so validations are enabled by default.
32
+ # @note CouchPotato::Persistence must be included before OmniAuth::Identity::Models::CouchPotatoModule.
33
+ # @note Includes "Module" in the name for invalid legacy reasons. Rename only with a major version bump.
13
34
  module CouchPotatoModule
14
- def self.included(base)
15
- base.class_eval do
16
- include(::OmniAuth::Identity::Model)
17
- include(::OmniAuth::Identity::SecurePassword)
35
+ class << self
36
+ # Called when this module is included in a model class.
37
+ #
38
+ # This method extends the base class with OmniAuth Identity functionality,
39
+ # including secure password support and authentication key validation.
40
+ #
41
+ # @param base [Class] the model class including this module
42
+ # @return [void]
43
+ def included(base)
44
+ base.class_eval do
45
+ include(::OmniAuth::Identity::Model)
46
+ include(::OmniAuth::Identity::SecurePassword)
18
47
 
19
- # validations: true (default) incurs a dependency on ActiveModel, but CouchPotato is ActiveModel based.
20
- has_secure_password
48
+ # validations: true (default) incurs a dependency on ActiveModel, but CouchPotato is ActiveModel based.
49
+ has_secure_password
21
50
 
22
- def self.auth_key=(key)
23
- super
24
- validates_uniqueness_of(key, case_sensitive: false)
25
- end
51
+ class << self
52
+ # @!method self.auth_key=(key)
53
+ # Sets the authentication key for the model and adds uniqueness validation.
54
+ #
55
+ # @param key [Symbol, String] the attribute to use as the authentication key
56
+ # @return [void]
57
+ # @example
58
+ # class User
59
+ # include OmniAuth::Identity::Models::CouchPotatoModule
60
+ # self.auth_key = :email
61
+ # end
62
+ def auth_key=(key)
63
+ super
64
+ validates_uniqueness_of(key, case_sensitive: false)
65
+ end
26
66
 
27
- def self.locate(search_hash)
28
- where(search_hash).first
29
- end
67
+ # @!method self.locate(search_hash)
68
+ # Finds a record by the given search criteria.
69
+ #
70
+ # @param search_hash [Hash] the attributes to search for
71
+ # @return [Object, nil] the first matching record or nil
72
+ # @example
73
+ # User.locate(email: 'user@example.com')
74
+ def locate(search_hash)
75
+ where(search_hash).first
76
+ end
77
+ end
30
78
 
31
- def save
32
- CouchPotato.database.save_document(self)
79
+ # @!method save
80
+ # Saves the document to the CouchDB database.
81
+ #
82
+ # @return [Boolean] true if saved successfully, false otherwise
83
+ # @example
84
+ # user = User.new(email: 'user@example.com', password: 'password')
85
+ # user.save # => true
86
+ def save
87
+ CouchPotato.database.save_document(self)
88
+ end
33
89
  end
34
90
  end
35
91
  end
@@ -6,24 +6,73 @@ module OmniAuth
6
6
  module Identity
7
7
  module Models
8
8
  # Mongoid is an ORM adapter for MongoDB:
9
- # https://github.com/mongodb/mongoid
10
- # NOTE: Mongoid is based on ActiveModel.
9
+ # https://github.com/mongodb/mongoid
10
+ #
11
+ # This module provides OmniAuth Identity functionality for Mongoid models,
12
+ # including secure password handling and authentication key management.
13
+ #
14
+ # @example Usage
15
+ # class User
16
+ # include Mongoid::Document
17
+ #
18
+ # include OmniAuth::Identity::Models::Mongoid
19
+ #
20
+ # field :email, type: String
21
+ # field :password_digest, type: String
22
+ # end
23
+ #
24
+ # user = User.new(email: 'user@example.com', password: 'password')
25
+ # user.save
26
+ #
27
+ # # Authenticate a user
28
+ # authenticated_user = User.locate(email: 'user@example.com')
29
+ # authenticated_user.authenticate('password') # => user or false
30
+ #
31
+ # @note Mongoid is based on ActiveModel, so validations are enabled by default.
11
32
  module Mongoid
12
- def self.included(base)
13
- base.class_eval do
14
- include(::OmniAuth::Identity::Model)
15
- include(::OmniAuth::Identity::SecurePassword)
33
+ class << self
34
+ # Called when this module is included in a model class.
35
+ #
36
+ # This method extends the base class with OmniAuth Identity functionality,
37
+ # including secure password support and authentication key validation.
38
+ #
39
+ # @param base [Class] the model class including this module
40
+ # @return [void]
41
+ def included(base)
42
+ base.class_eval do
43
+ include(::OmniAuth::Identity::Model)
44
+ include(::OmniAuth::Identity::SecurePassword)
16
45
 
17
- # validations: true (default) incurs a dependency on ActiveModel, but Mongoid is ActiveModel based.
18
- has_secure_password
46
+ # validations: true (default) incurs a dependency on ActiveModel, but Mongoid is ActiveModel based.
47
+ has_secure_password
19
48
 
20
- def self.auth_key=(key)
21
- super
22
- validates_uniqueness_of(key, case_sensitive: false)
23
- end
49
+ class << self
50
+ # @!method self.auth_key=(key)
51
+ # Sets the authentication key for the model and adds uniqueness validation.
52
+ #
53
+ # @param key [Symbol, String] the attribute to use as the authentication key
54
+ # @return [void]
55
+ # @example
56
+ # class User
57
+ # include OmniAuth::Identity::Models::Mongoid
58
+ # self.auth_key = :email
59
+ # end
60
+ def auth_key=(key)
61
+ super
62
+ validates_uniqueness_of(key, case_sensitive: false)
63
+ end
24
64
 
25
- def self.locate(search_hash)
26
- where(search_hash).first
65
+ # @!method self.locate(search_hash)
66
+ # Finds a record by the given search criteria.
67
+ #
68
+ # @param search_hash [Hash] the attributes to search for
69
+ # @return [Mongoid::Document, nil] the first matching record or nil
70
+ # @example
71
+ # User.locate(email: 'user@example.com')
72
+ def locate(search_hash)
73
+ where(search_hash).first
74
+ end
75
+ end
27
76
  end
28
77
  end
29
78
  end