Skip to content
Permalink
Browse files

Initial

  • Loading branch information...
mikker committed Nov 5, 2017
0 parents commit e8b2578a46a3f2ea91e4de138429071a18f71780
Showing with 1,717 additions and 0 deletions.
  1. +7 βˆ’0 .gitignore
  2. +4 βˆ’0 .projections.json
  3. +14 βˆ’0 Gemfile
  4. +119 βˆ’0 Gemfile.lock
  5. +20 βˆ’0 MIT-LICENSE
  6. +9 βˆ’0 README.md
  7. +36 βˆ’0 Rakefile
  8. +5 βˆ’0 app/controllers/passwordless/application_controller.rb
  9. +53 βˆ’0 app/controllers/passwordless/sessions_controller.rb
  10. +30 βˆ’0 app/lib/passwordless/controller_helpers.rb
  11. +12 βˆ’0 app/mailers/passwordless/mailer.rb
  12. +5 βˆ’0 app/models/passwordless/application_record.rb
  13. +30 βˆ’0 app/models/passwordless/session.rb
  14. +2 βˆ’0 app/views/passwordless/mailer/magic_link.text.erb
  15. +1 βˆ’0 app/views/passwordless/sessions/create.html.erb
  16. +5 βˆ’0 app/views/passwordless/sessions/new.html.erb
  17. +14 βˆ’0 bin/rails
  18. +7 βˆ’0 config/routes.rb
  19. +18 βˆ’0 db/migrate/20171104221735_create_passwordless_sessions.rb
  20. +5 βˆ’0 lib/passwordless.rb
  21. +5 βˆ’0 lib/passwordless/engine.rb
  22. +3 βˆ’0 lib/passwordless/version.rb
  23. +4 βˆ’0 lib/tasks/passwordless_tasks.rake
  24. +22 βˆ’0 passwordless.gemspec
  25. +74 βˆ’0 test/controllers/passwordless/sessions_controller_test.rb
  26. +6 βˆ’0 test/dummy/Rakefile
  27. +5 βˆ’0 test/dummy/app/assets/config/manifest.js
  28. 0 test/dummy/app/assets/images/.keep
  29. +13 βˆ’0 test/dummy/app/assets/javascripts/application.js
  30. +13 βˆ’0 test/dummy/app/assets/javascripts/cable.js
  31. 0 test/dummy/app/assets/javascripts/channels/.keep
  32. +2 βˆ’0 test/dummy/app/assets/javascripts/users.js
  33. +15 βˆ’0 test/dummy/app/assets/stylesheets/application.css
  34. +80 βˆ’0 test/dummy/app/assets/stylesheets/scaffold.css
  35. +4 βˆ’0 test/dummy/app/assets/stylesheets/users.css
  36. +4 βˆ’0 test/dummy/app/channels/application_cable/channel.rb
  37. +4 βˆ’0 test/dummy/app/channels/application_cable/connection.rb
  38. +18 βˆ’0 test/dummy/app/controllers/application_controller.rb
  39. 0 test/dummy/app/controllers/concerns/.keep
  40. +7 βˆ’0 test/dummy/app/controllers/secrets_controller.rb
  41. +58 βˆ’0 test/dummy/app/controllers/users_controller.rb
  42. +2 βˆ’0 test/dummy/app/helpers/application_helper.rb
  43. +2 βˆ’0 test/dummy/app/helpers/users_helper.rb
  44. +2 βˆ’0 test/dummy/app/jobs/application_job.rb
  45. +4 βˆ’0 test/dummy/app/mailers/application_mailer.rb
  46. +3 βˆ’0 test/dummy/app/models/application_record.rb
  47. 0 test/dummy/app/models/concerns/.keep
  48. +5 βˆ’0 test/dummy/app/models/user.rb
  49. +23 βˆ’0 test/dummy/app/views/layouts/application.html.erb
  50. +13 βˆ’0 test/dummy/app/views/layouts/mailer.html.erb
  51. +1 βˆ’0 test/dummy/app/views/layouts/mailer.text.erb
  52. +22 βˆ’0 test/dummy/app/views/users/_form.html.erb
  53. +6 βˆ’0 test/dummy/app/views/users/edit.html.erb
  54. +27 βˆ’0 test/dummy/app/views/users/index.html.erb
  55. +5 βˆ’0 test/dummy/app/views/users/new.html.erb
  56. +9 βˆ’0 test/dummy/app/views/users/show.html.erb
  57. +3 βˆ’0 test/dummy/bin/bundle
  58. +4 βˆ’0 test/dummy/bin/rails
  59. +4 βˆ’0 test/dummy/bin/rake
  60. +38 βˆ’0 test/dummy/bin/setup
  61. +29 βˆ’0 test/dummy/bin/update
  62. +11 βˆ’0 test/dummy/bin/yarn
  63. +5 βˆ’0 test/dummy/config.ru
  64. +26 βˆ’0 test/dummy/config/application.rb
  65. +5 βˆ’0 test/dummy/config/boot.rb
  66. +10 βˆ’0 test/dummy/config/cable.yml
  67. +25 βˆ’0 test/dummy/config/database.yml
  68. +5 βˆ’0 test/dummy/config/environment.rb
  69. +47 βˆ’0 test/dummy/config/environments/development.rb
  70. +83 βˆ’0 test/dummy/config/environments/production.rb
  71. +42 βˆ’0 test/dummy/config/environments/test.rb
  72. +8 βˆ’0 test/dummy/config/initializers/application_controller_renderer.rb
  73. +7 βˆ’0 test/dummy/config/initializers/backtrace_silencers.rb
  74. +5 βˆ’0 test/dummy/config/initializers/cookies_serializer.rb
  75. +4 βˆ’0 test/dummy/config/initializers/filter_parameter_logging.rb
  76. +16 βˆ’0 test/dummy/config/initializers/inflections.rb
  77. +4 βˆ’0 test/dummy/config/initializers/mime_types.rb
  78. +14 βˆ’0 test/dummy/config/initializers/wrap_parameters.rb
  79. +33 βˆ’0 test/dummy/config/locales/en.yml
  80. +56 βˆ’0 test/dummy/config/puma.rb
  81. +13 βˆ’0 test/dummy/config/routes.rb
  82. +32 βˆ’0 test/dummy/config/secrets.yml
  83. +6 βˆ’0 test/dummy/config/spring.rb
  84. +9 βˆ’0 test/dummy/db/migrate/20171104225303_create_users.rb
  85. +34 βˆ’0 test/dummy/db/schema.rb
  86. 0 test/dummy/lib/assets/.keep
  87. 0 test/dummy/log/.keep
  88. +5 βˆ’0 test/dummy/package.json
  89. +67 βˆ’0 test/dummy/public/404.html
  90. +67 βˆ’0 test/dummy/public/422.html
  91. +66 βˆ’0 test/dummy/public/500.html
  92. 0 test/dummy/public/apple-touch-icon-precomposed.png
  93. 0 test/dummy/public/apple-touch-icon.png
  94. 0 test/dummy/public/favicon.ico
  95. +15 βˆ’0 test/fixtures/passwordless/sessions.yml
  96. +8 βˆ’0 test/integration/navigation_test.rb
  97. 0 test/mailers/passwordless/mailer_test.rb
  98. +30 βˆ’0 test/models/passwordless/session_test.rb
  99. +7 βˆ’0 test/passwordless_test.rb
  100. +17 βˆ’0 test/test_helper.rb
