lato 3.5.8 → 3.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b04945a750538aecdc08a8b8632aa661c3e08f7def4fad9b5b9fa1621dd09e80
4
- data.tar.gz: 717437c493529ac4eb5da90ce0e38c917980e388e68bff2475ff37646d40fea9
3
+ metadata.gz: 124f38d5389e35689d3829980d788e5531af092d45fd378b5fbaabdc039ebe51
4
+ data.tar.gz: e6a938bc4549803deb41efd7df596e85148d84488d442f75ac46b9bb8c0191bd
5
5
  SHA512:
6
- metadata.gz: 01d49b48a8bef85902bd4c0b1b21f1a5d7b06789f468b686972ade21546f5e5be6507a1d2fe592dc83b79d364d62576babbe306068febe815ef16604f5b40fcd
7
- data.tar.gz: ac98e3240955cfb5a1c23b30c84c733480e9780d2747fc2ea9aea9a1c2a3828a9b59229c1cabd9d037237fd9350d8be7bcde4a72b0aeeccc4a8ffd13e35fc582
6
+ metadata.gz: fed883559fd4d1859aacc7ca6ca2dc2d65935c1d91d769c23ba71b940d2067cc8d320b84512a9adbd6b0a1540f7e3b33098664c89298a18277fda7fa548a7dc9
7
+ data.tar.gz: 9b87edd528d4c10bb7c82f4b8fa7769d6625560668657dea98b085661d22696c215d138fc3a5af0947d22cfb20c63b014503f472d99516bf6b0594398809e0ca
data/README.md CHANGED
@@ -107,4 +107,3 @@ $ ruby ./bin/publish.rb
107
107
 
108
108
  ## License
109
109
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
110
-
@@ -37,7 +37,7 @@ module Lato
37
37
  if collection.respond_to?(:lato_index_search)
38
38
  collection = collection.lato_index_search(search)
39
39
  else
40
- query = @_lato_index[key][:searchable_columns].map { |k| "lower(#{k}) LIKE :search" }
40
+ query = @_lato_index[key][:searchable_columns].map { |k| "#{k.to_s == 'id' ? k : "lower(#{k})"} LIKE :search" }
41
41
  collection = collection.where(query.join(' OR '), search: "%#{search.downcase.strip}%")
42
42
  end
43
43
  end
@@ -55,6 +55,20 @@ module Lato
55
55
  end
56
56
  end
57
57
 
58
+ def update_authenticator_action
59
+ return respond_to_with_not_found unless Lato.config.authenticator_connection
60
+
61
+ respond_to do |format|
62
+ if @session.user.generate_authenticator_secret
63
+ format.html { redirect_to lato.account_path }
64
+ format.json { render json: @session.user }
65
+ else
66
+ format.html { render :index, status: :unprocessable_entity }
67
+ format.json { render json: @session.user.errors, status: :unprocessable_entity }
68
+ end
69
+ end
70
+ end
71
+
58
72
  def request_verify_email_action
59
73
  respond_to do |format|
60
74
  if @session.user.request_verify_email
@@ -10,6 +10,7 @@ module Lato
10
10
  before_action :lock_signup_if_disabled, only: %i[signup signup_action]
11
11
  before_action :lock_recover_password_if_disabled, only: %i[recover_password recover_password_action update_password update_password_action]
12
12
  before_action :lock_web3_if_disabled, only: %i[web3_signin web3_signin_action]
13
+ before_action :lock_authenticator_if_disabled, only: %i[authenticator authenticator_action]
13
14
 
14
15
  before_action :hide_sidebar
15
16
 
@@ -28,10 +29,13 @@ module Lato
28
29
  ip_address: request.remote_ip,
29
30
  user_agent: request.user_agent
30
31
  ))
31
- session_create(@user.id)
32
-
33
- format.html { redirect_to lato.root_path }
34
- format.json { render json: @user }
32
+ if create_session_or_start_authenticator(@user)
33
+ format.html { redirect_to lato.root_path }
34
+ format.json { render json: @user }
35
+ else
36
+ format.html { redirect_to lato.authentication_authenticator_path }
37
+ format.json { render json: @user }
38
+ end
35
39
  else
36
40
  format.html { render :signin, status: :unprocessable_entity }
37
41
  format.json { render json: @user.errors, status: :unprocessable_entity }
@@ -54,10 +58,13 @@ module Lato
54
58
  web3_nonce: session[:web3_nonce]
55
59
  ))
56
60
  session[:web3_nonce] = nil
