weapon 0.1.1 → 0.1.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dd05b8383fdf6a56aee99e98e7c4e6aadfd800e4
4
- data.tar.gz: caf2a88d30150d5b98fd8824fdb5af1b90ba5e90
3
+ metadata.gz: 8621ad57230f376e88746ffb2ca40f8957f7d483
4
+ data.tar.gz: 969cb6e67bdc34eec0263004c0887896edc189f8
5
5
  SHA512:
6
- metadata.gz: 40ed25df93a88f72b4f1f14ae96a59de044d39fd23563b7943c8aa05dcaf9accaf2117b58bfb18529d2db826ebf522674417e504038ec5f6a322771f04fed121
7
- data.tar.gz: 026e9afc4441a43fbef02c8ca2c9f73de6c12866b5a034927420daf0ff1ca680f265e658f538d1cd203f2586040d938059380e25e5034b49ded79ca06eb86f3a
6
+ metadata.gz: 5641986317808d41699ffa477bd7e34c5edbeaedb5cd8dd5524f3f3649ab3f923fabd85c6a62bff9cc1a79b3c7d3ce7359162d6d0e20f3b15ec8ae03703f276d
7
+ data.tar.gz: 015e1e722924516d70c47c74aaeaa305f33e3a087993daf3cdd7ebe5edb4fa473f4984d0c694d8423105b62682df12bd2f5765d01b6ebd701ce0d101e86ac0af
@@ -1,36 +1,54 @@
1
1
 
2
2
  class Weapon::ActiveadminGenerator < Rails::Generators::NamedBase # :nodoc:
3
- desc 'This generator creates a example email setting and add exception_notification for production'
4
-
5
- def create_example_email
6
- application(nil, env: "production") do
7
- config.action_mailer.raise_delivery_errors = true
8
- config.action_mailer.default_url_options = {:host => '120.25.61.54:8100'}
9
- config.action_mailer.delivery_method = :smtp
10
- config.action_mailer.smtp_settings = {
11
- :address => "smtp.163.com",
12
- :port => 25,
13
- :user_name => "ledcloud@163.com",
14
- :password => "ffgexobhlolfjhij",
15
- :enable_starttls_auto => true,
16
- :authentication => "plain",
17
- :domain => "163.com"
18
- }
19
- end
20
- end
3
+ desc 'This generator creates activeadmin files'
21
4
 
22
- def add_exception_notify
23
- gem_group :production do
24
- gem "rspec-rails"
25
- end
5
+ class_option :only, type: :string, desc: 'only generate model for listed model'
6
+ class_option :except, type: :string, desc: 'when generate model, exclude listed model'
7
+
8
+ def generate_activeadmin
9
+
10
+ prefix = 'app/admin'
11
+
12
+ if args[0].nil? || args[0] == "all"
13
+ names = Dir["app/models/*.rb"].map {|x| File.basename(x, '.rb')}
14
+
15
+ if options[:only]
16
+ names = names & options[:only].split(',')
17
+ end
18
+
19
+ if options[:except]
20
+ names = names - options[:except].split(',')
21
+ end
22
+
23
+ names.each do |name|
24
+ next unless name.camelize.constantize.respond_to? 'column_names'
25
+ column_names = name.camelize.constantize.column_names
26
+ infos = column_names.map {|column| "expose :#{column}"}
27
+ end
28
+ else
29
+ name = args[0]
30
+ return unless name.camelize.constantize.respond_to? 'column_names'
31
+ column_names = name.camelize.constantize.column_names
32
+
33
+ if options[:only]
34
+ column_names = column_names & options[:only].split(',')
35
+ end
36
+
37
+ if options[:except]
38
+ column_names = column_names - options[:except].split(',')
39
+ end
40
+
41
+ ap column_names
42
+ a = Magicfile.new
43
+ infos = ['xx']
44
+ a.append_string_lines(infos)
45
+ a.to_file "#{prefix}/name.rb"
26
46
 
27
- application(nil, env: "production") do
28
- config.middleware.use ExceptionNotification::Rack,
29
- :email => {
30
- :email_prefix => "[weapon] ",
31
- :sender_address => "weapon <ledcloud@163.com>",
32
- :exception_recipients => %w{dilin.life@gmail.com}
33
- }
34
47
  end
