verify_it 0.2.0 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ede88092d9b66d9853d5f03713b719f1bc664eefdfe0cc245140494110bda8a8
4
- data.tar.gz: 1da02a88fc2c6262c6386eaac4f63184dad9bfebbd9bb694762a0e050f416aa3
3
+ metadata.gz: 9c975ad8c3016c930d9b8071d4f6c21fef89eece05332a48c5b1ebfebebf7386
4
+ data.tar.gz: 40adb101cba36f8cb6b1c89f81977558e4d21ae0de87a93333a70e3bf92006d1
5
5
  SHA512:
6
- metadata.gz: 584f310188b429e0e6d77b9ca6c89cd0042b97bae8809b4ae8fad8699863666184fbbdf059c77eaabc5610d37d9355fffbbf9cd238056a06acc83626955f955e
7
- data.tar.gz: 41394cf8edff07829dab5beecd3a4d723e8aaa1b89a6e8910095a77f1af3335a1f9988a56c92d5d77585aec2f23e4d683ca1f9ded3e494a2a0f938fc18417e41
6
+ metadata.gz: e4b862df0a1be371deb7fa9ea1d4eb2ed85da2f83852771a3efd52156187cf0c7a5057c162cd5e6e04ab5f6c88571c3fa6bc9c4d0427f901a7f4dbf5f23b6fe9
7
+ data.tar.gz: af94994c116729b2f0670b1664618ac1c01877755996ae00bd2b97069292fba1c0b2ef48d73f91a48d2c5653c2b49d5fc500a40c3a37e1cf304c77d7cf9d852c
data/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.3.0] - 2026-03-03
4
+
5
+ ### Security
6
+ - Verification codes are now hashed with HMAC-SHA256 before storage; a compromised storage backend no longer exposes usable codes
7
+ - New required configuration: `secret_key_base` — must be set to a random secret in your initializer
8
+
9
+ ### Added
10
+ - `VerifyIt::CodeHasher` module for HMAC-SHA256 code digesting (stdlib `openssl` only — no new dependencies)
11
+ - `config.secret_key_base` configuration option
12
+
3
13
  ## [0.1.1] - 2026-03-02
4
14
 
5
15
  ### Fixed
data/README.md CHANGED
@@ -15,393 +15,285 @@ VerifyIt provides a flexible framework for implementing SMS and email verificati
15
15
 
16
16
  ## Installation
17
17
 
18
- Add this line to your application's Gemfile:
18
+ Add to your Gemfile:
19
19
 
20
20
  ```ruby
21
21
  gem 'verify_it'
22
22
  ```
23
23
 
24
- And then execute:
25
-
26
24
  ```bash
27
25
  bundle install
28
26
  ```
29
27
 
30
- Or install it yourself as:
31
-
32
- ```bash
33
- gem install verify_it
34
- ```
35
-
36
- ### Rails Installation
28
+ ## Rails Setup
37
29
 
38
- For Rails applications, use the installer to generate configuration files:
30
+ ### 1. Generate configuration files
39
31
 
40
32
  ```bash
41
33
  bundle exec verify_it install
42
34
  ```
43
35
 
44
- This will:
45
- 1. Prompt you to select a storage backend (Memory, Redis, or Database)
46
- 2. Generate an initializer at `config/initializers/verify_it.rb`
47
- 3. Generate a migration (if Database storage is selected)
36
+ The installer will ask you to choose a storage backend and generate:
37
+
38
+ - `config/initializers/verify_it.rb` — your main configuration
39
+ - A database migration (if you chose Database storage)
48
40
 
49
- If you selected Database storage, run the migration:
41
+ If you chose Database storage, run:
50
42
 
51
43
  ```bash
52
44
  rails db:migrate
53
45
  ```
54
46
 
55
- # Quick Start
47
+ ### 2. Configure the initializer
56
48
 
57
- ## Rails Integration
49
+ Open `config/initializers/verify_it.rb` and fill in your delivery lambdas.
58
50
 
