simple_mobile_oauth 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.
Files changed (60) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Rakefile +32 -0
  4. data/lib/generators/active_record/simple_mobile_oauth_generator.rb +15 -0
  5. data/lib/generators/simple_mobile_oauth/install_generator.rb +39 -0
  6. data/lib/generators/simple_mobile_oauth/simple_mobile_oauth_generator.rb +15 -0
  7. data/lib/generators/templates/identity.rb +16 -0
  8. data/lib/generators/templates/migration.rb +14 -0
  9. data/lib/simple_mobile_oauth/authenticator.rb +122 -0
  10. data/lib/simple_mobile_oauth/identifiable.rb +23 -0
  11. data/lib/simple_mobile_oauth/version.rb +3 -0
  12. data/lib/simple_mobile_oauth.rb +5 -0
  13. data/lib/tasks/simple_mobile_oauth_tasks.rake +4 -0
  14. data/test/dummy/README.rdoc +28 -0
  15. data/test/dummy/Rakefile +6 -0
  16. data/test/dummy/app/assets/javascripts/application.js +13 -0
  17. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  18. data/test/dummy/app/controllers/application_controller.rb +5 -0
  19. data/test/dummy/app/helpers/application_helper.rb +2 -0
  20. data/test/dummy/app/models/identity.rb +16 -0
  21. data/test/dummy/app/models/user.rb +3 -0
  22. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  23. data/test/dummy/bin/bundle +3 -0
  24. data/test/dummy/bin/rails +4 -0
  25. data/test/dummy/bin/rake +4 -0
  26. data/test/dummy/config/application.rb +23 -0
  27. data/test/dummy/config/boot.rb +5 -0
  28. data/test/dummy/config/database.yml +25 -0
  29. data/test/dummy/config/environment.rb +5 -0
  30. data/test/dummy/config/environments/development.rb +37 -0
  31. data/test/dummy/config/environments/production.rb +78 -0
  32. data/test/dummy/config/environments/test.rb +39 -0
  33. data/test/dummy/config/initializers/assets.rb +8 -0
  34. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  35. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  36. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  37. data/test/dummy/config/initializers/inflections.rb +16 -0
  38. data/test/dummy/config/initializers/mime_types.rb +4 -0
  39. data/test/dummy/config/initializers/session_store.rb +3 -0
  40. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  41. data/test/dummy/config/locales/en.yml +23 -0
  42. data/test/dummy/config/routes.rb +56 -0
  43. data/test/dummy/config/secrets.yml +22 -0
  44. data/test/dummy/config.ru +4 -0
  45. data/test/dummy/db/development.sqlite3 +0 -0
  46. data/test/dummy/db/migrate/20141216003747_create_users.rb +8 -0
  47. data/test/dummy/db/migrate/20141216003803_simple_mobile_oauth_migration.rb +14 -0
  48. data/test/dummy/db/schema.rb +32 -0
  49. data/test/dummy/db/test.sqlite3 +0 -0
  50. data/test/dummy/log/development.log +0 -0
  51. data/test/dummy/log/test.log +61 -0
  52. data/test/dummy/public/404.html +67 -0
  53. data/test/dummy/public/422.html +67 -0
  54. data/test/dummy/public/500.html +66 -0
  55. data/test/dummy/public/favicon.ico +0 -0
  56. data/test/dummy/test/fixtures/users.yml +11 -0
  57. data/test/simple_mobile_oauth_test.rb +7 -0
  58. data/test/test_helper.rb +15 -0
  59. data/test/user_test.rb +9 -0
  60. metadata +177 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7dae4e339a5e998c95f6bfda287c99be2bdc272f