48
+
49
+
50
+
35
51
  end
52
+
53
+
36
54
  end
@@ -1,20 +1,19 @@
1
1
  require 'magicfile'
2
2
  require 'fileutils'
3
-
3
+ require 'thor'
4
4
 
5
5
  class Weapon::GrapeGenerator < Rails::Generators::Base # :nodoc:
6
- desc 'This generator creates grape entity for model'
6
+ desc 'This generator creates basic grape files for models'
7
+ include Thor::Actions
7
8
 
8
- def generate_grape_entity
9
+ source_root File.expand_path("../templates", __FILE__)
10
+ class_option :only, type: :string, desc: 'only generate api for listed model'
11
+ class_option :except, type: :string, desc: 'when generate api, exclude listed model'
9
12
 
10
- prefix_dirs = Dir.glob('app/api/*/')
11
- if prefix_dirs.count == 0
12
- prefix = 'app/api/v1'
13
- elsif prefix_dirs.count == 1
14
- prefix = prefix_dirs[0]
15
- else
16
- prefix = ask('there are multi directory in app/api directory, please input path like app/api/v1')
17
- end
13
+ def generate_grape_files
14
+
15
+ prefix = 'app/api/v1'
16
+ FileUtils.mkdir_p prefix
18
17
 
19
18
  if args[0].nil? || args[0] == "all"
20
19
  names = Dir["app/models/*.rb"].map {|x| File.basename(x, '.rb')}
@@ -22,28 +21,44 @@ class Weapon::GrapeGenerator < Rails::Generators::Base # :nodoc:
22
21
  names = args
23
22
  end
24
23
 
25
- ap names
26
-
27
- names.each do |name|
28
- entity_dir = File.join(prefix, "entities")
29
- entity_path = File.join(entity_dir, "#{name}.rb")
30
-
31
- ap "dir is #{entity_dir}"
32
- ap "path is #{entity_path}"
24
+ if options[:only]
25
+ names = names & options[:only].split(',')
26
+ end
33
27
 
34
- next unless name.camelize.constantize.respond_to? 'column_names'
35
- column_names = name.camelize.constantize.column_names
36
- infos = column_names.map {|column| "expose :#{column}"}
28
+ if options[:except]
29
+ names = names - options[:except].split(',')
30
+ end
37
31
 
38
- FileUtils.mkdir_p entity_dir
32
+ module_array = prefix.split('/')[1..-1]
33
+ names.each do |name|
39
34
  a = Magicfile.new
40
- module_array = prefix.split('/')[1..-1].append('entities')
41
35
  a.append_modules(module_array)
42
- a.append_class(name.camelize, 'Grape::Entity')
36
+ a.append_class(name.camelize.pluralize, 'Grape::API')
37
+ infos = ["version 'v1', using: :path", "format :json", "default_format: json"]
43
38
  a.append_string_lines(infos)
44
- a.to_file entity_path
39
+ a.to_file "#{prefix}/#{name.pluralize}.rb"
45
40
  end
46
41
 
42
+ b = Magicfile.new
43
+ b.append_modules(module_array)
44
+ b.append_class('Root', 'Grape::API')
45
+ infos = ["helpers Api::V1::Helpers", "version 'v1', using: :path", "cascade false", "format :json", "default_format :json\n", "use Api::V1::Auth::Middleware\n"]
46
+ infos += names.map {|x| "mount Api::V1::#{x.camelize.pluralize}"}
47
+ infos += ["\n", "before do", " header 'Access-Control-Allow-Origin'", "end\n"]
48
+ b.append_string_lines(infos)
49
+ b.to_file "#{prefix}/root.rb"
50
+
51
+ copy_file 'dispatch.rb', "app/api/dispatch.rb"
52
+ copy_file 'errors.rb', "#{prefix}/errors.rb"
53
+ copy_file 'helpers.rb', "#{prefix}/helpers.rb"
54
+ copy_file 'named_params.rb', "#{prefix}/named_params.rb"
55
+ FileUtils.mkdir_p "#{prefix}/auth"
56
+ copy_file 'auth/utils.rb', "#{prefix}/auth/utils.rb"
57
+ copy_file 'auth/middleware.rb', "#{prefix}/auth/middleware.rb"
58
+ copy_file 'auth/authenticator.rb', "#{prefix}/auth/authenticator.rb"
59
+
60
+ route "mount Api::Dispatch => '/api'"
61
+
47
62
  end