59
- VerifyIt automatically integrates with Rails when detected.
60
-
61
- ### Model Integration
51
+ **Redis + Twilio example:**
62
52
 
63
53
  ```ruby
64
- class User < ApplicationRecord
65
- include VerifyIt::Verifiable
66
-
67
- verifies :phone_number, channel: :sms
68
- verifies :email, channel: :email
69
- end
70
-
71
- # Usage
72
- user = User.find(params[:id])
73
-
74
- # Send code (no context needed)
75
- result = user.send_sms_code
76
-
77
- # Send with custom message template
78
- result = user.send_sms_code(context: {
79
- message_template: "Your #{user.company_name} verification code is: %{code}"
80
- })
81
-
82
- # Send with tracking metadata
83
- result = user.send_email_code(context: {
84
- ip: request.ip,
85
- user_agent: request.user_agent,
86
- action: 'password_reset'
87
- })
88
-
89
- # Verify code
90
- result = user.verify_sms_code(params[:code])
91
-
92
- # Cleanup
93
- user.cleanup_sms_verification
94
- ```
95
-
96
- ### Rails Configuration
54
+ VerifyIt.configure do |config|
55
+ config.secret_key_base = Rails.application.secret_key_base
97
56
 
98
- Create an initializer `config/initializers/verify_it.rb`:
57
+ config.storage = :redis
58
+ config.redis_client = Redis.new(url: ENV["REDIS_URL"])
99
59
 
100
- ```ruby
101
- VerifyIt.configure do |config|
102
- config.storage = :redis
103
- config.redis_client = Redis.new(url: ENV['REDIS_URL'])
104
-
105
60
  config.sms_sender = ->(to:, code:, context:) {
106
- TwilioService.send_sms(to: to, body: "Your code is: #{code}")
61
+ Twilio::REST::Client.new.messages.create(
62
+ from: ENV["TWILIO_NUMBER"],
63
+ to: to,
64
+ body: "Your verification code is: #{code}"
65
+ )
107
66
  }
108
-
109
- config.test_mode = Rails.env.test?
67
+
68
+ config.test_mode = Rails.env.test?
110
69
  config.bypass_delivery = Rails.env.test?
111
70
  end
112
71
  ```
113
72
 
114
- ## Plain Ruby Configuration
73
+ ### 3. Add `Verifiable` to your model
115
74
 
116
75
  ```ruby
117
- require 'verify_it'
76
+ class User < ApplicationRecord
77
+ include VerifyIt::Verifiable
118
78
 
119
- VerifyIt.configure do |config|
120
- # Storage backend
121
- config.storage = :memory # or :redis, :database
122
-
123
- # For Redis storage
124
- # config.redis_client = Redis.new(url: ENV['REDIS_URL'])
125
-
126
- # Code settings
127
- config.code_length = 6
128
- config.code_ttl = 300 # 5 minutes
129
- config.code_format = :numeric # or :alphanumeric, :alpha
130
-
131
- # Rate limiting
132
- config.max_send_attempts = 3
133
- config.max_verification_attempts = 5
134
- config.max_identifier_changes = 5
135
- config.rate_limit_window = 3600 # 1 hour
136
-
137
- # Delivery (SMS example with Twilio)
138
- config.sms_sender = ->(to:, code:, context:) {
139
- # Use custom template from context, or default
140
- message = if context[:message_template]
141
- context[:message_template] % { code: code }
142
- else
143
- "Your verification code is: #{code}"
144
- end
145
-
146
- twilio_client.messages.create(
147
- to: to,
148
- from: '+15551234567',
149
- body: message
150
- )
151
- }
152
-
153
- # Email delivery
154
- config.email_sender = ->(to:, code:, context:) {
155
- # Context available for customization
156
- UserMailer.verification_code(to, code, context).deliver_now
157
- }
79
+ verifies :phone_number # defaults to channel: :sms
80
+ verifies :email, channel: :email
158
81
  end
159
82
  ```
160
83
 
