village_auth 1.0.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.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in lam_auth.gemspec
4
+ gemspec
data/README.rdoc ADDED
@@ -0,0 +1,38 @@
1
+ Аутентификация для спецпроектов The Village
2
+
3
+ == Установка
4
+
5
+ gem install village_auth
6
+
7
+ После установки/добавления в Gemfile:
8
+
9
+ rails generate village_auth User
10
+
11
+ после этого нужно добавить настройки приложения в config/village_auth.yml.
12
+
13
+ == Обработчик LoginRequiredException
14
+
15
+ Для actions, где требуется залогиненный пользователь:
16
+
17
+ before_filter :login_required
18
+
19
+ можно сделать обработчик для LoginRequiredException:
20
+
21
+ rescue_from VillageAuth::LoginRequiredException, :with => :render_login_required
22
+
23
+ private
24
+
25
+ def render_login_required
26
+ render :file => 'shared/login_required', :layout => 'application', :status => 401
27
+ end
28
+
29
+ == Подключение панели
30
+
31
+ Подключить js-код в head:
32
+
33
+ <%= village_auth_include_tag %>
34
+
35
+ Затем:
36
+
37
+ <div id="village-root"></div>
38
+ <%= village_auth_init_tag %>
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,20 @@
1
+ class Create<%= table_name.camelize %> < ActiveRecord::Migration
2
+ def self.up
3
+ create_table(:<%= table_name %>) do |t|
4
+ t.string :login, :null => false
5
+ t.string :email, :null => false
6
+ t.string :first_name
7
+ t.string :last_name
8
+ t.string :userpic
9
+ t.text :profile
10
+ t.timestamps
11
+ end
12
+
13
+ add_index :<%= table_name %>, :login
14
+ add_index :<%= table_name %>, :email
15
+ end
16
+
17
+ def self.down
18
+ drop_table :<%= table_name %>
19
+ end
20
+ end
@@ -0,0 +1,23 @@
1
+ require 'rails/generators/active_record'
2
+ require 'generators/village_auth/helpers'
3
+
4
+ module ActiveRecord
5
+ module Generators
6
+ class VillageAuthGenerator < ActiveRecord::Generators::Base
7
+ include VillageAuth::Generators::Helpers
8
+ source_root File.expand_path("../templates", __FILE__)
9
+
10
+ def generate_model
11
+ invoke "active_record:model", [name], :migration => false unless model_exists? && behavior == :invoke
12
+ end
13
+
14
+ def copy_village_auth_migration
15
+ migration_template "migration.rb", "db/migrate/create_#{table_name}"
16
+ end
17
+
18
+ def inject_village_auth_content
19
+ inject_into_class(model_path, class_name, model_contents) if model_exists?
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,3 @@
1
+ # return_url можно не указывать, если это дефолтный http://:app-domain/xd_receiver.html
2
+ app_id: app_id
3
+ secret: secret
@@ -0,0 +1,15 @@
1
+ <!DOCTYPE HTML>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title></title>
6
+ <script type="text/javascript">
7
+ window.opener.VLG.successLogin(window.location.hash.substring(1));
8
+ </script>
9
+ </head>
10
+ <body><p>Loading...</p>
11
+ </body>
12
+ </html>
13
+
14
+
15
+
@@ -0,0 +1,19 @@
1
+ module VillageAuth
2
+ module Generators
3
+ module Helpers
4
+ def model_exists?
5
+ File.exists?(File.join(destination_root, model_path))
6
+ end
7
+
8
+ def model_path
9
+ @model_path ||= File.join("app", "models", "#{file_path}.rb")
10
+ end
11
+
12
+ def model_contents
13
+ <<-CONTENT
14
+ include VillageAuth::Model
15
+ CONTENT
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,24 @@
1
+ module VillageAuth
2
+ module Generators
3
+ class VillageAuthGenerator < Rails::Generators::NamedBase
4
+ namespace "village_auth"
5
+ source_root File.expand_path("../../templates", __FILE__)
6
+
7
+ desc "Installs village_auth: generates a model plus includes required extensions."
8
+
9
+ hook_for :orm
10
+
11
+ def inject_controller_content
12
+ inject_into_class(File.join("app", "controllers", "application_controller.rb"), 'ApplicationController', " village_auth_for :#{file_path}\n")
13
+ end
14
+
15
+ def copy_xd_receiver
16
+ copy_file 'xd_receiver.html', 'public/xd_receiver.html'
17
+ end
18
+
19
+ def copy_yml
20
+ copy_file 'village_auth.yml', 'config/village_auth.yml'
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,48 @@
1
+ require 'rack/utils'
2
+ require 'digest/md5'
3
+
4
+ require 'village_auth/controller_extensions'
5
+ require 'village_auth/helpers'
6
+ require 'village_auth/model'
7
+ ActionController::Base.extend(VillageAuth::ControllerExtensions)
8
+ ActionController::Base.helper(VillageAuth::Helpers)
9
+
10
+ module VillageAuth
11
+ class LoginRequiredException < Exception
12
+ end
13
+
14
+ class << self
15
+ def config
16
+ @config ||= YAML.load_file(Rails.root.join("config/village_auth.yml"))
17
+ end
18
+
19
+ def url
20
+ "http://www.the-village.ru"
21
+ end
22
+
23
+ def signup_url
24
+ "#{url}/signup"
25
+ end
26
+
27
+ def uri
28
+ URI.parse(url)
29
+ end
30
+
31
+ def cookie_id
32
+ "village_#{config['app_id']}"
33
+ end
34
+
35
+ def valid_cookie?(data)
36
+ valid_hash?(parse_cookie_to_hash(data))
37
+ end
38
+
39
+ def parse_cookie_to_hash(data)
40
+ Rack::Utils.parse_query(Rack::Utils.unescape(data.to_s.gsub('"', '')))
41
+ end
42
+
43
+ def valid_hash?(hash)
44
+ Digest::MD5.hexdigest(hash.except('sig').sort.map{|v| v.join('=')}.join + VillageAuth.config['secret']) == hash['sig']
45
+ end
46
+ end
47
+ end
48
+
@@ -0,0 +1,53 @@
1
+ module VillageAuth
2
+ module ControllerExtensions
3
+ def village_auth_for(klass)
4
+ class_attribute :user_model_class_name
5
+ self.user_model_class_name = klass
6
+
7
+ helper_method(:current_user, :logged_in?)
8
+ before_filter :login_from_cookie
9
+
10
+ extend ClassMethods
11
+ include InstanceMethods
12
+ protected :logged_in?, :current_user, :current_user=, :access_token, :login_from_cookie, :login_required
13
+ end
14
+
15
+ module ClassMethods
16
+ def user_model_class
17
+ user_model_class_name.to_s.classify.constantize
18
+ end
19
+ end
20
+
21
+ module InstanceMethods
22
+ def logged_in?
23
+ !!current_user
24
+ end
25
+
26
+ def current_user
27
+ @current_user ||= session[:user] && self.class.user_model_class.find_by_id(session[:user])
28
+ end
29
+
30
+ def current_user=(new_user)
31
+ session[:user] = new_user && new_user.id
32
+ @current_user = new_user
33
+ end
34
+
35
+ def access_token
36
+ cookie = cookies[VillageAuth.cookie_id]
37
+ VillageAuth.valid_cookie?(cookie) && VillageAuth.parse_cookie_to_hash(cookie)['access_token']
38
+ end
39
+
40
+ def login_from_cookie
41
+ if logged_in?
42
+ !access_token && self.current_user = nil
43
+ else
44
+ access_token && self.current_user = self.class.user_model_class.find_by_access_token(access_token)
45
+ end
46
+ end
47
+
48
+ def login_required
49
+ logged_in? || raise(LoginRequiredException)
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,18 @@
1
+ module VillageAuth
2
+ module Helpers
3
+ def village_auth_include_tag
4
+ javascript_include_tag("http://assets0.the-village.ru/api/js/VLG.Login.js")
5
+ end
6
+
7
+ def village_auth_init_tag(options = {})
8
+ options.reverse_merge!(
9
+ :app_id => VillageAuth.config['app_id'],
10
+ :panel_node_id => 'village-root',
11
+ :fixed => false
12
+ )
13
+ options.reverse_merge!(:xd_receiver_url => VillageAuth.config['return_url']) if VillageAuth.config['return_url']
14
+
15
+ javascript_tag("VLG.init({#{options.map{|k, v| "#{k.to_s.camelize(:lower)}: #{v.inspect}"}.join(",\n")}});")
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,54 @@
1
+ require 'net/http'
2
+ require 'net/https'
3
+ module VillageAuth
4
+ module Model
5
+ def self.included(base)
6
+ base.validates_presence_of :login, :email
7
+ base.validates_uniqueness_of :login, :email
8
+ base.serialize :profile
9
+ base.send(:extend, ClassMethods)
10
+ end
11
+
12
+ module ClassMethods
13
+ def find_by_access_token(access_token)
14
+ Rails.logger.info("Trying to authorize a token #{access_token.inspect} ")
15
+
16
+ village_uri = VillageAuth.uri
17
+ http = Net::HTTP.new(village_uri.host, village_uri.port)
18
+ response, body = http.get("#{village_uri.path}/users/me", {'Authorization' => "Token token=\"#{access_token}\""})
19
+ if response.code == "200"
20
+ data = ActiveSupport::JSON.decode(body)
21
+ Rails.logger.info("...success: #{data.inspect}")
22
+ create_or_update_by_auth_data(data)
23
+ else
24
+ Rails.logger.info("...failed with #{response.code}!")
25
+ nil
26
+ end
27
+ rescue Net::ProtoRetriableError => detail
28
+ Rails.logger.info("...failed!")
29
+ Rails.logger.info(detail)
30
+ nil
31
+ end
32
+
33
+ def create_or_update_by_auth_data(data)
34
+ user = find_or_initialize_by_login(data['login'])
35
+ user.update_attributes data.slice(*%w{email first_name last_name}).merge(
36
+ 'userpic' => data['userpic']['icon'],
37
+ 'profile' => data.except(*%w{login email first_name last_name userpic})
38
+ )
39
+ user
40
+ end
41
+ end
42
+
43
+ def name
44
+ [first_name, last_name].select(&:present?).join(" ")
45
+ end
46
+
47
+ def userpic(version = :icon)
48
+ pic = read_attribute(:userpic)
49
+ return nil if pic.blank?
50
+ pic.sub(/user-userpic-\w+/, "user-userpic-#{version}")
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,3 @@
1
+ module VillageAuth
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "village_auth/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "village_auth"
7
+ s.version = VillageAuth::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Max Macovsky", "Anton Platonov"]
10
+ s.email = ["robotector@gmail.com", "platosha@lookatme.ru"]
11
+ s.homepage = "http://github.com/macovsky/village_auth"
12
+ s.summary = %q{Аутентификация для спецпроектов The Village}
13
+ s.description = %q{}
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ["lib"]
19
+ end
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: village_auth
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease:
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 0
10
+ version: 1.0.0
11
+ platform: ruby
12
+ authors:
13
+ - Max Macovsky
14
+ - Anton Platonov
15
+ autorequire:
16
+ bindir: bin
17
+ cert_chain: []
18
+
19
+ date: 2012-06-25 00:00:00 Z
20
+ dependencies: []
21
+
22
+ description: ""
23
+ email:
24
+ - robotector@gmail.com
25
+ - platosha@lookatme.ru
26
+ executables: []
27
+
28
+ extensions: []
29
+
30
+ extra_rdoc_files: []
31
+
32
+ files:
33
+ - .gitignore
34
+ - Gemfile
35
+ - README.rdoc
36
+ - Rakefile
37
+ - lib/generators/active_record/templates/migration.rb
38
+ - lib/generators/active_record/village_auth_generator.rb
39
+ - lib/generators/templates/village_auth.yml
40
+ - lib/generators/templates/xd_receiver.html
41
+ - lib/generators/village_auth/helpers.rb
42
+ - lib/generators/village_auth/village_auth_generator.rb
43
+ - lib/village_auth.rb
44
+ - lib/village_auth/controller_extensions.rb
45
+ - lib/village_auth/helpers.rb
46
+ - lib/village_auth/model.rb
47
+ - lib/village_auth/version.rb
48
+ - village_auth.gemspec
49
+ homepage: http://github.com/macovsky/village_auth
50
+ licenses: []
51
+
52
+ post_install_message:
53
+ rdoc_options: []
54
+
55
+ require_paths:
56
+ - lib
57
+ required_ruby_version: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ hash: 3
63
+ segments:
64
+ - 0
65
+ version: "0"
66
+ required_rubygems_version: !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ hash: 3
72
+ segments:
73
+ - 0
74
+ version: "0"
75
+ requirements: []
76
+
77
+ rubyforge_project:
78
+ rubygems_version: 1.8.24
79
+ signing_key:
80
+ specification_version: 3
81
+ summary: !binary |
82
+ 0JDRg9GC0LXQvdGC0LjRhNC40LrQsNGG0LjRjyDQtNC70Y8g0YHQv9C10YbQ
83
+ v9GA0L7QtdC60YLQvtCyIFRoZSBWaWxsYWdl
84
+
85
+ test_files: []
86
+