57
- session_create(@user.id)
58
-
59
- format.html { redirect_to lato.root_path }
60
- format.json { render json: @user }
61
+ if create_session_or_start_authenticator(@user)
62
+ format.html { redirect_to lato.root_path }
63
+ format.json { render json: @user }
64
+ else
65
+ format.html { redirect_to lato.authentication_authenticator_path }
66
+ format.json { render json: @user }
67
+ end
61
68
  else
62
69
  session[:web3_nonce] = nil
63
70
  format.html { render :web3_signin, status: :unprocessable_entity }
@@ -183,6 +190,31 @@ module Lato
183
190
  end
184
191
  end
185
192
 
193
+ # Authenticator
194
+ ##
195
+
196
+ def authenticator
197
+ @user = Lato::User.find_by_id(session[:authenticator_user_id])
198
+ return respond_to_with_not_found unless @user
199
+ end
200
+
201
+ def authenticator_action
202
+ @user = Lato::User.find_by_id(session[:authenticator_user_id])
203
+
204
+ respond_to do |format|
205
+ if @user.authenticator(params.require(:user).permit(:authenticator_code))
206
+ session[:authenticator_user_id] = nil
207
+ session_create(@user.id)
208
+
209
+ format.html { redirect_to lato.root_path }
210
+ format.json { render json: @user }
211
+ else
212
+ format.html { render :authenticator, status: :unprocessable_entity }
213
+ format.json { render json: @user.errors, status: :unprocessable_entity }
214
+ end
215
+ end
216
+ end
217
+
186
218
  private
187
219
 
188
220
  def registration_params
@@ -199,6 +231,16 @@ module Lato
199
231
  respond_to_with_not_found unless @invitation
200
232
  end
201
233
 
234
+ def create_session_or_start_authenticator(user)
235
+ if !Lato.config.authenticator_connection || Lato.config.auth_disable_authenticator || !user.authenticator_enabled?
236
+ session_create(user.id)
237
+ return true
238
+ end
239
+
240
+ session[:authenticator_user_id] = user.id
241
+ false
242
+ end
243
+
202
244
  def lock_signup_if_disabled
203
245
  return unless Lato.config.auth_disable_signup
204
246
 
@@ -215,6 +257,12 @@ module Lato
215
257
  return if Lato.config.web3_connection && !Lato.config.auth_disable_web3
216
258
 
217
259
 
260
+ respond_to_with_not_found
261
+ end
262
+
263
+ def lock_authenticator_if_disabled
264
+ return if Lato.config.authenticator_connection && !Lato.config.auth_disable_authenticator
265
+
218
266
  respond_to_with_not_found
219
267
  end
220
268
  end
@@ -1,5 +1,6 @@
1
1
  module Lato
2
2
  class User < ApplicationRecord
3
+ include Lato::DependencyHelper
3
4
  include LatoUserApplication
4
5
 
5
6
  has_secure_password
@@ -53,6 +54,10 @@ module Lato
53
54
  @valid_accepted_terms_and_conditions_version ||= accepted_terms_and_conditions_version >= Lato.config.legal_terms_and_conditions_version
54
55
  end
55
56
 
57
+ def authenticator_enabled?
58
+ !authenticator_secret.blank?
59
+ end
60
+
56
61
  # Helpers
57
62
  ##
58
63
 
@@ -64,6 +69,10 @@ module Lato
64
69
  @gravatar_image_url ||= "https://www.gravatar.com/avatar/#{Digest::MD5.hexdigest(email)}?s=#{size}"
65
70
  end
66
71
 
72
+ def authenticator_qr_code_base64(size = 200)
73
+ "data:image/png;base64,#{Base64.strict_encode64(RQRCode::QRCode.new(ROTP::TOTP.new(authenticator_secret, :issuer => Lato.config.application_title).provisioning_uri(email).to_s).as_png(size: size, border_modules: 0).to_s)}"
74
+ end
75
+
67
76
  # Operations
68
77
  ##
69
78
 
@@ -112,6 +121,8 @@ module Lato
112
121
  end
113
122
 
114
123
  def web3_signin(params)
124
+ depends_on('eth')
125
+
115
126
  self.web3_address = params[:web3_address]
116
127
 
117
128
  user = Lato::User.find_by(web3_address: params[:web3_address].downcase)
@@ -221,7 +232,9 @@ module Lato
221
232
 
222
233
  c_password_update_code('')
223
234
 