@@ -0,0 +1,7 @@
.bundle/
log/*.log
pkg/
test/dummy/db/*.sqlite3
test/dummy/db/*.sqlite3-journal
test/dummy/log/*.log
test/dummy/tmp/
@@ -0,0 +1,4 @@
{
"app/*.rb": { "alternate": "test/{}_test.rb" },
"test/*_test.rb": { "alternate": "app/{}.rb" }
}
14 Gemfile
@@ -0,0 +1,14 @@
source 'https://rubygems.org'

# Declare your gem's dependencies in passwordless.gemspec.
# Bundler will treat runtime dependencies like base dependencies, and
# development dependencies will be added by default to the :development group.
gemspec

# Declare any dependencies that are still in development here instead of in
# your gemspec. These might include edge Rails or gems from your path or
# Git. Remember to move these dependencies to your gemspec before releasing
# your gem to rubygems.org.

# To use a debugger
# gem 'byebug', group: [:development, :test]
@@ -0,0 +1,119 @@
PATH
remote: .
specs:
passwordless (0.1.0)
rails (~> 5.1.4)

GEM
remote: https://rubygems.org/
specs:
actioncable (5.1.4)
actionpack (= 5.1.4)
nio4r (~> 2.0)
websocket-driver (~> 0.6.1)
actionmailer (5.1.4)
actionpack (= 5.1.4)
actionview (= 5.1.4)
activejob (= 5.1.4)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0)
actionpack (5.1.4)
actionview (= 5.1.4)
activesupport (= 5.1.4)
rack (~> 2.0)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
actionview (5.1.4)
activesupport (= 5.1.4)
builder (~> 3.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.3)
activejob (5.1.4)
activesupport (= 5.1.4)
globalid (>= 0.3.6)
activemodel (5.1.4)
activesupport (= 5.1.4)
activerecord (5.1.4)
activemodel (= 5.1.4)
activesupport (= 5.1.4)
arel (~> 8.0)
activesupport (5.1.4)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (~> 0.7)
minitest (~> 5.1)
tzinfo (~> 1.1)
arel (8.0.0)
builder (3.2.3)
concurrent-ruby (1.0.5)
crass (1.0.2)
erubi (1.7.0)
globalid (0.4.1)
activesupport (>= 4.2.0)
i18n (0.9.1)
concurrent-ruby (~> 1.0)
loofah (2.1.1)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
mail (2.7.0)
mini_mime (>= 0.1.1)
method_source (0.9.0)
mini_mime (0.1.4)
mini_portile2 (2.3.0)
minitest (5.10.3)
nio4r (2.1.0)
nokogiri (1.8.1)
mini_portile2 (~> 2.3.0)
rack (2.0.3)
rack-test (0.7.0)
rack (>= 1.0, < 3)
rails (5.1.4)
actioncable (= 5.1.4)
actionmailer (= 5.1.4)
actionpack (= 5.1.4)
actionview (= 5.1.4)
activejob (= 5.1.4)
activemodel (= 5.1.4)
activerecord (= 5.1.4)
activesupport (= 5.1.4)
bundler (>= 1.3.0)
railties (= 5.1.4)
sprockets-rails (>= 2.0.0)
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
rails-html-sanitizer (1.0.3)
loofah (~> 2.0)
railties (5.1.4)
actionpack (= 5.1.4)
activesupport (= 5.1.4)
method_source
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
rake (12.2.1)
sprockets (3.7.1)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
sprockets-rails (3.2.1)
actionpack (>= 4.0)
activesupport (>= 4.0)
sprockets (>= 3.0.0)
sqlite3 (1.3.13)
thor (0.20.0)
thread_safe (0.3.6)
tzinfo (1.2.4)
thread_safe (~> 0.1)
websocket-driver (0.6.5)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.2)

PLATFORMS
ruby

DEPENDENCIES
passwordless!
sqlite3

BUNDLED WITH
1.16.0
@@ -0,0 +1,20 @@
Copyright 2017 Mikkel Malmberg

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,9 @@
# Passwordless

Add authentication to your Rails app without all the icky-ness of passwords.

_WIP_

# License

MIT
@@ -0,0 +1,36 @@
begin
require 'bundler/setup'
rescue LoadError
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
end

require 'rdoc/task'

RDoc::Task.new(:rdoc) do |rdoc|
rdoc.rdoc_dir = 'rdoc'
rdoc.title = 'Passwordless'
rdoc.options << '--line-numbers'
rdoc.rdoc_files.include('README.md')
rdoc.rdoc_files.include('lib/**/*.rb')
end

APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
load 'rails/tasks/engine.rake'


load 'rails/tasks/statistics.rake'



require 'bundler/gem_tasks'

require 'rake/testtask'

Rake::TestTask.new(:test) do |t|
t.libs << 'test'
t.pattern = 'test/**/*_test.rb'
t.verbose = false
end


task default: :test
@@ -0,0 +1,5 @@
module Passwordless
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
end
end
@@ -0,0 +1,53 @@
module Passwordless
class SessionsController < ApplicationController
include ControllerHelpers

def new
@email_field = authenticatable_class.passwordless_email_field

@session = Session.new
end

def create
email_field = authenticatable_class.passwordless_email_field
authenticatable = authenticatable_class.where(
"lower(#{email_field}) = ?", params[:passwordless][email_field]
).first

session = Session.new.tap do |us|
us.remote_addr = request.remote_addr
us.user_agent = request.env['HTTP_USER_AGENT']
us.authenticatable = authenticatable
end

if session.save
Mailer.magic_link(session).deliver_now
end

render
end

def show
session = Session.valid.find_by!(
authenticatable_type: params[:authenticatable],
token: params[:token]
)

sign_in! session.authenticatable

redirect_to main_app.root_path
end

def destroy
sign_out! authenticatable_class

redirect_to main_app.root_path
end

