twimock 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 (55) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +23 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +5 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +125 -0
  8. data/Rakefile +6 -0
  9. data/db/.gitkeep +0 -0
  10. data/lib/twimock/access_token.rb +31 -0
  11. data/lib/twimock/api/account/verify_credentials.rb +40 -0
  12. data/lib/twimock/api/application.rb +29 -0
  13. data/lib/twimock/api/intent/sessions.rb +60 -0
  14. data/lib/twimock/api/oauth/access_token.rb +65 -0
  15. data/lib/twimock/api/oauth/authenticate.rb +51 -0
  16. data/lib/twimock/api/oauth/request_token.rb +49 -0
  17. data/lib/twimock/api/oauth.rb +83 -0
  18. data/lib/twimock/api.rb +35 -0
  19. data/lib/twimock/application.rb +21 -0
  20. data/lib/twimock/auth_hash.rb +8 -0
  21. data/lib/twimock/config.rb +90 -0
  22. data/lib/twimock/database/table.rb +359 -0
  23. data/lib/twimock/database.rb +133 -0
  24. data/lib/twimock/errors.rb +13 -0
  25. data/lib/twimock/omniauth/strategies/twitter.rb +28 -0
  26. data/lib/twimock/omniauth_twitter.rb +36 -0
  27. data/lib/twimock/request_token.rb +23 -0
  28. data/lib/twimock/user.rb +58 -0
  29. data/lib/twimock/version.rb +3 -0
  30. data/lib/twimock.rb +39 -0
  31. data/spec/spec_helper.rb +18 -0
  32. data/spec/support/api_spec_helper.rb +30 -0
  33. data/spec/support/omniauth_twitter_helper.rb +26 -0
  34. data/spec/support/tables_helper.rb +54 -0
  35. data/spec/support/test_application_helper.rb +9 -0
  36. data/spec/twimock/access_token_spec.rb +128 -0
  37. data/spec/twimock/api/account/verify_credentials_spec.rb +125 -0
  38. data/spec/twimock/api/application_spec.rb +27 -0
  39. data/spec/twimock/api/intent/sessions_spec.rb +184 -0
  40. data/spec/twimock/api/oauth/access_token_spec.rb +185 -0
  41. data/spec/twimock/api/oauth/authenticate_spec.rb +96 -0
  42. data/spec/twimock/api/oauth/request_token_spec.rb +123 -0
  43. data/spec/twimock/api_spec.rb +81 -0
  44. data/spec/twimock/application_spec.rb +120 -0
  45. data/spec/twimock/auth_hash_spec.rb +7 -0
  46. data/spec/twimock/config_spec.rb +192 -0
  47. data/spec/twimock/database/table_spec.rb +769 -0
  48. data/spec/twimock/database_spec.rb +261 -0
  49. data/spec/twimock/omniauth_twitter_spec.rb +129 -0
  50. data/spec/twimock/request_token_spec.rb +140 -0
  51. data/spec/twimock/user_spec.rb +271 -0
  52. data/spec/twimock_spec.rb +76 -0
  53. data/twimock.gemspec +38 -0
  54. data/view/authenticate.html.erb +23 -0
  55. metadata +343 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 98d87b06d405b5e1b62b1e556b0364db89fd791f