224
- update(params.permit(:password, :password_confirmation))
235
+ update(params.permit(:password, :password_confirmation).merge(
236
+ authenticator_secret: nil # Reset authenticator secret when password is updated
237
+ ))
225
238
  end
226
239
 
227
240
  def update_accepted_privacy_policy_version(params)
@@ -269,6 +282,8 @@ module Lato
269
282
  end
270
283
 
271
284
  def add_web3_connection(params)
285
+ depends_on('eth')
286
+
272
287
  signature_pubkey = Eth::Signature.personal_recover(params[:web3_nonce], params[:web3_signed_nonce])
273
288
  signature_address = Eth::Util.public_key_to_address signature_pubkey
274
289
  unless signature_address.to_s.downcase == params[:web3_address].downcase
@@ -287,6 +302,23 @@ module Lato
287
302
  true
288
303
  end
289
304
 
305
+ def generate_authenticator_secret
306
+ update(authenticator_secret: ROTP::Base32.random)
307
+ end
308
+
309
+ def authenticator(params)
310
+ return false unless authenticator_enabled?
311
+
312
+ totp = ROTP::TOTP.new(authenticator_secret)
313
+ result = totp.verify(params[:authenticator_code])
314
+ unless result
315
+ errors.add(:base, :authenticator_code_invalid)
316
+ return
317
+ end
318
+
319
+ true
320
+ end
321
+
290
322
  # Cache
291
323
  ##
292
324
 
@@ -0,0 +1,41 @@
1
+ <%
2
+
3
+ user ||= Lato::User.new
4
+
5
+ %>
6
+
7
+ <%= turbo_frame_tag 'account_form-authenticator' do %>
8
+ <%= form_with model: user, url: lato.account_update_authenticator_action_path, data: { turbo_frame: '_self', controller: 'lato-form' } do |form| %>
9
+ <%= lato_form_notices class: %w[mb-3] %>
10
+ <%= lato_form_errors user, class: %w[mb-3] %>
11
+
12
+ <% if user.authenticator_secret %>
13
+ <div class="d-block d-md-flex align-items-stretch">
14
+ <div class="text-center mb-3 mb-md-0 me-md-3">
15
+ <img src="<%= user.authenticator_qr_code_base64 %>" />
16
+ </div>
17
+ <div class="d-flex flex-column justify-content-between">
18
+ <div class="alert alert-light">
19
+ <p>
20
+ <%= raw I18n.t('lato.account_authenticator_ready_qr') %>
21
+ </p>
22
+ </div>
23
+
24
+ <div class="d-flex justify-content-end">
25
+ <%= lato_form_submit form, I18n.t('lato.reset_qr_code'), class: %w[btn-danger] %>
26
+ </div>
27
+ </div>
28
+ </div>
29
+ <% else %>
30
+ <div class="alert alert-light mb-0">
31
+ <h4 class="alert-heading"><%= I18n.t('lato.account_authenticator_start_title') %></h4>
32
+ <p>
33
+ <%= raw I18n.t('lato.account_authenticator_start_description') %>
34
+ </p>
35
+ <p class="mb-0">
36
+ <%= lato_form_submit form, I18n.t('lato.generate_qr_code'), class: %w[btn-primary] %>
37
+ </p>
38
+ </div>
39
+ <% end %>
40
+ <% end %>
41
+ <% end %>
@@ -32,6 +32,17 @@
32
32
  </div>
33
33
  <% end %>
34
34
 
35
+ <% if Lato.config.authenticator_connection %>
36
+ <div class="card mb-4">
37
+ <div class="card-header">
38
+ <h2 class="fs-4 mb-0"><%= I18n.t('lato.account_authenticator') %></h2>
39
+ </div>
40
+ <div class="card-body">
41
+ <%= render 'lato/account/form-authenticator', user: @session.user %>
42
+ </div>
43
+ </div>
44
+ <% end %>
45
+
35
46
  <div class="card mb-4">
36
47
  <div class="card-header">
37
48
  <h2 class="fs-4 mb-0"><%= I18n.t('lato.account_delete') %></h2>