161
- ### Sending a Verification Code
84
+ This generates the following methods on `User`:
162
85
 
163
- ```ruby
164
- result = VerifyIt.send_code(
165
- to: "+15551234567",
166
- record: current_user,
167
- channel: :sms,
168
- context: { user_id: current_user.id }
169
- )
170
-
171
- if result.success?
172
- puts "Code sent successfully!"
173
- puts "Expires at: #{result.expires_at}"
174
- else
175
- puts "Error: #{result.message}"
176
- puts "Rate limited!" if result.rate_limited?
177
- end
178
- ```
86
+ | Method | Description |
87
+ |---|---|
88
+ | `send_sms_code` | Send a code to `phone_number` via SMS |
89
+ | `send_email_code` | Send a code to `email` via email |
90
+ | `verify_sms_code(code)` | Verify an SMS code |
91
+ | `verify_email_code(code)` | Verify an email code |
92
+ | `cleanup_sms_verification` | Remove stored verification data |
93
+ | `cleanup_email_verification` | Remove stored verification data |
94
+
95
+ ### 4. Use it in your controllers
179
96
 
180
- ### Verifying a Code
97
+ **Sending a code:**
181
98
 
182
99
  ```ruby
183
- result = VerifyIt.verify_code(
184
- to: "+15551234567",
185
- code: params[:code],
186
- record: current_user
187
- )
188
-
189
- if result.verified?
190
- # Success! Code is valid
191
- session[:verified] = true
192
- redirect_to dashboard_path
193
- elsif result.locked?
194
- # Too many failed attempts
195
- flash[:error] = "Account locked due to too many attempts"
196
- elsif result.success? == false
197
- # Invalid code
198
- flash[:error] = "Invalid verification code. #{5 - result.attempts} attempts remaining"
100
+ class VerificationsController < ApplicationController
101
+ def create
102
+ result = current_user.send_sms_code
103
+
104
+ if result.success?
105
+ render json: { expires_at: result.expires_at }
106
+ elsif result.rate_limited?
107
+ render json: { error: "Too many requests" }, status: :too_many_requests
108
+ else
109
+ render json: { error: result.message }, status: :unprocessable_entity
110
+ end
111
+ end
199
112
  end
200
113
  ```
201
114
 
202
- ### Cleanup
115
+ **Verifying a code:**
203
116
 
204
117
  ```ruby
205
- # Clean up verification data for a user
206
- VerifyIt.cleanup(
207
- to: "+15551234567",
208
- record: current_user
209
- )
118
+ class VerificationsController < ApplicationController
119
+ def update
120
+ result = current_user.verify_sms_code(params[:code])
121
+
122
+ if result.verified?
123
+ session[:phone_verified] = true
124
+ render json: { verified: true }
125
+ elsif result.locked?
126
+ render json: { error: "Too many failed attempts. Try again later." }, status: :locked
127
+ else
128
+ remaining = VerifyIt.configuration.max_verification_attempts - result.attempts
129
+ render json: { error: "Invalid code. #{remaining} attempts remaining." }, status: :unprocessable_entity
130
+ end
131
+ end
132
+ end
210
133
  ```
211
134
 
212
- ## Configuration Options
213
-
214
- ### Storage Backends
135
+ ### Passing context
215
136
 
216
- #### Memory Storage (Default)
217
- Perfect for testing and development:
137
+ Both `send_*` methods accept an optional `context:` hash that is forwarded to your sender lambda. Use it for custom message templates or request metadata:
218
138
 
219
139
  ```ruby
220
- config.storage = :memory
221
- ```
222
-
223
- #### Redis Storage
224
- Recommended for production:
140
+ current_user.send_sms_code(context: {
141
+ message_template: "Your Acme login code: %{code}"
142
+ })
225
143
 
226
- ```ruby
227
- config.storage = :redis
228
- config.redis_client = Redis.new(url: ENV['REDIS_URL'])
144
+ current_user.send_email_code(context: {
145
+ ip: request.ip,
146
+ user_agent: request.user_agent
147
+ })
229
148
  ```
