cheapskate 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8f4d0d8936e75eacf28e812848025458e408a858
4
+ data.tar.gz: 5d6a36c1f6e59a973442b599cceefc895d5cd9a0
5
+ SHA512:
6
+ metadata.gz: 254b473de825e643c2a2ed9b76ac427803c3e907552f8f58790789bf120597a0797156b7093c189b3d860e7c92607f97af19d0b4213a5779764c891d18b4e498
7
+ data.tar.gz: 548124543f1b39b3a7c72ab6181b30f61c05b3bce9b74261fa1f651e77db72e14567f23fc03eb179b482edb2e1040c6752ddf2340ae93c6657fe9fd1c5db94e0
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Dan Tao
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,46 @@
1
+ # Cheapskate
2
+
3
+ Seamlessly jump to a separate domain for HTTPS login and then back.
4
+
5
+ ## Note
6
+
7
+ The below information is a work in progress. Don't use this yet; it isn't ready.
8
+
9
+ ## Usage
10
+
11
+ OK, here's how this works. First, obviously, you add cheapskate to your Gemfile:
12
+
13
+ gem 'cheapskate'
14
+
15
+ The gem provides its own Rails engine, which adds the following to your app:
16
+
17
+ ### Routes
18
+
19
+ POST /login
20
+ GET /logged_in
21
+
22
+ POST /register
23
+ GET /registered
24
+
25
+ ### Models
26
+
27
+ - `SingleUseLogin`
28
+ - `SingleUseNotice`
29
+
30
+ ### Customization
31
+
32
+ Both the **/logged_in** and **/registered** routes redirect back to `Cheapskate::ROOT_PATH`, which
33
+ defaults to `"/"`.
34
+
35
+ Internally much of the logic where the gem hooks into your application is found in the
36
+ `Cheapskate::Client` class. You can inherit from this class and override any of these methods if you
37
+ want:
38
+
39
+ - `create_user(params)`
40
+ - `find_user(params)`
41
+ - `authenticate_user(user, params)`
42
+ - `user_name(user)`
43
+ - `store_user_in_session(user, session)`
44
+
45
+ If you implement your own client, then you must set the `Cheapskate::CLIENT_CLASS` constant
46
+ accordingly. (Yeah, I know that's bad. Will think more on this.)
data/Rakefile ADDED
@@ -0,0 +1,34 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'Cheapskate'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+
21
+
22
+ Bundler::GemHelper.install_tasks
23
+
24
+ require 'rake/testtask'
25
+
26
+ Rake::TestTask.new(:test) do |t|
27
+ t.libs << 'lib'
28
+ t.libs << 'test'
29
+ t.pattern = 'test/**/*_test.rb'
30
+ t.verbose = false
31
+ end
32
+
33
+
34
+ task default: :test
@@ -0,0 +1,85 @@
1
+ module Cheapskate
2
+ class ApplicationController < ActionController::Base
3
+ # Typically (or so I read) you would make this a controller method and expose it via #helper;
4
+ # HOWEVER, I want this method to be available both to me (ApplicationController) and the client
5
+ # app. I'm guessing this is not the right approach. But step 1 is just getting it all to work.
6
+ include Cheapskate::ApplicationHelper
7
+
8
+ before_filter :initialize_client
9
+ before_filter :check_for_notification
10
+
11
+ def register
12
+ user = @client.create_user(params)
13
+ redirect_to(registered_url(url_options_for_protocol(:http)))
14
+ end
15
+
16
+ def complete_registration
17
+ alert_and_redirect("Thank you for registering.", Cheapskate::ROOT_PATH)
18
+ end
19
+
20
+ def login
21
+ user = @client.find_user(params)
22
+ if user.nil?
23
+ return alert_and_redirect('That user does not exist.', login_path)
24
+ end
25
+
26
+ if !@client.authenticate_user(user, params)
27
+ return alert_and_redirect('You have entered an incorrect password.', login_path)
28
+ end
29
+
30
+ login = @client.create_single_use_login!(user)
31
+ redirect_to(logged_in_url(url_options_for_protocol(:http).merge(:token => login.token)))
32
+ end
33
+
34
+ def complete_login
35
+ login = @client.get_single_use_login(params[:token])
36
+ if login.nil?
37
+ alert_and_redirect('Unable to verify login. Try again?', login_path)
38
+ end
39
+
40
+ user = login.get_user_and_destroy!
41
+ @client.store_user_in_session(user, session)
42
+ alert_and_redirect("Welcome, #{@client.user_name(user)}!", Cheapskate::ROOT_PATH)
43
+ end
44
+
45
+ protected
46
+
47
+ def alert_and_redirect(message, path)
48
+ uri = URI(path)
49
+ if uri.absolute? && uri.host != request.host
50
+ notice = @client.create_single_use_notice!(message)
51
+ uri.query = add_to_query(uri.query, :notice => notice.token)
52
+ else
53
+ flash[:notice] = message
54
+ end
55
+
56
+ logger.info("CHEAPSKATE - Redirecting...")
57
+ logger.info("CHEAPSKATE - FROM: #{request.path}")
58
+ logger.info("CHEAPSKATE - TO: #{path}")
59
+ logger.info("CHEAPSKATE - =>: #{uri})")
60
+
61
+ redirect_to(uri.to_s)
62
+ end
63
+
64
+ def add_to_query(query, parameters)
65
+ query ||= ''
66
+ start = query.length > 0 ? '&' : ''
67
+ query + start + parameters.map { |name, value| "#{URI.escape(name)}=#{URI.escape(value)}" }.join('&')
68
+ end
69
+
70
+ private
71
+
72
+ def initialize_client
73
+ @client = Cheapskate::CLIENT_CLASS.new
74
+ end
75
+
76
+ def check_for_notification
77
+ if params.include?(:notice)
78
+ @notification = get_single_use_notice(params.delete(:notice))
79
+ flash[:notice] = @notification.get_message_and_destroy!
80
+
81
+ redirect_to(request.path, params)
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,19 @@
1
+ module Cheapskate
2
+ module ApplicationHelper
3
+ def url_options_for_protocol(protocol)
4
+ if protocol == :https
5
+ {
6
+ :protocol => Cheapskate::HTTPS_PROTOCOL,
7
+ :host => Cheapskate::HTTPS_HOST,
8
+ :port => Cheapskate::HTTPS_PORT
9
+ }
10
+ else
11
+ {
12
+ :protocol => Cheapskate::HTTP_PROTOCOL,
13
+ :host => Cheapskate::HTTP_HOST,
14
+ :port => Cheapskate::HTTP_PORT
15
+ }
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ require 'randy'
2
+
3
+ class SingleUseLogin < ActiveRecord::Base
4
+ belongs_to :user
5
+
6
+ validates_presence_of :user_id
7
+
8
+ before_create :generate_token
9
+
10
+ def generate_token
11
+ self.token ||= Randy.string(30)
12
+ end
13
+
14
+ def get_user_and_destroy!
15
+ return self.user
16
+ ensure
17
+ self.destroy!
18
+ end
19
+ end
@@ -0,0 +1,17 @@
1
+ require 'randy'
2
+
3
+ class SingleUseNotice < ActiveRecord::Base
4
+ validates_presence_of :message
5
+
6
+ before_create :generate_token
7
+
8
+ def generate_token
9
+ self.token ||= Randy.string(30)
10
+ end
11
+
12
+ def get_message_and_destroy!
13
+ return self.message
14
+ ensure
15
+ self.destroy!
16
+ end
17
+ end
data/config/routes.rb ADDED
@@ -0,0 +1,6 @@
1
+ Cheapskate::Engine.routes.draw do
2
+ post 'register' => 'application#register'
3
+ get 'registered' => 'application#complete_registration'
4
+ post 'login' => 'application#login'
5
+ get 'logged_in' => 'application#complete_login'
6
+ end
@@ -0,0 +1,10 @@
1
+ class CreateSingleUseLogins < ActiveRecord::Migration
2
+ def change
3
+ create_table :single_use_logins do |t|
4
+ t.integer :user_id
5
+ t.string :token
6
+ end
7
+
8
+ add_index :single_use_logins, :token
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ class CreateSingleUseNotices < ActiveRecord::Migration
2
+ def change
3
+ create_table :single_use_notices do |t|
4
+ t.string :message
5
+ t.string :token
6
+ end
7
+
8
+ add_index :single_use_notices, :token
9
+ end
10
+ end
@@ -0,0 +1,39 @@
1
+ module Cheapskate
2
+ class Client
3
+ def create_user(params)
4
+ User.create!(params.require(:user).permit(:name, :email, :password, :password_confirmation))
5
+ end
6
+
7
+ def find_user(params)
8
+ User.find_by_email(params[:email])
9
+ end
10
+
11
+ def authenticate_user(user, params)
12
+ user.authenticate(params[:password])
13
+ end
14
+
15
+ def user_name(user)
16
+ user.name
17
+ end
18
+
19
+ def store_user_in_session(user, session)
20
+ session[:user_id] = user.id
21
+ end
22
+
23
+ def create_single_use_login!(user)
24
+ SingleUseLogin.create!(:user => user)
25
+ end
26
+
27
+ def get_single_use_login(token)
28
+ SingleUseLogin.find_by_token(token)
29
+ end
30
+
31
+ def create_single_use_notice!(message)
32
+ SingleUseNotice.create!(:message => message)
33
+ end
34
+
35
+ def get_single_use_notice(token)
36
+ SingleUseNotice.find_by_token(token)
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,5 @@
1
+ module Cheapskate
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace Cheapskate
4
+ end
5
+ end
@@ -0,0 +1,3 @@
1
+ module Cheapskate
2
+ VERSION = "0.0.1"
3
+ end
data/lib/cheapskate.rb ADDED
@@ -0,0 +1,15 @@
1
+ require "cheapskate/client"
2
+ require "cheapskate/engine"
3
+
4
+ module Cheapskate
5
+ HTTP_PROTOCOL = 'http'
6
+ HTTP_HOST = Rails.env.development? && 'localhost' || nil
7
+ HTTP_PORT = Rails.env.development? && 3000 || nil
8
+
9
+ HTTPS_PROTOCOL = Rails.env.development? && 'http' || 'https'
10
+ HTTPS_HOST = Rails.env.development? && 'localhost' || nil
11
+ HTTPS_PORT = Rails.env.development? && 8000 || nil
12
+
13
+ CLIENT_CLASS = Cheapskate::Client
14
+ ROOT_PATH = '/'
15
+ end
@@ -0,0 +1,8 @@
1
+ namespace :cheapskate do
2
+ desc 'Check if everything is set up properly for Cheapskate to work'
3
+ task :check => :environment do
4
+ puts "Checking Cheapskate..."
5
+ puts "#{SingleUseLogin.table_name} doesn't exist!" if !SingleUseLogin.table_exists?
6
+ puts "#{SingleUseNotice.table_name} doesn't exist!" if !SingleUseNotice.table_exists?
7
+ end
8
+ end
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cheapskate
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Dan Tao
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-08-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: randy
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: HTTPS login from a separate domain
42
+ email:
43
+ - daniel.tao@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - app/models/single_use_notice.rb
49
+ - app/models/single_use_login.rb
50
+ - app/helpers/cheapskate/application_helper.rb
51
+ - app/controllers/cheapskate/application_controller.rb
52
+ - config/routes.rb
53
+ - db/migrate/20130808161902_create_single_use_logins.rb
54
+ - db/migrate/20130808161920_create_single_use_notices.rb
55
+ - lib/cheapskate/version.rb
56
+ - lib/cheapskate/client.rb
57
+ - lib/cheapskate/engine.rb
58
+ - lib/tasks/cheapskate_tasks.rake
59
+ - lib/cheapskate.rb
60
+ - LICENSE.txt
61
+ - Rakefile
62
+ - README.md
63
+ homepage: https://github.com/dtao/cheapskate
64
+ licenses:
65
+ - MIT
66
+ metadata: {}
67
+ post_install_message:
68
+ rdoc_options: []
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - '>='
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ requirements: []
82
+ rubyforge_project:
83
+ rubygems_version: 2.0.6
84
+ signing_key:
85
+ specification_version: 4
86
+ summary: Seamlessly jump to a separate domain for HTTPS login and then back
87
+ test_files: []