@@ -0,0 +1,28 @@
1
+ <%
2
+
3
+ user ||= Lato::User.new
4
+
5
+ %>
6
+
7
+ <%= turbo_frame_tag 'authentication_form-authenticator' do %>
8
+ <%= form_with model: user, url: lato.authentication_authenticator_action_path, method: :post, data: { turbo_frame: '_self', controller: 'lato-form' } do |form| %>
9
+ <%= lato_form_notices class: %w[mb-3] %>
10
+ <%= lato_form_errors user, class: %w[mb-3] %>
11
+
12
+ <div class="mb-3 text-center">
13
+ <p><%= raw I18n.t('lato.authenticator_code_help', email: user.email) %></p>
14
+ </div>
15
+
16
+ <div class="mb-3">
17
+ <%= lato_form_item_input_text form, :authenticator_code, required: true %>
18
+ </div>
19
+
20
+ <div>
21
+ <%= lato_form_submit form, I18n.t('lato.confirm'), class: %w[d-block w-100] %>
22
+ </div>
23
+
24
+ <div class="text-center mt-3 mb-3">
25
+ <%= I18n.t('lato.or').downcase %> <%= link_to I18n.t('lato.reset_password').downcase, lato.authentication_recover_password_path %>
26
+ </div>
27
+ <% end %>
28
+ <% end %>
@@ -0,0 +1,10 @@
1
+ <div class="w-100 h-100 d-flex justify-content-center align-items-center" style="min-height: calc(100vh - 54px - 2rem)">
2
+ <div class="card w-100" style="max-width: 400px">
3
+ <div class="card-header">
4
+ <h1 class="fs-3 mb-0 text-center"><%= I18n.t('lato.authenticator') %></h1>
5
+ </div>
6
+ <div class="card-body">
7
+ <%= render 'lato/authentication/form-authenticator', user: @user %>
8
+ </div>
9
+ </div>
10
+ </div>
@@ -49,6 +49,15 @@ en:
49
49
  web3_signin: Web3 Login
50
50
  retry: Retry
51
51
  back: Go back
52
+ account_authenticator: Google Authenticator
53
+ account_authenticator_start_title: Enable Google Authenticator
54
+ account_authenticator_start_description: Generate a QR code by clicking the button below and scan it with the Google Authenticator app on your phone.<br>This will allow you to use the protect your account with a second factor authentication.
55
+ account_authenticator_ready_qr: Scan the QR code with the Google Authenticator app to use the account protection with a second factor authentication.
56
+ generate_qr_code: Generate QR code
57
+ reset_qr_code: Reset QR code
58
+ authenticator: Two-factor authentication
59
+ authenticator_code_help: Insert the code generated by the Google Authenticator app for the account <b>%{email}</b>
60
+ reset_password: Reset your password
52
61
 
53
62
  account_controller:
54
63
  update_user_action_notice: Account information properly updated
@@ -82,6 +91,7 @@ en:
82
91
  terms_and_conditions_invalid: To accept the terms and conditions you must select the confirmation checkbox
83
92
  web3_address_invalid: The address you send is not corretly signed
84
93
  web3_connection_error: Impossible to connect the wallet
94
+ authenticator_code_invalid: The code you inserted is not correct
85
95
  password:
86
96
  not_correct: not correct
87
97
  email:
@@ -51,6 +51,15 @@ it:
51
51
  web3_signin: Accedi con Web3
52
52
  retry: Riprova
53
53
  back: Torna indietro
54
+ account_authenticator: Google Authenticator
55
+ account_authenticator_start_title: Abilita Google Authenticator
56
+ account_authenticator_start_description: Genera un codice QR cliccando il pulsante sottostante e scansionalo con l'app Google Authenticator sul tuo telefono.<br>Questo ti permetterà di proteggere il tuo account con un'autenticazione a due fattori.
57
+ account_authenticator_ready_qr: Scansiona il codice QR con l'app Google Authenticator per utilizzare la protezione dell'account con un'autenticazione a due fattori.
58
+ generate_qr_code: Genera codice QR
59
+ reset_qr_code: Resetta codice QR
60
+ authenticator: Autenticazione a due fattori
61
+ authenticator_code_help: Inserisci il codice generato dall'app Google Authenticator per l'account <b>%{email}</b>
62
+ reset_password: Reimposta la tua password
54
63
 
55
64
  account_controller:
56
65
  update_user_action_notice: Informazioni account aggiornate correttamente
@@ -90,6 +99,7 @@ it:
90
99
  invitation_invalid: Invito non valido
91
100
  web3_address_invalid: L'inidirizzo inviato non è correttamente firmato
92
101
  web3_connection_error: Impossibile connettere il wallet
102
+ authenticator_code_invalid: Il codice inserito non è corretto
93
103
  password:
94
104
  not_correct: non corretta
95
105
  password_confirmation:
data/config/routes.rb CHANGED
@@ -26,6 +26,8 @@ Lato::Engine.routes.draw do
26
26
  patch 'update_password_action', to: 'authentication#update_password_action', as: :authentication_update_password_action