230
149
 
231
- #### Database Storage
232
- Uses ActiveRecord models for persistent storage:
150
+ ---
151
+
152
+ ## Plain Ruby
233
153
 
234
154
  ```ruby
235
- config.storage = :database
236
- ```
155
+ require "verify_it"
237
156
 
238
- Requires running the migration:
157
+ VerifyIt.configure do |config|
158
+ config.secret_key_base = ENV.fetch("VERIFY_IT_SECRET")
159
+ config.storage = :memory # :memory, :redis, or :database
239
160
 
240
- ```bash
241
- bundle exec verify_it install
242
- rails db:migrate
243
- ```
161
+ config.sms_sender = ->(to:, code:, context:) {
162
+ MySmsSender.deliver(to: to, body: "Your code: #{code}")
163
+ }
164
+ end
244
165
 
245
- Creates three tables:
246
- - `verify_it_codes` - Stores verification codes
247
- - `verify_it_attempts` - Tracks verification and send attempts
248
- - `verify_it_identifier_changes` - Tracks identifier change history
166
+ # Send a code
167
+ result = VerifyIt.send_code(to: "+15551234567", channel: :sms, record: current_user)
249
168
 
250
- ### Code Settings
169
+ # Verify a code
170
+ result = VerifyIt.verify_code(to: "+15551234567", code: "123456", record: current_user)
251
171
 
252
- ```ruby
253
- config.code_length = 6 # Length of verification code
254
- config.code_ttl = 300 # Time-to-live in seconds (5 minutes)
255
- config.code_format = :numeric # :numeric, :alphanumeric, or :alpha
172
+ # Clean up
173
+ VerifyIt.cleanup(to: "+15551234567", record: current_user)
256
174
  ```
257
175
 
258
- ### Rate Limiting
259
-
260
- ```ruby
261
- config.max_send_attempts = 3 # Max sends per window
262
- config.max_verification_attempts = 5 # Max verification tries per window
263
- config.max_identifier_changes = 5 # Max identifier changes per window
264
- config.rate_limit_window = 3600 # Window duration in seconds
265
- ```
176
+ ---
177
+
178
+ ## Configuration Reference
179
+
180
+ | Option | Default | Accepted values |
181
+ |---|---|---|
182
+ | `secret_key_base` | `nil` | Any string — **required** |
183
+ | `storage` | `:memory` | `:memory`, `:redis`, `:database` |
184
+ | `redis_client` | `nil` | A `Redis` instance (required when `storage: :redis`) |
185
+ | `code_length` | `6` | Integer |
186
+ | `code_ttl` | `300` | Seconds (integer) |
187
+ | `code_format` | `:numeric` | `:numeric`, `:alphanumeric`, `:alpha` |
188
+ | `max_send_attempts` | `3` | Integer |
189
+ | `max_verification_attempts` | `5` | Integer |
190
+ | `max_identifier_changes` | `5` | Integer |
191
+ | `rate_limit_window` | `3600` | Seconds (integer) |
192
+ | `sms_sender` | `nil` | Lambda `(to:, code:, context:) { }` |
193
+ | `email_sender` | `nil` | Lambda `(to:, code:, context:) { }` |
194
+ | `on_send` | `nil` | Lambda `(record:, identifier:, channel:) { }` |
195
+ | `on_verify_success` | `nil` | Lambda `(record:, identifier:) { }` |
196
+ | `on_verify_failure` | `nil` | Lambda `(record:, identifier:, attempts:) { }` |
197
+ | `namespace` | `nil` | Lambda `(record) { }` returning a string or nil |
198
+ | `test_mode` | `false` | Boolean — exposes `result.code` |
199
+ | `bypass_delivery` | `false` | Boolean — skips actual delivery |
266
200
 
267
201
  ### Callbacks
268
202
 
