passwordless 0.1.0 → 0.2.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
  SHA1:
3
- metadata.gz: 7975d0dabfd39211005c2a34f3f3d967755b0a70
4
- data.tar.gz: 621a7327a0375aeeb6e4dafb990bce78d4bf32dc
3
+ metadata.gz: d3bdc9fe84110cc587576344e493cbe16a0a9a74
4
+ data.tar.gz: 1d7558d9be99a4764c21eb6fda029a765a9540bb
5
5
  SHA512:
6
- metadata.gz: 55ca6da5e10b2a0d8e92d0dad1cc048214efd7e32a9d6fecc40a2ebce102744772c96b6b128fae53d1b14b3709bb49f1225c82c6d5a08507eef8db29fc1ce0f9
7
- data.tar.gz: 925dbd8b6d98ac9a68d5c12bdc940bc38a1dc8c4e82b47c941d2de768b0cdd43edf2681a900e213eac366fd1e17dab9031650869cc2ce6801bd24881989e6320
6
+ metadata.gz: 6ec72945db7eec026bd640a3116c82fc9b5eea790cea4405bf9593815ed2e02edc3d91e58c82bdc52122a6190e512eb8013e51ca198d0b47cd961491d5f471aa
7
+ data.tar.gz: 0ca8c6e2e4d6bed6fab0351200acef5ac9e65a1526c2cd7503d751d967da8fd96d7200d005310600af693af00fde068aee7541b185e8969612342f32155dca4a
data/README.md CHANGED
@@ -1,8 +1,129 @@
1
- # Passwordless
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
- _WIP_
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: params[:authenticatable],
34
+ authenticatable_type: authenticatable_classname,
33
35
  token: params[:token]
34
36
  )
35
37
 
36
- sign_in! session.authenticatable
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! authenticatable_class
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
- params[:authenticatable].constantize
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
- def authenticate!(authenticatable_class)
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!(authenticatable)
13
- key = :"#{authenticatable.class.to_s.underscore}_id"
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!(authenticatable_class)
19
- key = :"#{authenticatable_class.to_s.underscore}_id"
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
- # def self.included(kls)
25
- # kls.class_eval do
26
- # # helper_method :current_user
27
- # end
28
- # end
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: 'from@example.com'
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
- <%= passwordless.token_sign_in_url @session.token %>
2
+ <%= @magic_link %>
@@ -1,4 +1,4 @@
1
- <%= form_for @session, url: passwordless.sign_in_path do |f| %>
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' %>
@@ -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
@@ -1,5 +1,5 @@
1
1
  require "passwordless/engine"
2
2
 
3
3
  module Passwordless
4
- # Your code goes here...
4
+ mattr_accessor(:default_from_address) { 'CHANGE_ME@example.com' }
5
5
  end
@@ -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,7 @@
1
+ module Passwordless
2
+ module ModelHelpers
3
+ def passwordless_with(field)
4
+ define_singleton_method(:passwordless_email_field) { field }
5
+ end
6
+ end
7
+ 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
@@ -1,3 +1,3 @@
1
1
  module Passwordless
2
- VERSION = '0.1.0'
2
+ VERSION = '0.2.0'
3
3
  end
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.1.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-05 00:00:00.000000000 Z
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: Add authentication to your Rails app without all the icky-ness of passwords.
91
+ summary: Summary of Passwordless.
90
92
  test_files: []