27
27
  get 'accept_invitation', to: 'authentication#accept_invitation', as: :authentication_accept_invitation
28
28
  post 'accept_invitation_action', to: 'authentication#accept_invitation_action', as: :authentication_accept_invitation_action
29
+ get 'authenticator', to: 'authentication#authenticator', as: :authentication_authenticator
30
+ post 'authenticator_action', to: 'authentication#authenticator_action', as: :authentication_authenticator_action
29
31
  end
30
32
 
31
33
  # Account
@@ -35,6 +37,7 @@ Lato::Engine.routes.draw do
35
37
  get '', to: 'account#index', as: :account
36
38
  patch 'update_user_action', to: 'account#update_user_action', as: :account_update_user_action
37
39
  patch 'update_web3_action', to: 'account#update_web3_action', as: :account_update_web3_action
40
+ patch 'update_authenticator_action', to: 'account#update_authenticator_action', as: :account_update_authenticator_action
38
41
  patch 'request_verify_email_action', to: 'account#request_verify_email_action', as: :account_request_verify_email_action
39
42
  patch 'update_password_action', to: 'account#update_password_action', as: :account_update_password_action
40
43
  delete 'destroy_action', to: 'account#destroy_action', as: :account_destroy_action
@@ -0,0 +1,5 @@
1
+ class AddAuthenticatorSecretToUser < ActiveRecord::Migration[7.1]
2
+ def change
3
+ add_column :lato_users, :authenticator_secret, :string
4
+ end
5
+ end
data/lib/lato/config.rb CHANGED
@@ -10,7 +10,7 @@ module Lato
10
10
  attr_accessor :session_lifetime, :session_root_path
11
11
 
12
12
  # Authentication configs
13
- attr_accessor :auth_disable_signup, :auth_disable_recover_password, :auth_disable_web3
13
+ attr_accessor :auth_disable_signup, :auth_disable_recover_password, :auth_disable_web3, :auth_disable_authenticator
14
14
 
15
15
  # Assets configs
16
16
  attr_accessor :assets_stylesheet_entry
@@ -22,8 +22,12 @@ module Lato
22
22
  attr_accessor :legal_privacy_policy_url, :legal_privacy_policy_version, :legal_terms_and_conditions_url, :legal_terms_and_conditions_version
23
23
 
24
24
  # Web3 connection
25
+ # NOTE: It requires the gem 'eth' to be installed in the application Gemfile
25
26
  attr_accessor :web3_connection
26
27
 
28
+ # Authenticator connection
29
+ attr_accessor :authenticator_connection
30
+
27
31
  def initialize
28
32
  @application_title = 'Lato'
29
33
  @application_version = '1.0.0'
@@ -34,6 +38,7 @@ module Lato
34
38
  @auth_disable_signup = false
35
39
  @auth_disable_recover_password = false
36
40
  @auth_disable_web3 = false
41
+ @auth_disable_authenticator = false
37
42
 
38
43
  @assets_stylesheet_entry = 'application'
39
44
 
@@ -48,6 +53,7 @@ module Lato
48
53
  @legal_terms_and_conditions_version = 1
49
54
 
50
55
  @web3_connection = false
56
+ @authenticator_connection = false
51
57
  end
52
58
  end
53
59
  end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ # NOTE: Taken from https://github.com/andreibondarev/langchainrb/blob/main/lib/langchain/dependency_helper.rb
4
+ # Thanks to Andrei Bondarev for the inspiration!!
5
+
6
+ module Lato
7
+ module DependencyHelper
8
+ class LoadError < ::LoadError; end
9
+
10
+ class VersionError < ScriptError; end
11
+
12
+ # This method requires and loads the given gem, and then checks to see if the version of the gem meets the requirements listed in `lato.gemspec`
13
+ # This solution was built to avoid auto-loading every single gem in the Gemfile when the developer will mostly likely be only using a few of them.
14
+ #
15
+ # @param gem_name [String] The name of the gem to load
16
+ # @return [Boolean] Whether or not the gem was loaded successfully
17
+ # @raise [LoadError] If the gem is not installed
18
+ # @raise [VersionError] If the gem is installed, but the version does not meet the requirements
19
+ #
20
+ def depends_on(gem_name, req: true)
21
+ gem(gem_name) # require the gem
22
+
23
+ return(true) unless defined?(Bundler) # If we're in a non-bundler environment, we're no longer able to determine if we'll meet requirements
24
+
25
+ gem_version = Gem.loaded_specs[gem_name].version
26
+ gem_requirement = Bundler.load.dependencies.find { |g| g.name == gem_name }&.requirement
27
+
28
+ raise LoadError unless gem_requirement
29
+
30
+ unless gem_requirement.satisfied_by?(gem_version)
31
+ raise VersionError, "The #{gem_name} gem is installed, but version #{gem_requirement} is required. You have #{gem_version}."
32
+ end
33
+
34
+ lib_name = gem_name if req == true
35
+ lib_name = req if req.is_a?(String)
36
+
37
+ require(lib_name) if lib_name
38
+
39
+ true
40
+ rescue ::LoadError
41
+ raise LoadError, "Could not load #{gem_name}. Please ensure that the #{gem_name} gem is installed."
42
+ end
43
+ end
44
+ end
data/lib/lato/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Lato
2
- VERSION = "3.5.8"
2
+ VERSION = "3.6.0"
3
3
  end