269
- Hook into the verification lifecycle:
270
-
271
203
  ```ruby
272
204
  config.on_send = ->(record:, identifier:, channel:) {
273
- Analytics.track('verification_sent', user_id: record.id)
205
+ Analytics.track("verification_sent", user_id: record.id, channel: channel)
274
206
  }
275
207
 
276
208
  config.on_verify_success = ->(record:, identifier:) {
277
- Analytics.track('verification_success', user_id: record.id)
209
+ Analytics.track("verification_success", user_id: record.id)
278
210
  }
279
211
 
280
212
  config.on_verify_failure = ->(record:, identifier:, attempts:) {
281
- Analytics.track('verification_failure', user_id: record.id, attempts: attempts)
213
+ Analytics.track("verification_failure", user_id: record.id, attempts: attempts)
282
214
  }
283
215
  ```
284
216
 
285
217
  ### Namespacing
286
218
 
287
- Isolate verification data by tenant or organization:
219
+ Isolate verification data per tenant:
288
220
 
289
221
  ```ruby
290
- config.namespace = ->(record) {
291
- record.respond_to?(:organization_id) ? "org:#{record.organization_id}" : nil
292
- }
222
+ config.namespace = ->(record) { "org:#{record.organization_id}" }
293
223
  ```
294
224
 
295
- ### Test Mode
225
+ ---
296
226
 
297
- Expose codes in test environment:
227
+ ## Result Object
298
228
 
299
- ```ruby
300
- config.test_mode = true # Includes code in Result object
301
- config.bypass_delivery = true # Skip actual delivery
302
- ```
229
+ Every operation returns a `VerifyIt::Result`:
303
230
 
304
- ## Result Object API
231
+ | Method | Type | Description |
232
+ |---|---|---|
233
+ | `success?` | Boolean | Operation completed without error |
234
+ | `verified?` | Boolean | Code matched successfully |
235
+ | `rate_limited?` | Boolean | Rate limit was exceeded |
236
+ | `locked?` | Boolean | Max verification attempts reached |
237
+ | `error` | Symbol | `:invalid_code`, `:rate_limited`, `:code_not_found`, `:locked`, `:delivery_failed` |
238
+ | `message` | String | Human-readable description |
239
+ | `code` | String | The verification code (only when `test_mode: true`) |
240
+ | `expires_at` | Time | When the code expires |
241
+ | `attempts` | Integer | Number of verification attempts so far |
305
242
 
306
- All operations return a `VerifyIt::Result` object:
307
-
308
- ```ruby
309
- result.success? # true if operation succeeded
310
- result.verified? # true if code was verified successfully
311
- result.locked? # true if max attempts exceeded
312
- result.rate_limited? # true if rate limit hit
313
- result.error # Symbol error code (:invalid_code, :rate_limited, etc.)
314
- result.message # Human-readable message
315
- result.code # Verification code (only in test_mode)
316
- result.expires_at # Time when code expires
317
- result.attempts # Number of verification attempts
318
- ```
243
+ ---
319
244
 
320
245
  ## Testing
321
246
 
322
- ### RSpec Example
247
+ Configure VerifyIt in your spec helper to avoid real delivery and expose codes:
323
248
 
324
249
  ```ruby
325
- RSpec.describe "Phone Verification", type: :request do
326
- before do
327
- VerifyIt.configure do |config|
328
- config.storage = :memory
329
- config.test_mode = true
330
- config.bypass_delivery = true
250
+ # spec/support/verify_it.rb
251
+ RSpec.configure do |config|
252
+ config.before(:each) do
253
+ VerifyIt.configure do |c|
254
+ c.storage = :memory
255
+ c.test_mode = true
256
+ c.bypass_delivery = true
257
+ c.secret_key_base = "test_secret"
331
258
  end
332
259
  end
333
-
334
- it "verifies phone number" do
335
- post '/verify/send', params: { phone: '+15551234567' }
336
-
337
- # Get code from response (test mode)
338
- code = JSON.parse(response.body)['code']
339
-
340
- post '/verify/confirm', params: { phone: '+15551234567', code: code }
341
- expect(response).to have_http_status(:success)
342
- end
343
260
  end
344
261
  ```