4
+ data.tar.gz: 38995f7cd9263b72f4598a966fb277c42813011e
5
+ SHA512:
6
+ metadata.gz: 2e7f1c8907463723201d6b04445a5833e6a8f1ec214fe4d87efee3f2e734478e6d37cc5af44ba4d1a09889b6ee3656de2806b6c6afbf35eafff0764354e7586f
7
+ data.tar.gz: 4e15731713037c23788d34ba32fdd9b9cbc402d40b50af5671248ad6cdfe699385adc350da48e1ef85622372b97fa6ccbddd6f7ff6098c62df1c4428ea12333f
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2014 YOURNAME
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,32 @@
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 = 'SimpleMobileOauth'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+
18
+
19
+
20
+ Bundler::GemHelper.install_tasks
21
+
22
+ require 'rake/testtask'
23
+
24
+ Rake::TestTask.new(:test) do |t|
25
+ t.libs << 'lib'
26
+ t.libs << 'test'
27
+ t.pattern = 'test/**/*_test.rb'
28
+ t.verbose = false
29
+ end
30
+
31
+
32
+ task default: :test
@@ -0,0 +1,15 @@
1
+ require 'rails/generators/active_record'
2
+
3
+ module ActiveRecord
4
+ module Generators
5
+ class SimpleMobileOauthGenerator < ActiveRecord::Generators::Base
6
+ source_root File.expand_path("../templates", __FILE__)
7
+
8
+ def append_to_token_authenticatable_model
9
+ inject_into_class "app/models/#{name}.rb", name.camelize.constantize, <<-END
10
+ include SimpleMobileOauth::Identifiable
11
+ END
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,39 @@
1
+ require 'rails/generators/base'
2
+
3
+ module SimpleMobileOauth
4
+ module Generators
5
+ class InstallGenerator < Rails::Generators::Base
6
+ include Rails::Generators::Migration
7
+
8
+ source_root File.expand_path("../../templates", __FILE__)
9
+
10
+ desc "Generates a SimpleMobileOauth migrations for identity model"
11
+
12
+ def self.orm
13
+ Rails::Generators.options[:rails][:orm]
14
+ end
15
+
16
+ def self.orm_has_migration?
17
+ [:active_record].include? orm
18
+ end
19
+
20
+ def self.next_migration_number(path)
21
+ Time.now.utc.strftime("%Y%m%d%H%M%S")
22
+ end
23
+
24
+ def create_migration_file
25
+ if self.class.orm_has_migration?
26
+ migration_template 'migration.rb', 'db/migrate/simple_mobile_oauth_migration.rb'
27
+ end
28
+ end
29
+
30
+ # def copy_initializer
31
+ # template "simple_mobile_oauth.rb", "config/initializers/simple_mobile_oauth.rb"
32
+ # end
33
+
34
+ def copy_identity_model
35
+ template "identity.rb", "app/models/identity.rb"
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,15 @@
1
+ require 'rails/generators/named_base'
2
+
3
+ module SimpleMobileOauth
4
+ module Generators
5
+ class SimpleMobileOauthGenerator < Rails::Generators::NamedBase
6
+ include Rails::Generators::ResourceHelpers
7
+
8
+ namespace 'simple_mobile_oauth'
9
+ source_root File.expand_path("../templates", __FILE__)
10
+
11
+ desc 'Insert include for given NAME model'
12
+ hook_for :orm
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,16 @@
1
+ class Identity < ActiveRecord::Base
2
+ validates :uid, :provider, presence: true
3
+ validates_uniqueness_of :uid, scope: [:provider, :identifiable_type]
4
+
5
+ belongs_to :identifiable, polymorphic: true
6
+
7
+ serialize :info, JSON
8
+
9
+ def username
10
+ info["nickname"]
11
+ end
12
+
13
+ def avatar_url
14
+ info["image"]
15
+ end
16
+ end
@@ -0,0 +1,14 @@
1
+ class SimpleMobileOauthMigration < ActiveRecord::Migration
2
+ def change
3
+ create_table :identities do |t|
4
+ t.integer :identifiable_id
5
+ t.string :identifiable_type
6
+ t.string :image
7
+ t.string :uid, null: false
8
+ t.string :provider, null: false
9
+ t.text :info
10
+
11
+ t.timestamps
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,122 @@
1
+ module SimpleMobileOauth
2
+ # SimpleMobileOauth::Authenticator
3
+ #
4
+ # Scenarios:
5
+ #
6
+ # 1. if identity with uid and provider exists
7
+ # 1. if user param is given
8
+ # 1. if identity's owner matches the user param, it returns the identity's owner
9
+ # 2. else it raises error because the identity exists with another user
10
+ # 2. if user param is not given (so it's a log in), it returns the identity's owner
11
+ # 2. if identity is not found by given oauth
12
+ # 1. if user_param is not given, then we return nil (most likely in mid of registration phase)
13
+ # 2. if user param is given
14
+ # 1. if user can be found by user_param, it creates the binds the identity to that user
15
+ # 2. if user can not be found by user param, it creates both user and identity (registration)
16
+ #
17
+ # Usage example:
18
+ #
19
+ # class UserAuthenticator
20
+ # include SimpleMobileOauth::Authenticator
21
+ #
22
+ # find_identity do |params|
23
+ # Identity.find_by params.merge(identifiable_type: 'User')
24
+ # end
25
+ #
26
+ # find_user do |params|
27
+ # return nil unless params.present?
28
+ # User.find_by email: params['email']
29
+ # end
30
+ #
31
+ # build_user do |params|
32
+ # raise ArgumentError, 'missing params' unless params
33
+ # attrs = {email: params['email'], password: Devise.friendly_token[0,20]}
34
+ # User.new(attrs)
35
+ # end
36
+ # end
37
+ #
38
+ # user = UserAuthenticator.new.call(params)
39
+ #
40
+ module Authenticator
41
+ BaseError = Class.new(StandardError)
42
+ IdentityMissingOwnerError = Class.new(BaseError)
43
+ IdentityAlreadyBoundError = Class.new(BaseError)
44
+ InvalidParamsError = Class.new(BaseError)
45
+
46
+ extend ActiveSupport::Concern
47
+
48
+ module ClassMethods
49
+ def find_identity(&block)
50
+ define_method(:_find_identity_strategy, &block)
51
+ end
52
+
53
+ def find_user(&block)
54
+ define_method(:_find_user_strategy, &block)
55
+ end
56
+
57
+ def build_user(&block)
58
+ define_method(:_build_user_strategy, &block)
59
+ end
60
+ end
61
+
62
+ class EmptyUser < Hash
63
+ def initialize(params={})
64
+ super
65
+ self[:user] = nil
66
+ end
67
+
68
+ def valid?
69
+ true
70
+ end
71
+ end
72
+
73
+ def call(params)
74
+ oauth_params = params.fetch('auth') { raise InvalidParamsError, "auth param is missing" }
75
+ oauth_uid = oauth_params.fetch('uid') { raise InvalidParamsError, "uid is missing" }
76
+ oauth_provider = oauth_params.fetch('provider') { raise InvalidParamsError, "provider is missing" }
77
+ oauth_info = oauth_params.fetch('info') { {} }
78
+ user_params = params['user']
79
+ identity_params = { uid: oauth_uid, provider: oauth_provider, info: oauth_info }
80
+ identity = _find_identity_strategy(identity_params.slice(:uid, :provider))
81
+
82
+ return EmptyUser.new if start_of_registration_process?(identity, user_params)
83
+
84
+ if identity
85
+ identity_owner = identity.identifiable
86
+ raise IdentityMissingOwnerError, 'internal error' unless identity_owner
87
+
88
+ return identity_owner if login_request?(identity_owner, user_params)
89
+
90
+ user = _find_user_strategy(user_params)
91
+ raise InvalidParamsError, 'could not find user from params given' unless user
92
+ raise IdentityAlreadyBoundError, 'oauth identity exists with another user' \
93
+ if identity_already_bound_to_different_user?(identity_owner, user)
94
+
95
+ # So the identity owner and user found from param match
96
+ user
97
+ else
98
+ raise InvalidParamsError, 'missing user params' unless user_params
99
+
100
+ user = _find_user_strategy(user_params) || _build_user_strategy(user_params)
101
+
102
+ user.identities.build(identity_params)
103
+ user.save
104
+ user
105
+ end
106
+ end
107
+
108
+ private
109
+
110
+ def login_request?(identity_owner, user_params)
111
+ identity_owner && !user_params
112
+ end
113
+
114
+ def identity_already_bound_to_different_user?(identity_owner, user)
115
+ identity_owner && user && identity_owner != user
116
+ end
117
+
118
+ def start_of_registration_process?(identity, user_params)
119
+ !identity && !user_params
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,23 @@
1
+ module SimpleMobileOauth
2
+ module Identifiable
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ has_many :identities, as: :identifiable
7
+ end
8
+
9
+ def username
10
+ current_identity_info.try(:fetch, "nickname", "")
11
+ end
12
+
13
+ def avatar_url
14
+ current_identity_info.try(:fetch, "image", "")
15
+ end
16
+
17
+ private
18
+
19
+ def current_identity_info
20
+ identities.first.try(:info)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,3 @@
1
+ module SimpleMobileOauth
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,5 @@
1
+ module SimpleMobileOauth
2
+ end
3
+
4
+ require_relative 'simple_mobile_oauth/identifiable'
5
+ require_relative 'simple_mobile_oauth/authenticator'
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :simple_mobile_oauth do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,28 @@
1
+ == README
2
+
3
+ This README would normally document whatever steps are necessary to get the
4
+ application up and running.
5
+
6
+ Things you may want to cover:
7
+
8
+ * Ruby version
9
+
10
+ * System dependencies
11
+
12
+ * Configuration
13
+
14
+ * Database creation
15
+
16
+ * Database initialization
17
+
18
+ * How to run the test suite
19
+
20
+ * Services (job queues, cache servers, search engines, etc.)
21
+
22
+ * Deployment instructions
23
+
24
+ * ...
25
+
26
+
27
+ Please feel free to use a different markup language if you do not plan to run
28
+ <tt>rake doc:app</tt>.
@@ -0,0 +1,6 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require File.expand_path('../config/application', __FILE__)
5
+
6
+ Rails.application.load_tasks
@@ -0,0 +1,13 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file.
9
+ //
10
+ // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require_tree .
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any styles
10
+ * defined in the other CSS/SCSS files in this directory. It is generally better to create a new
11
+ * file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,5 @@
1
+ class ApplicationController < ActionController::Base
2
+ # Prevent CSRF attacks by raising an exception.
3
+ # For APIs, you may want to use :null_session instead.
4
+ protect_from_forgery with: :exception
5
+ end
@@ -0,0 +1,2 @@
1
+ module ApplicationHelper
2
+ end
@@ -0,0 +1,16 @@
1
+ class Identity < ActiveRecord::Base
2
+ validates :uid, :provider, presence: true
3
+ validates_uniqueness_of :uid, scope: [:provider, :identifiable_type]
4
+
5
+ belongs_to :identifiable, polymorphic: true
6
+
7
+ serialize :info, JSON
8
+
9
+ def username
10
+ info["nickname"]
11
+ end
12
+
13
+ def avatar_url
14
+ info["image"]
15
+ end
16
+ end
@@ -0,0 +1,3 @@
1
+ class User < ActiveRecord::Base
2
+ include SimpleMobileOauth::Identifiable
3
+ end