passwordless 0.1.0 → 0.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.
- checksums.yaml +4 -4
- data/README.md +123 -2
- data/Rakefile +0 -4
- data/app/controllers/passwordless/sessions_controller.rb +18 -5
- data/app/lib/passwordless/controller_helpers.rb +11 -12
- data/app/mailers/passwordless/mailer.rb +6 -1
- data/app/views/passwordless/mailer/magic_link.text.erb +1 -1
- data/app/views/passwordless/sessions/new.html.erb +1 -1
- data/config/routes.rb +0 -1
- data/lib/passwordless.rb +1 -1
- data/lib/passwordless/engine.rb +7 -0
- data/lib/passwordless/model_helpers.rb +7 -0
- data/lib/passwordless/router_helpers.rb +12 -0
- data/lib/passwordless/version.rb +1 -1
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d3bdc9fe84110cc587576344e493cbe16a0a9a74
|
4
|
+
data.tar.gz: 1d7558d9be99a4764c21eb6fda029a765a9540bb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6ec72945db7eec026bd640a3116c82fc9b5eea790cea4405bf9593815ed2e02edc3d91e58c82bdc52122a6190e512eb8013e51ca198d0b47cd961491d5f471aa
|
7
|
+
data.tar.gz: 0ca8c6e2e4d6bed6fab0351200acef5ac9e65a1526c2cd7503d751d967da8fd96d7200d005310600af693af00fde068aee7541b185e8969612342f32155dca4a
|
data/README.md
CHANGED
@@ -1,8 +1,129 @@
|
|
1
|
-
|
1
|
+
<p align='center'>
|
2
|
+
<img src='https://s3.brnbw.com/Passwordless-title-JO71NQv7Q0.svg' alt='Passwordless' />
|
3
|
+
<br />
|
4
|
+
<br />
|
5
|
+
</p>
|
6
|
+
|
7
|
+
<img src='https://travis-ci.org/mikker/passwordless.svg?branch=master' alt='Build status' /> <img src='https://img.shields.io/gem/v/passwordless.svg' alt='Gem version' />
|
2
8
|
|
3
9
|
Add authentication to your Rails app without all the icky-ness of passwords.
|
4
10
|
|
5
|
-
|
11
|
+
---
|
12
|
+
|
13
|
+
## Installation
|
14
|
+
|
15
|
+
Add the `passwordless` gem to your `Gemfile`:
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
gem 'passwordless'
|
19
|
+
```
|
20
|
+
|
21
|
+
Install it and copy over the migrations:
|
22
|
+
|
23
|
+
```sh
|
24
|
+
$ bundle
|
25
|
+
$ bin/rails passwordless:install:migrations
|
26
|
+
```
|
27
|
+
|
28
|
+
Passwordless creates a single model called `Passwordless::Session`. It doesn't come with its own `User` model, it expects you to create one, eg.:
|
29
|
+
|
30
|
+
```
|
31
|
+
$ bin/rails generate model User email
|
32
|
+
```
|
33
|
+
|
34
|
+
Then specify which field on your `User` record is the email field with:
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
class User < ApplicationRecord
|
38
|
+
passwordless_with :email
|
39
|
+
end
|
40
|
+
```
|
41
|
+
|
42
|
+
Finally, mount the engine in your routes:
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
Rails.application.routes.draw do
|
46
|
+
passwordless_for :users
|
47
|
+
|
48
|
+
# other routes
|
49
|
+
end
|
50
|
+
```
|
51
|
+
|
52
|
+
## Getting the current user, restricting access, the usual
|
53
|
+
|
54
|
+
Passwordless doesn't give you `current_user` automatically -- it's dead easy to add it though:
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
class ApplicationController < ActionController::Base
|
58
|
+
include Passwordless::ControllerHelpers # <-- This!
|
59
|
+
|
60
|
+
# ...
|
61
|
+
|
62
|
+
helper_method :current_user
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def current_user
|
67
|
+
@current_user ||= authenticate_by_cookie(User)
|
68
|
+
end
|
69
|
+
|
70
|
+
def require_user!
|
71
|
+
return if current_user
|
72
|
+
redirect_to root_path, flash: {error: 'You are not worthy!'}
|
73
|
+
end
|
74
|
+
end
|
75
|
+
```
|
76
|
+
|
77
|
+
## Providing your own templates
|
78
|
+
|
79
|
+
Override `passwordless`' bundled views by adding your own. `passwordless` has 2 action views and 1 mailer view:
|
80
|
+
|
81
|
+
```sh
|
82
|
+
# the form where the user inputs their email address
|
83
|
+
app/views/passwordless/sessions/new.html.erb
|
84
|
+
# shown after a user requests a magic link
|
85
|
+
app/views/passwordless/sessions/create.html.erb
|
86
|
+
# the mail with the magic link that gets sent
|
87
|
+
app/views/passwordless/mailer/magic_link.text.erb
|
88
|
+
```
|
89
|
+
|
90
|
+
See [the bundled views](https://github.com/mikker/passwordless/tree/master/app/views/passwordless).
|
91
|
+
|
92
|
+
## Registering new users
|
93
|
+
|
94
|
+
Because your `User` record is just any other record, you just create one like you normally would. Passwordless provides a helper method you can use to sign in the created user after it is saved like so:
|
95
|
+
|
96
|
+
```ruby
|
97
|
+
class UsersController < ApplicationController
|
98
|
+
include Passwordless::ControllerHelpers # <-- This!
|
99
|
+
# (unless you already have it in your ApplicationController)
|
100
|
+
|
101
|
+
def create
|
102
|
+
@user = User.new user_params
|
103
|
+
|
104
|
+
if @user.save
|
105
|
+
sign_in @user # <-- And this!
|
106
|
+
redirect_to @user, flash: {notice: 'Welcome!'}
|
107
|
+
else
|
108
|
+
render :new
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# ...
|
113
|
+
end
|
114
|
+
```
|
115
|
+
|
116
|
+
Et voilá:
|
117
|
+
|
118
|
+
```ruby
|
119
|
+
class VerySecretThingsController < ApplicationController
|
120
|
+
before_filter :require_user!
|
121
|
+
|
122
|
+
def index
|
123
|
+
@things = current_user.very_secret_things
|
124
|
+
end
|
125
|
+
end
|
126
|
+
```
|
6
127
|
|
7
128
|
# License
|
8
129
|
|
data/Rakefile
CHANGED
@@ -17,11 +17,8 @@ end
|
|
17
17
|
APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
|
18
18
|
load 'rails/tasks/engine.rake'
|
19
19
|
|
20
|
-
|
21
20
|
load 'rails/tasks/statistics.rake'
|
22
21
|
|
23
|
-
|
24
|
-
|
25
22
|
require 'bundler/gem_tasks'
|
26
23
|
|
27
24
|
require 'rake/testtask'
|
@@ -32,5 +29,4 @@ Rake::TestTask.new(:test) do |t|
|
|
32
29
|
t.verbose = false
|
33
30
|
end
|
34
31
|
|
35
|
-
|
36
32
|
task default: :test
|
@@ -2,6 +2,8 @@ module Passwordless
|
|
2
2
|
class SessionsController < ApplicationController
|
3
3
|
include ControllerHelpers
|
4
4
|
|
5
|
+
helper_method :authenticatable_resource
|
6
|
+
|
5
7
|
def new
|
6
8
|
@email_field = authenticatable_class.passwordless_email_field
|
7
9
|
|
@@ -29,25 +31,36 @@ module Passwordless
|
|
29
31
|
|
30
32
|
def show
|
31
33
|
session = Session.valid.find_by!(
|
32
|
-
authenticatable_type:
|
34
|
+
authenticatable_type: authenticatable_classname,
|
33
35
|
token: params[:token]
|
34
36
|
)
|
35
37
|
|
36
|
-
sign_in
|
38
|
+
sign_in session.authenticatable
|
37
39
|
|
38
40
|
redirect_to main_app.root_path
|
39
41
|
end
|
40
42
|
|
41
43
|
def destroy
|
42
|
-
sign_out
|
43
|
-
|
44
|
+
sign_out authenticatable_class
|
44
45
|
redirect_to main_app.root_path
|
45
46
|
end
|
46
47
|
|
47
48
|
private
|
48
49
|
|
50
|
+
def authenticatable
|
51
|
+
params.fetch(:authenticatable)
|
52
|
+
end
|
53
|
+
|
54
|
+
def authenticatable_classname
|
55
|
+
authenticatable.to_s.camelize
|
56
|
+
end
|
57
|
+
|
49
58
|
def authenticatable_class
|
50
|
-
|
59
|
+
authenticatable_classname.constantize
|
60
|
+
end
|
61
|
+
|
62
|
+
def authenticatable_resource
|
63
|
+
authenticatable.pluralize
|
51
64
|
end
|
52
65
|
end
|
53
66
|
end
|
@@ -1,30 +1,29 @@
|
|
1
1
|
module Passwordless
|
2
2
|
module ControllerHelpers
|
3
|
-
|
4
|
-
|
5
|
-
key = :"#{authenticatable_class.to_s.underscore}_id"
|
3
|
+
def authenticate_by_cookie(authenticatable_class)
|
4
|
+
key = cookie_name(authenticatable_class)
|
6
5
|
authenticatable_id = cookies.encrypted[key]
|
7
6
|
return unless authenticatable_id
|
8
7
|
|
9
8
|
authenticatable_class.find_by(id: authenticatable_id)
|
10
9
|
end
|
11
10
|
|
12
|
-
def sign_in
|
13
|
-
key =
|
11
|
+
def sign_in(authenticatable)
|
12
|
+
key = cookie_name(authenticatable.class)
|
14
13
|
cookies.encrypted.permanent[key] = { value: authenticatable.id }
|
15
14
|
authenticatable
|
16
15
|
end
|
17
16
|
|
18
|
-
def sign_out
|
19
|
-
key =
|
17
|
+
def sign_out(authenticatable_class)
|
18
|
+
key = cookie_name(authenticatable_class)
|
20
19
|
cookies.encrypted.permanent[key] = { value: nil }
|
21
20
|
cookies.delete(key)
|
22
21
|
end
|
23
22
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
23
|
+
private
|
24
|
+
|
25
|
+
def cookie_name(authenticatable_class)
|
26
|
+
:"#{authenticatable_class.to_s.underscore}_id"
|
27
|
+
end
|
29
28
|
end
|
30
29
|
end
|
@@ -1,10 +1,15 @@
|
|
1
1
|
module Passwordless
|
2
2
|
class Mailer < ActionMailer::Base
|
3
|
-
default from:
|
3
|
+
default from: Passwordless.default_from_address
|
4
4
|
|
5
5
|
def magic_link(session)
|
6
6
|
@session = session
|
7
7
|
|
8
|
+
authenticatable_resource_name =
|
9
|
+
@session.authenticatable_type.underscore.pluralize
|
10
|
+
@magic_link =
|
11
|
+
send(authenticatable_resource_name).token_sign_in_url(session.token)
|
12
|
+
|
8
13
|
email_field = @session.authenticatable.class.passwordless_email_field
|
9
14
|
mail to: @session.authenticatable.send(email_field), subject: "Your magic link ✨"
|
10
15
|
end
|
@@ -1,2 +1,2 @@
|
|
1
1
|
Here's your link:
|
2
|
-
<%=
|
2
|
+
<%= @magic_link %>
|
@@ -1,4 +1,4 @@
|
|
1
|
-
<%= form_for @session, url:
|
1
|
+
<%= form_for @session, url: send(authenticatable_resource).sign_in_path do |f| %>
|
2
2
|
<% email_field_name = :"passwordless[#{@email_field}]" %>
|
3
3
|
<%= text_field_tag email_field_name, params.fetch(email_field_name, nil) %>
|
4
4
|
<%= f.submit 'Send magic link' %>
|
data/config/routes.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
Passwordless::Engine.routes.draw do
|
2
2
|
get '/sign_in', to: 'sessions#new', as: :sign_in
|
3
3
|
post '/sign_in', to: 'sessions#create'
|
4
|
-
get '/sign_in_create', to: 'sessions#create_test'
|
5
4
|
get '/sign_in/:token', to: 'sessions#show', as: :token_sign_in
|
6
5
|
match '/sign_out', to: 'sessions#destroy', via: %i[get delete], as: :sign_out
|
7
6
|
end
|
data/lib/passwordless.rb
CHANGED
data/lib/passwordless/engine.rb
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
module Passwordless
|
2
2
|
class Engine < ::Rails::Engine
|
3
3
|
isolate_namespace Passwordless
|
4
|
+
|
5
|
+
config.to_prepare do
|
6
|
+
require 'passwordless/router_helpers'
|
7
|
+
ActionDispatch::Routing::Mapper.include RouterHelpers
|
8
|
+
require 'passwordless/model_helpers'
|
9
|
+
ActiveRecord::Base.extend ModelHelpers
|
10
|
+
end
|
4
11
|
end
|
5
12
|
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Passwordless
|
2
|
+
module RouterHelpers
|
3
|
+
def passwordless_for(resource, at: nil, as: nil)
|
4
|
+
mount(
|
5
|
+
Passwordless::Engine,
|
6
|
+
at: at || resource.to_s,
|
7
|
+
as: as || resource.to_s,
|
8
|
+
defaults: { authenticatable: resource.to_s.singularize }
|
9
|
+
)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/lib/passwordless/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: passwordless
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mikkel Malmberg
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-11-
|
11
|
+
date: 2017-11-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -38,7 +38,7 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
-
description:
|
41
|
+
description: Description of Passwordless.
|
42
42
|
email:
|
43
43
|
- mikkel@brnbw.com
|
44
44
|
executables: []
|
@@ -61,6 +61,8 @@ files:
|
|
61
61
|
- db/migrate/20171104221735_create_passwordless_sessions.rb
|
62
62
|
- lib/passwordless.rb
|
63
63
|
- lib/passwordless/engine.rb
|
64
|
+
- lib/passwordless/model_helpers.rb
|
65
|
+
- lib/passwordless/router_helpers.rb
|
64
66
|
- lib/passwordless/version.rb
|
65
67
|
- lib/tasks/passwordless_tasks.rake
|
66
68
|
homepage: https://github.com/mikker/passwordless
|
@@ -86,5 +88,5 @@ rubyforge_project:
|
|
86
88
|
rubygems_version: 2.6.13
|
87
89
|
signing_key:
|
88
90
|
specification_version: 4
|
89
|
-
summary:
|
91
|
+
summary: Summary of Passwordless.
|
90
92
|
test_files: []
|