345
262
 
346
- ## Thread Safety
263
+ In a request spec:
347
264
 
348
- VerifyIt is designed to be thread-safe:
349
-
350
- - Memory storage uses `Mutex` for synchronization
351
- - Redis operations are atomic
352
- - No shared mutable state in core logic
353
-
354
- ## Performance Considerations
355
-
356
- ### Redis Storage
357
- - Uses key expiration for TTL
358
- - Sorted sets for identifier tracking
359
- - Atomic operations for counters
360
-
361
- ### Memory Storage
362
- - Fast for testing and development
363
- - Not recommended for production
364
- - Data lost on restart
265
+ ```ruby
266
+ it "verifies phone number" do
267
+ post "/verify/send", params: { phone: "+15551234567" }
268
+ code = JSON.parse(response.body)["code"] # available in test_mode
365
269
 
366
- ## Error Handling
270
+ post "/verify/confirm", params: { phone: "+15551234567", code: code }
271
+ expect(response).to have_http_status(:ok)
272
+ end
273
+ ```
367
274
 
368
- VerifyIt uses explicit error states in Result objects:
275
+ ---
369
276
 
370
- - `:rate_limited` - Rate limit exceeded
371
- - `:invalid_code` - Code doesn't match
372
- - `:code_not_found` - No code stored or expired
373
- - `:locked` - Max attempts reached
374
- - `:delivery_failed` - Delivery provider error
277
+ ## Security
375
278
 
376
- ## Security Best Practices
279
+ - **`secret_key_base` is required** — codes are hashed with HMAC-SHA256 before storage
280
+ - Enable rate limiting (on by default) in all environments
281
+ - Use `:redis` or `:database` storage in production (`:memory` does not survive restarts)
282
+ - Keep `code_ttl` short — 5 minutes is a sensible default
283
+ - Use `on_verify_failure` to monitor and alert on repeated failures
284
+ - Always serve verification endpoints over HTTPS
377
285
 
378
- 1. **Always use rate limiting** in production
379
- 2. **Use Redis storage** for distributed systems
380
- 3. **Set short TTLs** (5 minutes recommended)
381
- 4. **Monitor failed attempts** via callbacks
382
- 5. **Use HTTPS** for all verification endpoints
383
- 6. **Sanitize phone numbers** before storage
286
+ ---
384
287
 
385
288
  ## Development
386
289
 
387
- After checking out the repo:
388
-
389
290
  ```bash
390
- bin/setup # Install dependencies
391
- bundle exec rspec # Run tests
392
- bin/console # Interactive console
393
- bundle exec rake build # Build gem
291
+ bin/setup # Install dependencies
292
+ bundle exec rspec # Run tests
293
+ bundle exec rubocop # Lint
294
+ bin/console # Interactive console
394
295
  ```
395
296
 
396
- ## Roadmap
397
-
398
- - [x] Database storage adapter
399
- - [ ] Voice verification support
400
- - [ ] WebAuthn integration
401
- - [ ] Backup code generation
402
- - [ ] Multi-factor authentication helpers
403
- - [x] Rails installer (CLI)
404
-
405
297
  ## Contributing
406
298
 
407
299
  Bug reports and pull requests are welcome on GitHub at https://github.com/JeremasPosta/verify_it. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/JeremasPosta/verify_it/blob/main/CODE_OF_CONDUCT.md).
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openssl"
4
+
5
+ module VerifyIt
6
+ # Hashes verification codes with HMAC-SHA256 before storage.
7
+ #
8
+ # Using a secret key makes offline brute-force of the small OTP keyspace
9
+ # infeasible even if the storage layer is compromised.
10
+ module CodeHasher
11
+ # @param code [String] the plaintext verification code
12
+ # @param secret [String] the HMAC secret (config.secret_key_base)
13
+ # @return [String] hex-encoded HMAC-SHA256 digest
14
+ # @raise [ArgumentError] if secret is nil or empty
15
+ def self.digest(code, secret:)
16
+ if secret.nil? || secret.to_s.empty?
17
+ raise ArgumentError,
18
+ "VerifyIt requires secret_key_base to be configured. " \
19
+ "Set config.secret_key_base in your initializer."
20
+ end
21
+
22
+ OpenSSL::HMAC.hexdigest("SHA256", secret.to_s, code.to_s)
23
+ end
24
+ end
25
+ end
@@ -19,7 +19,8 @@ module VerifyIt
19
19
  :on_verify_failure,
