yaag 0.0.1 → 0.0.11
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 +4 -4
- data/LICENSE.txt +1 -1
- data/lib/generators/yaag/USAGE +5 -0
- data/lib/generators/yaag/install_generator.rb +64 -0
- data/lib/generators/yaag/templates/README +1 -0
- data/lib/generators/yaag/templates/active_model/passwordless_login.rb +51 -0
- data/lib/generators/yaag/templates/app/channels/application_cable/connection.rb +16 -0
- data/lib/generators/yaag/templates/app/controllers/concerns/authentication.rb +52 -0
- data/lib/generators/yaag/templates/app/controllers/sessions_controller.rb +24 -0
- data/lib/generators/yaag/templates/app/controllers/signins_controller.rb +12 -0
- data/lib/generators/yaag/templates/app/mailers/signins_mailer.rb +6 -0
- data/lib/generators/yaag/templates/app/models/current.rb +4 -0
- data/lib/generators/yaag/templates/app/models/session.rb +3 -0
- data/lib/generators/yaag/templates/app/models/user.rb +7 -0
- data/lib/generators/yaag/templates/app/views/sessions/new.html.erb +2 -0
- data/lib/generators/yaag/templates/app/views/signins/new.html.erb +8 -0
- data/lib/generators/yaag/templates/app/views/signins_mailer/token.html.erb +8 -0
- data/lib/generators/yaag/templates/app/views/signins_mailer/token.text.erb +6 -0
- data/lib/yaag/engine.rb +5 -0
- data/lib/yaag/version.rb +1 -1
- metadata +19 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2da4ef8b96e8631b9e35d8ffa355325a3f0a0a0dc3c59a439c39e47e624e5e16
|
|
4
|
+
data.tar.gz: 40e8a8882b657f30850118b72a132b9e61296381df6b52c908eaf71022c46cdb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ca92370e1389ed19923f99a192aa3c87a54c0fd6551620b0ea52edef322a9fa6995aafc6d01ea27044326313f988f884488eac4abae50d9803d24ec790a262b0
|
|
7
|
+
data.tar.gz: 1e220e7aa4138f589a274f6a80f4173372087e2fbdf5f7c56dc02683e9951b42f5fefb12a1fd76741a714194c6066c225c6447df32c9737ec68d3ed21d81da9f
|
data/LICENSE.txt
CHANGED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators/bundle_helper"
|
|
4
|
+
|
|
5
|
+
module Yaag
|
|
6
|
+
module Generators
|
|
7
|
+
class InstallGenerator < Rails::Generators::Base # :nodoc:
|
|
8
|
+
include Rails::Generators::BundleHelper
|
|
9
|
+
source_root File.expand_path("../templates", __FILE__)
|
|
10
|
+
|
|
11
|
+
class_option :api, type: :boolean,
|
|
12
|
+
desc: "Generate API-only controllers and models, with no view templates"
|
|
13
|
+
|
|
14
|
+
# hook_for :template_engine do |template_engine|
|
|
15
|
+
#invoke template_engine unless options.api?
|
|
16
|
+
# end
|
|
17
|
+
|
|
18
|
+
def create_authentication_files
|
|
19
|
+
|
|
20
|
+
template "app/models/session.rb"
|
|
21
|
+
template "app/models/user.rb"
|
|
22
|
+
template "app/models/current.rb"
|
|
23
|
+
|
|
24
|
+
template "app/controllers/signins_controller.rb"
|
|
25
|
+
template "app/controllers/sessions_controller.rb"
|
|
26
|
+
template "app/controllers/concerns/authentication.rb"
|
|
27
|
+
|
|
28
|
+
template "app/channels/application_cable/connection.rb" # if defined?(ActionCable::Engine)
|
|
29
|
+
|
|
30
|
+
copy_file "app/views/sessions/new.html.erb"
|
|
31
|
+
copy_file "app/views/signins/new.html.erb"
|
|
32
|
+
|
|
33
|
+
#if defined?(ActionMailer::Railtie)
|
|
34
|
+
template "app/mailers/signins_mailer.rb"
|
|
35
|
+
|
|
36
|
+
copy_file "app/views/signins_mailer/token.html.erb"
|
|
37
|
+
copy_file "app/views/signins_mailer/token.text.erb"
|
|
38
|
+
#end
|
|
39
|
+
|
|
40
|
+
template "active_model/passwordless_login.rb", "lib/active_model/passwordless_login.rb"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def configure_application_controller
|
|
44
|
+
inject_into_class "app/controllers/application_controller.rb", "ApplicationController", " include Authentication\n" # if File.exist? "app/controllers/application_controller.rb"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def configure_authentication_routes
|
|
48
|
+
route "resource :signin, only: [:new, :create]" # if File.exist? "config/routes.rb"
|
|
49
|
+
route "resource :session, only: [:new, :destroy] do\n get \"/:token/create\" => \"sessions#create\", as: :create\nend" # if File.exist? "config/routes.rb"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def add_migrations
|
|
53
|
+
generate "migration", "CreateUsers", "email_address:string!:uniq", "--force"
|
|
54
|
+
generate "migration", "CreateSessions", "user:references ip_address:string user_agent:string", "--force"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def show_readme
|
|
58
|
+
readme "README" if behavior == :invoke
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
#hook_for :test_framework
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
===============================================================================
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveModel
|
|
4
|
+
module PasswordlessLogin
|
|
5
|
+
extend ActiveSupport::Concern
|
|
6
|
+
|
|
7
|
+
DEFAULT_LOGIN_TOKEN_EXPIRES_IN = 15.minutes
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
module ClassMethods
|
|
13
|
+
def has_passwordless_login(attribute = :email_address)
|
|
14
|
+
include InstanceMethodsOnActivation.new(attribute)
|
|
15
|
+
|
|
16
|
+
if respond_to?(:generates_token_for)
|
|
17
|
+
login_token_expires_in = DEFAULT_LOGIN_TOKEN_EXPIRES_IN
|
|
18
|
+
|
|
19
|
+
silence_redefinition_of_method(:"#{attribute}_login_token_expires_in")
|
|
20
|
+
define_method(:"#{attribute}_login_token_expires_in") { login_token_expires_in }
|
|
21
|
+
|
|
22
|
+
generates_token_for :"#{attribute}_login", expires_in: login_token_expires_in do
|
|
23
|
+
public_send(:"#{attribute}")&.first(10)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
27
|
+
silence_redefinition_of_method :find_by_#{attribute}_login_token
|
|
28
|
+
def self.find_by_#{attribute}_login_token(token)
|
|
29
|
+
find_by_token_for(:#{attribute}_login, token)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
silence_redefinition_of_method :find_by_#{attribute}_login_token!
|
|
33
|
+
def self.find_by_#{attribute}_login_token!(token)
|
|
34
|
+
find_by_token_for!(:#{attribute}_login, token)
|
|
35
|
+
end
|
|
36
|
+
RUBY
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
class InstanceMethodsOnActivation < Module
|
|
42
|
+
def initialize(attribute)
|
|
43
|
+
attr_reader attribute
|
|
44
|
+
|
|
45
|
+
define_method("#{attribute}_login_token") do
|
|
46
|
+
generate_token_for(:"#{attribute}_login")
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module ApplicationCable
|
|
2
|
+
class Connection < ActionCable::Connection::Base
|
|
3
|
+
identified_by :current_user
|
|
4
|
+
|
|
5
|
+
def connect
|
|
6
|
+
set_current_user || reject_unauthorized_connection
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
private
|
|
10
|
+
def set_current_user
|
|
11
|
+
if session = Session.find_by(id: cookies.signed[:session_id])
|
|
12
|
+
self.current_user = session.user
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
module Authentication
|
|
2
|
+
extend ActiveSupport::Concern
|
|
3
|
+
|
|
4
|
+
included do
|
|
5
|
+
before_action :require_authentication
|
|
6
|
+
helper_method :authenticated?
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
class_methods do
|
|
10
|
+
def allow_unauthenticated_access(**options)
|
|
11
|
+
skip_before_action :require_authentication, **options
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
def authenticated?
|
|
17
|
+
resume_session
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def require_authentication
|
|
21
|
+
resume_session || request_authentication
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def resume_session
|
|
25
|
+
Current.session ||= find_session_by_cookie
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def find_session_by_cookie
|
|
29
|
+
Session.find_by(id: cookies.signed[:session_id]) if cookies.signed[:session_id]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def request_authentication
|
|
33
|
+
session[:return_to_after_authenticating] = request.url
|
|
34
|
+
redirect_to new_signin_path
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def after_authentication_url
|
|
38
|
+
session.delete(:return_to_after_authenticating) || root_url
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def start_new_session_for(user)
|
|
42
|
+
user.sessions.create!(user_agent: request.user_agent, ip_address: request.remote_ip).tap do |session|
|
|
43
|
+
Current.session = session
|
|
44
|
+
cookies.signed.permanent[:session_id] = { value: session.id, httponly: true, same_site: :lax }
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def terminate_session
|
|
49
|
+
Current.session.destroy
|
|
50
|
+
cookies.delete(:session_id)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
class SessionsController < ApplicationController
|
|
2
|
+
allow_unauthenticated_access only: %i[ new create ]
|
|
3
|
+
before_action :set_user_by_token, only: %i[ create ]
|
|
4
|
+
rate_limit to: 10, within: 3.minutes, only: :create, with: -> { redirect_to new_session_path, alert: "Try again later." }
|
|
5
|
+
|
|
6
|
+
def new
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def create
|
|
10
|
+
start_new_session_for @user
|
|
11
|
+
redirect_to after_authentication_url
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def destroy
|
|
15
|
+
terminate_session
|
|
16
|
+
redirect_to new_signin_path, status: :see_other
|
|
17
|
+
end
|
|
18
|
+
private
|
|
19
|
+
def set_user_by_token
|
|
20
|
+
@user = User.find_by_email_address_login_token!(params[:token])
|
|
21
|
+
rescue ActiveSupport::MessageVerifier::InvalidSignature
|
|
22
|
+
redirect_to new_signin_path, alert: "Signin link is invalid or has expired."
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
class SigninsController < ApplicationController
|
|
2
|
+
allow_unauthenticated_access
|
|
3
|
+
rate_limit to: 10, within: 3.minutes, only: :create, with: -> { redirect_to new_signin_path, alert: "Try again later." }
|
|
4
|
+
def new
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def create
|
|
8
|
+
user = User.find_or_create_by(email_address: params[:email_address])
|
|
9
|
+
SigninsMailer.token(user).deliver_now
|
|
10
|
+
redirect_to new_session_path, notice: "Sign in address sent to provided e-mail."
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<%= tag.div(flash[:alert], style: "color:red") if flash[:alert] %>
|
|
2
|
+
<%= tag.div(flash[:notice], style: "color:green") if flash[:notice] %>
|
|
3
|
+
|
|
4
|
+
<%= form_with url: signin_path do |form| %>
|
|
5
|
+
<%= form.email_field :email_address, required: true, autofocus: true, autocomplete: "username", placeholder: "Enter your email address", value: params[:email_address] %><br>
|
|
6
|
+
<%= form.submit "Sign in" %>
|
|
7
|
+
<% end %>
|
|
8
|
+
<br>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<% if @user %>
|
|
2
|
+
<p>
|
|
3
|
+
You can reset your password on
|
|
4
|
+
<%= link_to "this password reset page", create_session_url(@user.email_address_login_token) %>.
|
|
5
|
+
|
|
6
|
+
This link will expire in <%= distance_of_time_in_words(0, @user.email_address_login_token_expires_in) %>.
|
|
7
|
+
</p>
|
|
8
|
+
<% end %>
|
data/lib/yaag/engine.rb
ADDED
data/lib/yaag/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: yaag
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.11
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- nu12
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-01-06 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: Passwordless authentication.
|
|
14
14
|
email:
|
|
@@ -21,7 +21,24 @@ files:
|
|
|
21
21
|
- LICENSE.txt
|
|
22
22
|
- README.md
|
|
23
23
|
- Rakefile
|
|
24
|
+
- lib/generators/yaag/USAGE
|
|
25
|
+
- lib/generators/yaag/install_generator.rb
|
|
26
|
+
- lib/generators/yaag/templates/README
|
|
27
|
+
- lib/generators/yaag/templates/active_model/passwordless_login.rb
|
|
28
|
+
- lib/generators/yaag/templates/app/channels/application_cable/connection.rb
|
|
29
|
+
- lib/generators/yaag/templates/app/controllers/concerns/authentication.rb
|
|
30
|
+
- lib/generators/yaag/templates/app/controllers/sessions_controller.rb
|
|
31
|
+
- lib/generators/yaag/templates/app/controllers/signins_controller.rb
|
|
32
|
+
- lib/generators/yaag/templates/app/mailers/signins_mailer.rb
|
|
33
|
+
- lib/generators/yaag/templates/app/models/current.rb
|
|
34
|
+
- lib/generators/yaag/templates/app/models/session.rb
|
|
35
|
+
- lib/generators/yaag/templates/app/models/user.rb
|
|
36
|
+
- lib/generators/yaag/templates/app/views/sessions/new.html.erb
|
|
37
|
+
- lib/generators/yaag/templates/app/views/signins/new.html.erb
|
|
38
|
+
- lib/generators/yaag/templates/app/views/signins_mailer/token.html.erb
|
|
39
|
+
- lib/generators/yaag/templates/app/views/signins_mailer/token.text.erb
|
|
24
40
|
- lib/yaag.rb
|
|
41
|
+
- lib/yaag/engine.rb
|
|
25
42
|
- lib/yaag/version.rb
|
|
26
43
|
- mise.toml
|
|
27
44
|
- sig/yaag.rbs
|