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 +4 -0
- data/Gemfile +4 -0
- data/README.rdoc +38 -0
- data/Rakefile +2 -0
- data/lib/generators/active_record/templates/migration.rb +20 -0
- data/lib/generators/active_record/village_auth_generator.rb +23 -0
- data/lib/generators/templates/village_auth.yml +3 -0
- data/lib/generators/templates/xd_receiver.html +15 -0
- data/lib/generators/village_auth/helpers.rb +19 -0
- data/lib/generators/village_auth/village_auth_generator.rb +24 -0
- data/lib/village_auth.rb +48 -0
- data/lib/village_auth/controller_extensions.rb +53 -0
- data/lib/village_auth/helpers.rb +18 -0
- data/lib/village_auth/model.rb +54 -0
- data/lib/village_auth/version.rb +3 -0
- data/village_auth.gemspec +19 -0
- metadata +86 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
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,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,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
|
data/lib/village_auth.rb
ADDED
@@ -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,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
|
+
|