20
20
  :namespace,
21
21
  :test_mode,
22
- :bypass_delivery
22
+ :bypass_delivery,
23
+ :secret_key_base
23
24
 
24
25
  def initialize
25
26
  # Default values
@@ -41,6 +42,7 @@ module VerifyIt
41
42
  @namespace = nil
42
43
  @test_mode = false
43
44
  @bypass_delivery = false
45
+ @secret_key_base = nil
44
46
  end
45
47
  end
46
48
  end
@@ -1,6 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  VerifyIt.configure do |config|
4
+ # Required: set a secret key to hash verification codes before storage.
5
+ # It is not required to use the Rails secret key base.
6
+ config.secret_key_base = Rails.application.secret_key_base
7
+
4
8
  <% if storage_type == "redis" %>
5
9
  config.storage = :redis
6
10
  config.redis_client = Redis.new(url: ENV.fetch("REDIS_URL", "redis://localhost:6379/0"))
@@ -19,7 +23,7 @@ VerifyIt.configure do |config|
19
23
  # e.g. Twilio, Vonage, etc.
20
24
  }
21
25
 
22
- # Optional overrides (sensible defaults are set automatically):
26
+ # Some other config options (with defaults):
23
27
  # config.code_length = 6
24
28
  # config.code_ttl = 300
25
29
  # config.code_format = :numeric
@@ -41,11 +41,12 @@ module VerifyIt
41
41
  )
42
42
  expires_at = Time.now + VerifyIt.configuration.code_ttl
43
43
 
44
- # Store code
44
+ # Store hashed code
45
+ hashed_code = CodeHasher.digest(code, secret: VerifyIt.configuration.secret_key_base)
45
46
  storage.store_code(
46
47
  identifier: to,
47
48
  record: record,
48
- code: code,
49
+ code: hashed_code,
49
50
  expires_at: expires_at
50
51
  )
51
52
 
@@ -115,7 +116,7 @@ module VerifyIt
115
116
  current_attempts = rate_limiter.record_verification_attempt(identifier: to, record: record)
116
117
 
117
118
  # Verify code
118
- if stored_code == code.to_s
119
+ if stored_code == CodeHasher.digest(code, secret: VerifyIt.configuration.secret_key_base)
119
120
  # Success - cleanup
120
121
  storage.delete_code(identifier: to, record: record)
121
122
  storage.reset_attempts(identifier: to, record: record)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module VerifyIt
4
- VERSION = "0.2.0"
4
+ VERSION = "0.3.0"
5
5
  end
data/lib/verify_it.rb CHANGED
@@ -4,6 +4,7 @@ require_relative "verify_it/version"
4
4
  require_relative "verify_it/configuration"
5
5
  require_relative "verify_it/result"
6
6
  require_relative "verify_it/code_generator"
7
+ require_relative "verify_it/code_hasher"
7
8
  require_relative "verify_it/rate_limiter"
8
9
  require_relative "verify_it/storage/base"
9
10
  require_relative "verify_it/storage/memory_storage"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: verify_it
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremias Ramirez
@@ -157,6 +157,7 @@ files:
157
157
  - lib/verify_it.rb
158
158
  - lib/verify_it/cli.rb
159
159
  - lib/verify_it/code_generator.rb
160
+ - lib/verify_it/code_hasher.rb
160
161
  - lib/verify_it/configuration.rb
161
162
  - lib/verify_it/delivery/base.rb
162
163
  - lib/verify_it/delivery/email_delivery.rb