4
+ data.tar.gz: 51a1cc2ac6c7bf7bc616330947265a52f3736462
5
+ SHA512:
6
+ metadata.gz: 1bada1bcbe144100f5d8358303b6e9214cface5cd33052e5f5f4f0f8154a06ac45b24b606b658dc09f2bc38748ef4f808b186d5b6c8242e37a11e7b562568d29
7
+ data.tar.gz: 46af02913e36302f7eb310e1eda72711fa7857bedd0dc7cce99f72e5dc9e3a2c0038ac101d96975272ea588f562b17910645393a5da4871d14533eb813904fd6
data/.gitignore ADDED
@@ -0,0 +1,23 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ tmp/
19
+ db/*.sqlite3
20
+ vendor/bundle/
21
+ vendor/bundler/
22
+ log/*.log
23
+ .ruby-*
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ - 2.1.5
5
+ - 2.2.0
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in twimock.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 ogawatti
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,125 @@
1
+ [![Gem Version](https://badge.fury.io/rb/twimock.svg)](http://badge.fury.io/rb/twimock)
2
+ [![Build Status](https://travis-ci.org/ogawatti/twimock.svg?branch=master)](https://travis-ci.org/ogawatti/twimock)
3
+ [![Coverage Status](https://coveralls.io/repos/ogawatti/twimock/badge.png?branch=master)](https://coveralls.io/r/ogawatti/twimock?branch=master)
4
+ [<img src="https://gemnasium.com/ogawatti/twimock.png" />](https://gemnasium.com/ogawatti/twimock)
5
+ [![Code Climate](https://codeclimate.com/github/ogawatti/twimock.png)](https://codeclimate.com/github/ogawatti/twimock)
6
+
7
+ # Twimock
8
+
9
+ This gem is used to mock the communication part of the twitter api.
10
+
11
+ ## Installation
12
+
13
+ Add this line to your application's Gemfile:
14
+
15
+ gem 'twimock'
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install twimock
24
+
25
+ ## Usage
26
+
27
+ ### For Rails App Settings (config/initializers/twimock.rb)
28
+
29
+ # Create Twimock Application & User
30
+ application = Twimock::Application.create!
31
+ user = Twimock::User.create!
32
+
33
+ # Associate App and User
34
+ user.generate_access_token(app.id)
35
+
36
+ # Twimock Setting
37
+ Twimock::Config.host = 'example.com'
38
+ Twimock::Config.port = 3000
39
+ Twimock::Config.callback_url = '/users/auth/twitter/callback'
40
+
41
+ # Enable Twimock
42
+ Twimock::API.on
43
+ Twimock::OmniAuthTwitter.on
44
+
45
+ # Add Rack Middleware for twimock
46
+ [ Twimock::API::OAuth::Authenticate, Twimock::API::Intent::Sessions ].each do |middleware|
47
+ Rails.application.config.middleware.use middleware
48
+ end
49
+
50
+ ### Create Apps and Users at once by yaml file
51
+
52
+ require 'twimock'
53
+
54
+ filename = File.expand_path('../test_users.yml', __FILE__)
55
+ Twimock::Config.load_users(filename)
56
+
57
+ Twimock::Application.find_by_id(1).api_key #=> avb0vlu767yhu37hti5qq9hcc
58
+ Twimock::User.find_by_id(1).name #=> testuser01
59
+
60
+ yaml file see below.
61
+
62
+ ---
63
+ - :id: 1
64
+ :api_key: avb0vlu767yhu37hti5qq9hcc
65
+ :api_secret: e85vl7fc4susiyjjp0pncz0hf2xtf3vm29gj7hhp2ktv28wunl
66
+ :users:
67
+ - :id: 1
68
+ :name: testuser01
69
+ :password: r3xkhy64w
70
+ :access_token: 6697725737-9ntcnith1wq7zgphnisxu6bqybl019bms05t8l9
71
+ :access_token_secret: 22ogzdkn5kqtlihr3u5vwplrlh8noie61pr6ndeangrpt
72
+ :application_id: 1
73
+ - :id: 2
74
+ :name: testuser02
75
+ :password: 5ush05lp0
76
+ :access_token: 6891305263-xpvu78zd1p76s3cp6jwrudgb0g0sffxe9hp7mdj
77
+ :access_token_secret: or1xkqs96tim8n7vhc77yxo2i6ed9a6bmhru0zozjao80
78
+ :application_id: 1
79
+ - :id: 2
80
+ :api_key: w6cb9sj17fyf5g1rr4fl5ignp
81
+ :api_secret: 2vrdpujwvl3421qatn8qah9ishpia9khq7mprnkfx49mldo0k6
82
+ :users:
83
+ - :id: 3
84
+ :name: testuser03
85
+ :password: ylgi4lth
86
+ :access_token: 6932630251-1sshumnflh0abshkgaf2scxa6l02cr8tyi2kt00
87
+ :access_token_secret: txncllipm1wl0g21wvtc750lqz2dleu6e0lqg62vt7eam
88
+ :application_id: 2
89
+
90
+ ### User Model
91
+
92
+ require 'twimock'
93
+
94
+ # Create
95
+ user = Twimock::User.new
96
+ user.name = "twimock_test_user"
97
+ user.save!
98
+
99
+ user = Twimock::User.new(name: "hoge", password: "fuga")
100
+ user.name #=> "hoge"
101
+ user.save!
102
+
103
+ user = Twimock::User.create!(name: "hogehoge", password: "fugafuga")
104
+ user.name #=> "hogehoge"
105
+ user.password #=> "fugafuga"
106
+
107
+ # Find
108
+ Twimock::User.find_by_id(1)
109
+ Twimock::User.find_by_name("testuser01")
110
+ Twimock::User.where(name: "testuser02")
111
+ Twimock::User.all
112
+ Twimock::User.first
113
+ Twimock::User.last
114
+
115
+ # Delete
116
+ user = User.last
117
+ user.destroy
118
+
119
+ ## Contributing
120
+
121
+ 1. Fork it
122
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
123
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
124
+ 4. Push to the branch (`git push origin my-new-feature`)
125
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/db/.gitkeep ADDED
File without changes
@@ -0,0 +1,31 @@
1
+ require 'faker'
2
+ require 'twimock/database/table'
3
+
4
+ module Twimock
5
+ class AccessToken < Database::Table
6
+ TABLE_NAME = :access_tokens
7
+ COLUMN_NAMES = [:id, :string, :secret, :application_id, :user_id, :created_at]
8
+
9
+ def initialize(options={})
10
+ opts = Hashie::Mash.new(options)
11
+ id = opts.id.to_i
12
+ @id = id if id > 0
13
+ app_id = opts.application_id.to_i
14
+ @application_id = app_id if app_id > 0
15
+ user_id = opts.user_id.to_i
16
+ @user_id = user_id if user_id > 0
17
+
18
+ @string = generate_string(opts.string)
19
+ @secret = opts.secret || Faker::Lorem.characters(45)
20
+ @created_at = opts.created_at
21
+ end
22
+
23
+ private
24
+
25
+ def generate_string(string=nil)
26
+ return string if string
27
+ return "#{@user_id}-#{Faker::Lorem.characters(39)}" if @user_id
28
+ return Faker::Lorem.characters(50)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,40 @@
1
+ require 'twimock/api/oauth'
2
+ require 'twimock/user'
3
+
4
+ module Twimock
5
+ module API
6
+ # OAuth 1.1, OAuth Echo で利用するAPI
7
+ # ユーザ情報を取得する
8
+ module Account
9
+ class VerifyCredentials < OAuth
10
+ METHOD = "GET"
11
+ PATH = "/1.1/account/verify_credentials.json"
12
+ AUTHORIZATION_REGEXP = /OAuth oauth_consumer_key=\"(.*)\", oauth_nonce=\"(.*)\", oauth_signature=\"(.*)\", oauth_signature_method=\"(.*)\", oauth_timestamp=\"(.*)\", oauth_token=\"(.*)\", oauth_version=\"(.*)\".*/
13
+
14
+ def call(env)
15
+ return super unless called?(env)
16
+
17
+ begin
18
+ authorization_header = env["authorization"] || env["HTTP_AUTHORIZATION"]
19
+ oauth = parse_authorization_header(authorization_header)
20
+
21
+ raise Twimock::Errors::InvalidConsumerKey.new if !validate_consumer_key(oauth.consumer_key)
22
+ application = Twimock::Application.find_by_api_key(oauth.consumer_key)
23
+ raise Twimock::Errors::InvalidAccessToken.new if !validate_access_token(oauth.token, application.id)
24
+ access_token = Twimock::AccessToken.find_by_string(oauth.token)
25
+ user = Twimock::User.find_by_id(access_token.user_id)
26
+ rescue Twimock::Errors::InvalidAccessToken, Twimock::Errors::InvalidConsumerKey => @error
27
+ return unauthorized
28
+ rescue => @error
29
+ return internal_server_error
30
+ end
31
+
32
+ status = '200 OK'
33
+ body = user.info.to_json
34
+ header = { "Content-Length" => body.bytesize.to_s }
35
+ [ status, header, [ body ] ]
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,29 @@
1
+ require 'excon'
2
+
3
+ module Twimock
4
+ module API
5
+ # Rack Application
6
+ # Net::HTTP は ShamRack で偽装されるため, Excon (Socket) で通信する
7
+ class Application
8
+ def call(env)
9
+ request(env)
10
+ end
11
+
12
+ private
13
+
14
+ def request(env)
15
+ rackreq = Rack::Request.new(env)
16
+ connection = Excon.new(rackreq.url)
17
+
18
+ options = {}
19
+ options[:method] = rackreq.request_method
20
+ options[:path] = rackreq.path
21
+ options[:headers] = rackreq.env.select{|k,v| k !~ /^rack\./}
22
+ options[:body] = rackreq.body.read
23
+
24
+ res = connection.request(options)
25
+ [ res.status, res.headers, [ res.body ] ]
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,60 @@
1
+ require 'uri'
2
+ require 'erb'
3
+ require 'json'
4
+ require 'addressable/uri'
5
+ require 'twimock/errors'
6
+
7
+ module Twimock
8
+ module API
9
+ # POST https://twitter.com/intent/sessions
10
+ # body: { 'session[username_or_email]' => "xxx", 'session[password]' => "xxx", oauth_token: "xxx" }
11
+ module Intent
12
+ class Sessions < OAuth
13
+ METHOD = "POST"
14
+ PATH = "/intent/sessions"
15
+
16
+ def call(env)
17
+ return super unless called?(env)
18
+ begin
19
+ request = Rack::Request.new(env)
20
+ body = query_string_to_hash(request.body.read)
21
+ @oauth_token = body.oauth_token
22
+ @username_or_email = body["session[username_or_email]"]
23
+ @password = body["session[password]"]
24
+
25
+ if !validate_request_token(@oauth_token)
26
+ raise Twimock::Errors::InvalidRequestToken.new
27
+ elsif !(user = Twimock::User.find_by_tiwtter_id_or_email(@username_or_email))
28
+ raise Twimock::Errors::InvalidUsernameOrEmail.new
29
+ elsif @password.blank? || @password != user.password
30
+ raise Twimock::Errors::InvalidPassword.new
31
+ end
32
+ request_token = Twimock::RequestToken.find_by_string(@oauth_token)
33
+ request_token.user_id = user.id
34
+ request_token.save!
35
+
36
+ uri = Addressable::URI.new
37
+ uri.query_values = { oauth_token: request_token.string,
38
+ oauth_verifier: request_token.verifier }
39
+ callback_url = Twimock::Config.callback_url + "?" + uri.query
40
+
41
+ status = 302
42
+ body = ""
43
+ header = { "Content-Length" => body.bytesize.to_s,
44
+ "Location" => callback_url }
45
+ [ status, header, [ body ] ]
46
+ rescue Twimock::Errors::InvalidUsernameOrEmail, Twimock::Errors::InvalidPassword => @error
47
+ response = unauthorized
48
+ response[0] = 302
49
+ response[1].merge!( {"Location" => "/oauth/authenticate?oauth_token=#{@oauth_token}" })
50
+ response
51
+ rescue Twimock::Errors::InvalidRequestToken => @error
52
+ return unauthorized
53
+ rescue => @error
54
+ internal_server_error
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,65 @@
1
+ require 'twimock/api/oauth'
2
+ require 'twimock/user'
3
+
4
+ module Twimock
5
+ module API
6
+ class OAuth
7
+ # OAuth 1.1 で利用するAPI
8
+ # Access Token を取得する
9
+ class AccessToken < OAuth
10
+ METHOD = "POST"
11
+ PATH = "/oauth/access_token"
12
+ AUTHORIZATION_REGEXP = /OAuth oauth_body_hash=\"(.*)\", oauth_consumer_key=\"(.*)\", oauth_nonce=\"(.*)\", oauth_signature=\"(.*)\", oauth_signature_method=\"(.*)\", oauth_timestamp=\"(.*)\", oauth_token=\"(.*)\", oauth_verifier=\"(.*)\", oauth_version=\"(.*)\"/
13
+
14
+ def call(env)
15
+ return super unless called?(env)
16
+ begin
17
+ authorization_header = env["authorization"] || env["HTTP_AUTHORIZATION"]
18
+ oauth = parse_authorization_header(authorization_header)
19
+ consumer_key = oauth.consumer_key
20
+ request_token = oauth.token
21
+
22
+ raise Twimock::Errors::InvalidConsumerKey.new if !validate_consumer_key(consumer_key)
23
+ application = Twimock::Application.find_by_api_key(consumer_key)
24
+ if !validate_request_token(request_token, application.id)
25
+ raise Twimock::Errors::InvalidRequestToken.new
26
+ end
27
+ request_token = Twimock::RequestToken.find_by_string(request_token)
28
+ user = Twimock::User.find_by_id(request_token.user_id)
29
+ access_tokens = Twimock::AccessToken.where(user_id: user.id)
30
+ unless access_token = access_tokens.find{|at| at.application_id == application.id }
31
+ access_token = user.generate_access_token(application.id)
32
+ end
33
+ rescue Twimock::Errors::InvalidConsumerKey, Twimock::Errors::InvalidRequestToken => @error
34
+ return unauthorized
35
+ rescue => @error
36
+ return internal_server_error
37
+ end
38
+
39
+ status = "200 OK"
40
+ params = {
41
+ oauth_token: access_token.string,
42
+ oauth_token_secret: access_token.secret,
43
+ user_id: user.id,
44
+ screen_name: user.twitter_id
45
+ }
46
+ body = params.inject([]){|a, (k, v)| a << "#{k}=#{v}"}.join('&')
47
+ header = { "Content-Length" => body.bytesize.to_s }
48
+
49
+ [ status, header, [ body ] ]
50
+ end
51
+
52
+ private
53
+
54
+ def validate_request_token(request_token, application_id)
55
+ return false unless super(request_token)
56
+
57
+ request_token = Twimock::RequestToken.find_by_string(request_token)
58
+ return false unless request_token.application_id == application_id
59
+ return false unless User.find_by_id(request_token.user_id)
60
+ true
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,51 @@
1
+ require 'uri'
2
+ require 'erb'
3
+
4
+ module Twimock
5
+ module API
6
+ # OAuthでブラウザ認証するAPI
7
+ # GET http://api.twimock.com/authenticate?oauth_token=xxx
8
+ class OAuth
9
+ class Authenticate < OAuth
10
+ METHOD = "GET"
11
+ PATH = "/oauth/authenticate"
12
+ VIEW_DIRECTORY = File.expand_path("../../../../../view", __FILE__)
13
+ VIEW_FILE_NAME = "authenticate.html.erb"
14
+
15
+ def call(env)
16
+ return super unless called?(env)
17
+ begin
18
+ request = Rack::Request.new(env)
19
+ @oauth_token = request.params["oauth_token"]
20
+
21
+ if !validate_request_token(@oauth_token)
22
+ raise Twimock::Errors::InvalidRequestToken.new
23
+ end
24
+
25
+ status = 200
26
+ body = Twimock::API::OAuth::Authenticate.view(@oauth_token)
27
+ header = { "Content-Length" => body.bytesize.to_s }
28
+ [ status, header, [ body ] ]
29
+ rescue Twimock::Errors::InvalidRequestToken => @error
30
+ unauthorized
31
+ rescue => @error
32
+ internal_server_error
33
+ end
34
+ end
35
+
36
+ def self.view(oauth_token)
37
+ @action_url = Twimock::API::Intent::Sessions::PATH
38
+ @oauth_token = oauth_token
39
+ erb = ERB.new(File.read(filepath))
40
+ erb.result(binding)
41
+ end
42
+
43
+ private
44
+
45
+ def self.filepath
46
+ File.join(VIEW_DIRECTORY, VIEW_FILE_NAME)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,49 @@
1
+ require 'twimock/api/oauth'
2
+ require 'twimock/application'
3
+
4
+ module Twimock
5
+ module API
6
+ # Twitter OAuth で利用するAPI
7
+ # Request Token を発行する
8
+ class OAuth
9
+ class RequestToken < OAuth
10
+ METHOD = "POST"
11
+ PATH = "/oauth/request_token"
12
+ AUTHORIZATION_REGEXP = /OAuth oauth_callback=\"(.*)\", oauth_consumer_key=\"(.*)\", oauth_nonce=\"(.*)\", oauth_signature=\"(.*)\", oauth_signature_method=\"(.*)\", oauth_timestamp=\"(.*)\", oauth_version=\"(.*)\".*/
13
+
14
+ def call(env)
15
+ return super unless called?(env)
16
+ begin
17
+ authorization_header = env["authorization"] || env["HTTP_AUTHORIZATION"]
18
+ oauth = parse_authorization_header(authorization_header)
19
+ consumer_key = oauth.consumer_key
20
+
21
+ raise Twimock::Errors::InvalidConsumerKey.new if !validate_consumer_key(consumer_key)
22
+ application = Twimock::Application.find_by_api_key(consumer_key)
23
+ rescue Twimock::Errors::InvalidConsumerKey => @error
24
+ return unauthorized
25
+ rescue => @error
26
+ return internal_server_error
27
+ end
28
+
29
+ request_token = create_request_token(application.id)
30
+ status = "200 OK"
31
+ params = { oauth_token: request_token.string,
32
+ oauth_token_secret: request_token.secret,
33
+ oauth_callback_confirmed: true }
34
+ body = params.inject([]){|a, (k, v)| a << "#{k}=#{v}"}.join('&')
35
+ header = { "Content-Length" => body.bytesize.to_s }
36
+ [ status, header, [ body ] ]
37
+ end
38
+
39
+ private
40
+
41
+ def create_request_token(application_id)
42
+ request_token = Twimock::RequestToken.new(application_id: application_id)
43
+ request_token.save!
44
+ request_token
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,83 @@
1
+ require 'twimock/api/oauth/access_token'
2
+ require 'twimock/api/oauth/request_token'
3
+ require 'twimock/api/oauth/authenticate'
4
+ require 'twimock/api/intent/sessions'
5
+ require 'twimock/api/account/verify_credentials'
6
+ require 'twimock/errors'
7
+
8
+ module Twimock
9
+ module API
10
+ class OAuth
11
+ def initialize(app)
12
+ @app = app
13
+ end
14
+
15
+ def call(env)
16
+ @app.call(env)
17
+ end
18
+
19
+ private
20
+
21
+ def validate_consumer_key(consumer_key)
22
+ return false if consumer_key.blank?
23
+ return false unless application = Twimock::Application.find_by_api_key(consumer_key)
24
+ true
25
+ end
26
+
27
+ def validate_request_token(request_token)
28
+ return false if request_token.blank?
29
+ return false unless request_token = Twimock::RequestToken.find_by_string(request_token)
30
+ return false unless request_token.application_id
31
+ true
32
+ end
33
+
34
+ def validate_access_token(access_token_string, application_id)
35
+ return false if access_token_string.blank?
36
+ return false unless access_token = Twimock::AccessToken.find_by_string(access_token_string)
37
+ return false unless access_token.application_id
38
+ return false unless access_token.application_id == application_id
39
+ true
40
+ end
41
+
42
+ def called?(env)
43
+ request = Rack::Request.new(env)
44
+ request.request_method == self.class::METHOD && request.path == self.class::PATH
45
+ end
46
+
47
+ def unauthorized
48
+ generate_error_response(401)
49
+ end
50
+
51
+ def internal_server_error
52
+ generate_error_response(500)
53
+ end
54
+
55
+ def parse_authorization_header(authorization_header)
56
+ authorization = case authorization_header
57
+ when Array then authorization_header.first
58
+ when String then authorization_header
59
+ else ""
60
+ end
61
+
62
+ oauth = Hashie::Mash.new
63
+ authorization.scan(/oauth_(\w+)=\"([\w%-.]+)\"/) do |key, value|
64
+ oauth[key] = value
65
+ end
66
+ oauth
67
+ end
68
+
69
+ def query_string_to_hash(query_string)
70
+ ary = URI.decode(query_string).split("&").inject([]){|a, s| a << s.split("=")}
71
+ Hashie::Mash.new(Hash[ary])
72
+ end
73
+
74
+ def generate_error_response(status)
75
+ error_code = @error.class.to_s.split("::").last
76
+ body = { error: { code: error_code } }.to_json
77
+ header = { "Content-Type" => "application/json; charset=utf-8",
78
+ "Content-Length" => body.bytesize.to_s }
79
+ [ status, header, [ body ] ]
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,35 @@
1
+ require 'twimock/api/application'
2
+ require 'twimock/api/oauth'
3
+ require 'sham_rack'
4
+
5
+ module Twimock
6
+ module API
7
+ extend self
8
+
9
+ HOSTNAME = "api.twitter.com"
10
+ PORT = 443
11
+ MIDDLEWARES = [ OAuth::AccessToken, OAuth::RequestToken, Account::VerifyCredentials ]
12
+
13
+ def on
14
+ ShamRack.at(HOSTNAME, PORT){|env| app.call(env) } unless on?
15
+ true
16
+ end
17
+
18
+ def off
19
+ ShamRack.unmount_all
20
+ true
21
+ end
22
+
23
+ def on?
24
+ !ShamRack.application_for(HOSTNAME, PORT).nil?
25
+ end
26
+
27
+ # Rack Application
28
+ def app
29
+ app = Twimock::API::Application.new
30
+ MIDDLEWARES.inject(app) do |app, klass|
31
+ app = klass.new(app)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,21 @@
1
+ require 'faker'
2
+ require 'twimock/database/table'
3
+ require 'twimock/access_token'
4
+ require 'twimock/request_token'
5
+
6
+ module Twimock
7
+ class Application < Database::Table
8
+ TABLE_NAME = :applications
9
+ COLUMN_NAMES = [:id, :api_key, :api_secret, :created_at]
10
+ CHILDREN = [ Twimock::AccessToken, Twimock::RequestToken ]
11
+
12
+ # WANT : DBに登録済みの値と重複しないようにする(id, api_secret)
13
+ def initialize(options={})
14
+ opts = Hashie::Mash.new(options)
15
+ @id = ( opts.id.to_i > 0 ) ? opts.id.to_i : Faker::Number.number(10).to_i
16
+ @api_key = opts.api_key || Faker::Lorem.characters(25)
17
+ @api_secret = opts.api_secret || Faker::Lorem.characters(50)
18
+ @created_at = opts.created_at
19
+ end
20
+ end
21
+ end