twimock 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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