data/lib/lato.rb CHANGED
@@ -1,12 +1,14 @@
1
1
  require "kaminari"
2
2
  require "bootstrap"
3
3
  require "browser"
4
- require "eth"
4
+ require "rotp"
5
+ require "rqrcode"
5
6
 
6
7
  require "lato/version"
7
8
  require "lato/engine"
8
9
  require "lato/config"
9
10
  require "lato/btstrap"
11
+ require "lato/dependency_helper"
10
12
 
11
13
  module Lato
12
14
  class << self
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lato
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.5.8
4
+ version: 3.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gregorio Galante
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-03-21 00:00:00.000000000 Z
11
+ date: 2024-03-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -95,7 +95,21 @@ dependencies:
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
- name: eth
98
+ name: rqrcode
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rotp
99
113
  requirement: !ruby/object:Gem::Requirement
100
114
  requirements:
101
115
  - - ">="
@@ -108,6 +122,20 @@ dependencies:
108
122
  - - ">="
109
123
  - !ruby/object:Gem::Version
110
124
  version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: eth
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
111
139
  description: A Rails engine that includes what you need to build a new project!
112
140
  email:
113
141
  - me@gregoriogalante.com
@@ -162,6 +190,7 @@ files:
162
190
  - app/models/lato/user.rb
163
191
  - app/views/lato/account/_alert-accepted-privacy-policy-version.html.erb
164
192
  - app/views/lato/account/_alert-accepted-terms-and-conditions-version.html.erb
193
+ - app/views/lato/account/_form-authenticator.html.erb
165
194
  - app/views/lato/account/_form-destroy.html.erb
166
195
  - app/views/lato/account/_form-password.html.erb
167
196
  - app/views/lato/account/_form-user.html.erb
@@ -169,6 +198,7 @@ files:
169
198
  - app/views/lato/account/index.html.erb
170
199
  - app/views/lato/authentication/_fields-registration.html.erb
171
200
  - app/views/lato/authentication/_form-accept-invitation.html.erb
201
+ - app/views/lato/authentication/_form-authenticator.html.erb
172
202
  - app/views/lato/authentication/_form-recover-password.html.erb
173
203
  - app/views/lato/authentication/_form-signin.html.erb
174
204
  - app/views/lato/authentication/_form-signup.html.erb
@@ -176,6 +206,7 @@ files:
176
206
  - app/views/lato/authentication/_form-verify-email.html.erb
177
207
  - app/views/lato/authentication/_form-web3-signin.html.erb
178
208
  - app/views/lato/authentication/accept_invitation.html.erb
209
+ - app/views/lato/authentication/authenticator.html.erb
179
210
  - app/views/lato/authentication/recover_password.html.erb
180
211
  - app/views/lato/authentication/signin.html.erb
181
212
  - app/views/lato/authentication/signout.html.erb
@@ -226,9 +257,11 @@ files:
226
257
  - db/migrate/20230823165716_create_lato_log_user_signups.rb
227
258
  - db/migrate/20240222125124_add_web3_to_lato_users.rb
228
259
  - db/migrate/20240222171418_add_indexes_on_lato_users_email.rb
260
+ - db/migrate/20240318074025_add_authenticator_secret_to_user.rb
229
261
  - lib/lato.rb
230
262
  - lib/lato/btstrap.rb
231
263
  - lib/lato/config.rb
264
+ - lib/lato/dependency_helper.rb
232
265
  - lib/lato/engine.rb
233
266
  - lib/lato/version.rb
234
267
  - lib/tasks/lato_tasks.rake