private

def authenticatable_class
params[:authenticatable].constantize
end
end
end
@@ -0,0 +1,30 @@
module Passwordless
module ControllerHelpers

def authenticate!(authenticatable_class)
key = :"#{authenticatable_class.to_s.underscore}_id"
authenticatable_id = cookies.encrypted[key]
return unless authenticatable_id

authenticatable_class.find_by(id: authenticatable_id)
end

def sign_in!(authenticatable)
key = :"#{authenticatable.class.to_s.underscore}_id"
cookies.encrypted.permanent[key] = { value: authenticatable.id }
authenticatable
end

def sign_out!(authenticatable_class)
key = :"#{authenticatable_class.to_s.underscore}_id"
cookies.encrypted.permanent[key] = { value: nil }
cookies.delete(key)
end

# def self.included(kls)
# kls.class_eval do
# # helper_method :current_user
# end
# end
end
end
@@ -0,0 +1,12 @@
module Passwordless
class Mailer < ActionMailer::Base
default from: 'from@example.com'

def magic_link(session)
@session = session

email_field = @session.authenticatable.class.passwordless_email_field
mail to: @session.authenticatable.send(email_field), subject: "Your magic link ✨"
end
end
end
@@ -0,0 +1,5 @@
module Passwordless
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
end
end
@@ -0,0 +1,30 @@
module Passwordless
class Session < ApplicationRecord
belongs_to :authenticatable, polymorphic: true

validates \
:timeout_at,
:expires_at,
:user_agent,
:remote_addr,
:token,
presence: true

before_validation :set_defaults

scope :valid, lambda {
where('timeout_at > ? AND expires_at > ?', Time.current, Time.current)
}

private

def set_defaults
self.expires_at ||= 1.year.from_now
self.timeout_at ||= 1.hour.from_now
self.token ||= loop do
token = SecureRandom.urlsafe_base64(32)
break token unless Session.find_by(token: token)
end
end
end
end
@@ -0,0 +1,2 @@
Here's your link:
<%= passwordless.token_sign_in_url @session.token %>
@@ -0,0 +1 @@
<p>If we found you in the system, we've sent you an email.</p>
@@ -0,0 +1,5 @@
<%= form_for @session, url: passwordless.sign_in_path do |f| %>
<% email_field_name = :"passwordless[#{@email_field}]" %>
<%= text_field_tag email_field_name, params.fetch(email_field_name, nil) %>
<%= f.submit 'Send magic link' %>
<% end %>
@@ -0,0 +1,14 @@
#!/usr/bin/env ruby
# This command will automatically be run when you run "rails" with Rails gems
# installed from the root of your application.

ENGINE_ROOT = File.expand_path('../..', __FILE__)
ENGINE_PATH = File.expand_path('../../lib/passwordless/engine', __FILE__)
APP_PATH = File.expand_path('../../test/dummy/config/application', __FILE__)

# Set up gems listed in the Gemfile.
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])

require 'rails/all'
require 'rails/engine/commands'
@@ -0,0 +1,7 @@
Passwordless::Engine.routes.draw do
get '/sign_in', to: 'sessions#new', as: :sign_in
post '/sign_in', to: 'sessions#create'
get '/sign_in_create', to: 'sessions#create_test'
get '/sign_in/:token', to: 'sessions#show', as: :token_sign_in
match '/sign_out', to: 'sessions#destroy', via: %i[get delete], as: :sign_out
end
Oops, something went wrong.

0 comments on commit e8b2578

Please sign in to comment.
You can’t perform that action at this time.