48
63
 
49
64
  end
@@ -0,0 +1,86 @@
1
+ module Api
2
+ module V1
3
+ module Auth
4
+ class Authenticator
5
+
6
+ def initialize(request, params)
7
+ @request = request
8
+ @params = params
9
+ end
10
+
11
+
12
+ def authenticate!
13
+ check_user!
14
+ check_tonce!
15
+ check_signature!
16
+ user
17
+ end
18
+
19
+ def user
20
+ @user ||= User.where(access_key: @params[:access_key]).first
21
+ end
22
+
23
+ def check_user!
24
+ raise InvalidAccessKeyError, @params[:access_key] unless user
25
+ raise ExpiredAccessKeyError, @params[:access_key] if user.auth_expired?
26
+ end
27
+
28
+ def check_signature!
29
+ Rails.logger.warn "payload is #{payload}"
30
+ Rails.logger.warn "uploaded signature is #{@params[:signature]}"
31
+ Rails.logger.warn "generated signature is #{Utils.hmac_signature(user.secret_key, payload)}"
32
+ if @params[:signature] != Utils.hmac_signature(user.secret_key, payload)
33
+ Rails.logger.warn "Api v1 auth failed: signature doesn't match. token: #{user.access_key} payload: #{payload}"
34
+ raise Api::V1::IncorrectSignatureError, @params[:signature]
35
+ end
36
+ end
37
+
38
+ def check_tonce!
39
+ key = "api:v1:tonce:#{user.access_key}:#{tonce}"
40
+ if Utils.cache.read(key)
41
+ Rails.logger.warn "API v1 auth failed: used tonce.access_key: #{user.access_key} payload: #{payload} tonce: #{tonce}"
42
+ raise Api::V1::TonceUsedError.new(user.access_key, tonce)
43
+ end
44
+ Utils.cache.write key, tonce, 61 # forget after 61 seconds
45
+
46
+ now = Time.now.to_i
47
+ if tonce < now-30 || tonce > now+30# within 30 seconds
48
+ Rails.logger.warn "Api v1 auth failed: invalid tonce. access_key: #{user.access_key} payload: #{payload} tonce: #{tonce} current timestamp: #{now}"
49
+ raise Api::V1::InvalidTonceError.new(tonce, now)
50
+ end
51
+ end
52
+
53
+ def tonce
54
+ @tonce ||= @params[:tonce].to_i
55
+ end
56
+
57
+ def payload
58
+ "#{canonical_verb}|#{Api::V1::Root::PREFIX}#{canonical_uri}|#{canonical_query}"
59
+ end
60
+
61
+ def canonical_verb
62
+ @request.request_method
63
+ end
64
+
65
+ def canonical_uri
66
+ @request.path_info
67
+ end
68
+
69
+ def canonical_query
70
+ hash = @params.select {|k,v| !%w(route_info signature format).include?(k) }
71
+ ap hash
72
+ URI.unescape(hash.to_param)
73
+ end
74
+
75
+ def endpoint
76
+ @request.env['api.endpoint']
77
+ end
78
+
79
+ def route_scopes
80
+ endpoint.options[:route_options][:scopes]
81
+ end
82
+
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,35 @@
1
+ module Api
2
+ module V1
3
+ module Auth
4
+ class Middleware < ::Grape::Middleware::Base
5
+
6
+ def before
7
+ #raise AuthorizationError
8
+ if provided?
9
+ auth = Api::V1::Auth::Authenticator.new(request, params)
10
+ ap "do auth"
11
+ @env['user'] = auth.authenticate!
12
+ end
13
+ end
14
+
15
+ def provided?
16
+ ap params
17
+ ap params["access_key"]
18
+ ap params["tonce"]
19
+ ap params["signature"]
20
+ params["access_key"] && params["tonce"] && params["signature"]
21
+ end
22
+
23
+ def request
24
+ @request ||= ::Grape::Request.new(env)
25
+ end
26
+
27
+ def params
28
+ @params ||= request.params
29
+ end
30
+
31
+ end
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,28 @@
1
+ module Api
2
+ module V1
3
+ module Auth
4
+ module Utils
5
+ class <<self
6
+
7
+ def cache
8
+ # Simply use rack-attack cache wrapper
9
+ @cache ||= Rack::Attack::Cache.new
10
+ end
11
+
12
+ def urlsafe_string_40
13
+ # 30 is picked so generated string length is 40
14
+ SecureRandom.urlsafe_base64(30).tr('_-', 'xx')
15
+ end
16
+
17
+ alias :generate_access_key :urlsafe_string_40
18
+ alias :generate_secret_key :urlsafe_string_40
19
+
20
+ def hmac_signature(secret_key, payload)
21
+ OpenSSL::HMAC.hexdigest 'SHA256', secret_key, payload
22
+ end
23
+
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,13 @@
1
+
2
+ module Api
3
+ class Dispatch < Grape::API
4
+
5
+ mount Api::V1::Root
6
+
7
+ format :json
8
+ default_format :json
9
+
10
+ content_type :json, "application/json;charset=utf-8"
11
+
12
+ end
13
+ end
@@ -0,0 +1,81 @@
1
+ module Api
2
+ module V1
3
+
4
+ module ExceptionHandlers
5
+
6
+ def self.included(base)
7
+ base.instance_eval do
8
+ rescue_from Grape::Exceptions::ValidationErrors do |e|
9
+ Rack::Response.new({
10
+ success: false,
11
+ message: e.message,
12
+ data: {}
13
+ }.to_json, e.status)
14
+ end
15
+ end
16
+ end
17
+
18
+ end
19
+
20
+ class Error < Grape::Exceptions::Base
21
+ attr :code, :text
22
+
23
+ # code: api error code defined by Peatio, errors originated from
24
+ # subclasses of Error have code start from 2000.
25
+ # text: human readable error message
26
+ # status: http status code
27
+ def initialize(opts={})
28
+ @text = opts[:text] || ''
29
+
30
+ @status = 200
31
+ @message = {success: false, message: @text, data: {}}
32
+ end
33
+ end
34
+
35
+ class AuthorizationError < Error
36
+ def initialize
37
+ super code: 2001, text: 'Authorization failed', status: 401
38
+ end
39
+ end
40
+
41
+
42
+
43
+ class IncorrectSignatureError < Error
44
+ def initialize(signature)
45
+ super code: 2005, text: "Signature #{signature} is incorrect.", status: 401
46
+ end
47
+ end
48
+
49
+ class TonceUsedError < Error
50
+ def initialize(access_key, tonce)
51
+ super code: 2006, text: "The tonce #{tonce} has already been used by access key #{access_key}.", status: 401
52
+ end
53
+ end
54
+
55
+ class InvalidTonceError < Error
56
+ def initialize(tonce, now)
57
+ super code: 2007, text: "The tonce #{tonce} is invalid, current timestamp is #{now}.", status: 401
58
+ end
59
+ end
60
+
61
+ class InvalidAccessKeyError < Error
62
+ def initialize(access_key)
63
+ super code: 2008, text: "The access key #{access_key} does not exist.", status: 401
64
+ end
65
+ end
66
+
67
+ class DisabledAccessKeyError < Error
68
+ def initialize(access_key)
69
+ super code: 2009, text: "The access key #{access_key} is disabled.", status: 401
70
+ end
71
+ end
72
+
73
+ class ExpiredAccessKeyError < Error
74
+ def initialize(access_key)
75
+ super code: 2010, text: "The access key #{access_key} has expired.", status: 401
76
+ end
77
+ end
78
+
79
+
80
+ end
81
+ end
@@ -0,0 +1,24 @@
1
+ module Api
2
+ module V1
3
+ module Helpers
4
+ def render_success(data = {}, msg = nil)
5
+ status 200
6
+ { success: true, message: msg.to_s, data: data }
7
+ end
8
+
9
+ def render_fail(msg = nil, data = {})
10
+ status 200
11
+ { success: false, message: msg.to_s, data: data }
12
+ end
13
+
14
+ def authenticate!
15
+ current_user or raise AuthorizationError
16
+ end
17
+
18
+ def current_user
19
+ @user ||= env['user']
20
+ end
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,14 @@
1
+ module Api
2
+ module V1
3
+ module NamedParams
4
+ extend ::Grape::API::Helpers
5
+
6
+ params :auth do
7
+ requires :access_key, type: String, desc: "Access key."
8
+ requires :tonce, type: Integer, desc: "Tonce is an integer represents the milliseconds elapsed since Unix epoch."
9
+ requires :signature, type: String, desc: "The signature of your request payload, generated using your secret key."
10
+ end
11
+
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,55 @@
1
+ require 'magicfile'
2
+ require 'fileutils'
3
+
4
+
5
+ class Weapon::GrapeEntityGenerator < Rails::Generators::Base # :nodoc:
6
+ desc 'This generator creates grape entity for model'
7
+
8
+ class_option :only, type: :string, desc: 'only generate api for listed model'
9
+ class_option :except, type: :string, desc: 'when generate api, exclude listed model'
10
+
11
+ def generate_grape_entity
12
+
13
+ prefix_dirs = Dir.glob('app/api/*/')
14
+ if prefix_dirs.count == 0
15
+ prefix = 'app/api/v1'
16
+ elsif prefix_dirs.count == 1
17
+ prefix = prefix_dirs[0]
18
+ else
19
+ prefix = ask('there are multi directory in app/api directory, please input path like app/api/v1')
20
+ end
21
+
22
+ if args[0].nil? || args[0] == "all"
23
+ names = Dir["app/models/*.rb"].map {|x| File.basename(x, '.rb')}
24
+ else
25
+ names = args
26
+ end
27
+
28
+ if options[:only]
29
+ names = names & options[:only].split(',')
30
+ end
31
+
32
+ if options[:except]
33
+ names = names - options[:except].split(',')
34
+ end
35
+
36
+ names.each do |name|
37
+ entity_dir = File.join(prefix, "entities")
38
+ entity_path = File.join(entity_dir, "#{name}.rb")
39
+
40
+ next unless name.camelize.constantize.respond_to? 'column_names'
41
+ column_names = name.camelize.constantize.column_names
42
+ infos = column_names.map {|column| "expose :#{column}"}
43
+
44
+ FileUtils.mkdir_p entity_dir
45
+ a = Magicfile.new
46
+ module_array = prefix.split('/')[1..-1].append('entities')
47
+ a.append_modules(module_array)
48
+ a.append_class(name.camelize, 'Grape::Entity')
49
+ a.append_string_lines(infos)
50
+ a.to_file entity_path
51
+ end
52
+
53
+ end
54
+
55
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: weapon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - seaify
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-26 00:00:00.000000000 Z
11
+ date: 2016-01-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -92,6 +92,14 @@ files:
92
92
  - lib/generators/weapon/activeadmin/activeadmin_generator.rb
93
93
  - lib/generators/weapon/email/email_generator.rb
94
94
  - lib/generators/weapon/grape/grape_generator.rb
95
+ - lib/generators/weapon/grape/templates/auth/authenticator.rb
96
+ - lib/generators/weapon/grape/templates/auth/middleware.rb
97
+ - lib/generators/weapon/grape/templates/auth/utils.rb
98
+ - lib/generators/weapon/grape/templates/dispatch.rb
99
+ - lib/generators/weapon/grape/templates/errors.rb
100
+ - lib/generators/weapon/grape/templates/helpers.rb
101
+ - lib/generators/weapon/grape/templates/named_params.rb
102
+ - lib/generators/weapon/grape_entity/grape_entity_generator.rb
95
103
  - lib/generators/weapon/i18n/i18n_generator.rb
96
104
  - lib/support/create_gem/basic.bin
97
105
  - lib/support/create_gem/basic.gemspec