vkontakte_client 2.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.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/.rubocop.yml +33 -0
- data/LICENSE +21 -0
- data/README.md +90 -0
- data/README.ru.md +79 -0
- data/examples/accept_all_requests.rb +37 -0
- data/examples/add_suggestions.rb +40 -0
- data/examples/ban_news_from_all_friends.rb +72 -0
- data/examples/friends_of_friends.rb +125 -0
- data/examples/get_online_friends.rb +30 -0
- data/examples/last_seen.rb +32 -0
- data/examples/long_poll.rb +105 -0
- data/examples/mechanize.rb +55 -0
- data/examples/remove_out_requests.rb +44 -0
- data/examples/remove_suspended_friends.rb +30 -0
- data/examples/users_get_offline.rb +17 -0
- data/examples/users_info.rb +25 -0
- data/gems.rb +5 -0
- data/lib/socksify_mechanize.rb +24 -0
- data/lib/vkontakte/api.rb +86 -0
- data/lib/vkontakte/api_error.rb +22 -0
- data/lib/vkontakte/ask_for_credentials.rb +57 -0
- data/lib/vkontakte/client.rb +129 -0
- data/lib/vkontakte/proxy.rb +23 -0
- data/lib/vkontakte/version.rb +5 -0
- data/lib/vkontakte_client.rb +18 -0
- data/vkontakte_client.gemspec +25 -0
- metadata +150 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Vkontakte
|
4
|
+
class API
|
5
|
+
# An exception raised by `Vkontakte::API` when given a response with an error
|
6
|
+
class Error < StandardError
|
7
|
+
attr_reader :method_name, :error_code, :error_msg, :params
|
8
|
+
|
9
|
+
def initialize(method_name, error_code, error_msg, params)
|
10
|
+
@method_name = method_name
|
11
|
+
@error_code = error_code.to_i
|
12
|
+
@error_msg = error_msg
|
13
|
+
@params = params
|
14
|
+
end
|
15
|
+
|
16
|
+
# A full description of the error
|
17
|
+
def message
|
18
|
+
"VKontakte returned an error #{@error_code}: '#{@error_msg}' after calling method '#{@method_name}' with parameters #{@params.inspect}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Vkontakte
|
4
|
+
# Ask Email and Password for user
|
5
|
+
class AskForCredentials
|
6
|
+
attr_reader :email, :password
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
ask_for_credentials
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def ask_for_credentials
|
15
|
+
puts 'Enter your credentials.'
|
16
|
+
|
17
|
+
print 'Email: '
|
18
|
+
@email = ask
|
19
|
+
|
20
|
+
print 'Password (typing will be hidden): '
|
21
|
+
@password = ask_for_password
|
22
|
+
|
23
|
+
nil
|
24
|
+
end
|
25
|
+
|
26
|
+
def ask
|
27
|
+
$stdin.gets.to_s.strip
|
28
|
+
end
|
29
|
+
|
30
|
+
def ask_for_password
|
31
|
+
echo_off
|
32
|
+
password = ask
|
33
|
+
puts
|
34
|
+
echo_on
|
35
|
+
|
36
|
+
password
|
37
|
+
end
|
38
|
+
|
39
|
+
def echo_off
|
40
|
+
with_tty do
|
41
|
+
system 'stty -echo'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def echo_on
|
46
|
+
with_tty do
|
47
|
+
system 'stty echo'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def with_tty
|
52
|
+
return unless $stdin.isatty
|
53
|
+
|
54
|
+
yield
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Vkontakte
|
4
|
+
# :nodoc:
|
5
|
+
class Client
|
6
|
+
attr_reader :api, :access_token, :user_id, :expires_in, :api_version
|
7
|
+
|
8
|
+
def initialize(
|
9
|
+
client_id = nil,
|
10
|
+
api_version: Vkontakte::API_VERSION,
|
11
|
+
proxy: nil,
|
12
|
+
timeout: 60
|
13
|
+
)
|
14
|
+
@client_id = client_id
|
15
|
+
@api_version = api_version
|
16
|
+
@proxy = proxy
|
17
|
+
@timeout = timeout
|
18
|
+
@authorize = false
|
19
|
+
|
20
|
+
@api = Vkontakte::API.new
|
21
|
+
end
|
22
|
+
|
23
|
+
def login!(email, pass, open_captcha: false, permissions: '')
|
24
|
+
@email = email
|
25
|
+
@pass = pass
|
26
|
+
|
27
|
+
redirect_uri = 'https://oauth.vk.com/blank.html'
|
28
|
+
display = 'mobile'
|
29
|
+
response_type = 'token'
|
30
|
+
|
31
|
+
query = {
|
32
|
+
client_id: @client_id,
|
33
|
+
redirect_uri: redirect_uri,
|
34
|
+
display: display,
|
35
|
+
scope: permissions,
|
36
|
+
response_type: response_type,
|
37
|
+
v: api_version
|
38
|
+
}
|
39
|
+
|
40
|
+
agent = Mechanize.new do |a|
|
41
|
+
a.user_agent_alias = 'Linux Firefox'
|
42
|
+
a.follow_meta_refresh
|
43
|
+
|
44
|
+
a.agent.set_socks(@proxy.addr, @proxy.port) if @proxy&.socks?
|
45
|
+
a.agent.set_proxy(@proxy.addr, @proxy.port) if @proxy&.http?
|
46
|
+
end
|
47
|
+
|
48
|
+
# https://vk.com/dev/implicit_flow_user
|
49
|
+
#
|
50
|
+
# Открытие диалога авторизации OAuth
|
51
|
+
#
|
52
|
+
query_string = query.map { |k, v| "#{k}=#{v}" }.join('&')
|
53
|
+
url = "https://oauth.vk.com/authorize?#{query_string}"
|
54
|
+
|
55
|
+
page = agent.get(url)
|
56
|
+
|
57
|
+
login_form = page.forms.first
|
58
|
+
login_form.email = @email
|
59
|
+
login_form.pass = @pass
|
60
|
+
page = login_form.submit
|
61
|
+
|
62
|
+
raise('Invalid login or password.') unless page.search('.service_msg_warning').empty?
|
63
|
+
|
64
|
+
page = submit_gain_access_form(page, open_captcha) if page.uri.path == '/authorize'
|
65
|
+
|
66
|
+
get_token(page)
|
67
|
+
end
|
68
|
+
|
69
|
+
def authorized?
|
70
|
+
@authorize ? true : false
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def get_token(page)
|
76
|
+
auth_regexp = /access_token=(?<access_token>.*)&expires_in=(?<expires_in>\d+)&user_id=(?<user_id>\d*)\z/
|
77
|
+
|
78
|
+
return false unless page.uri.path == '/auth_redirect'
|
79
|
+
|
80
|
+
query_params = URI.decode_www_form(page.uri.query).to_h
|
81
|
+
authorize_url = CGI.unescape(query_params['authorize_url'])
|
82
|
+
|
83
|
+
auth_params = authorize_url.match(auth_regexp)
|
84
|
+
|
85
|
+
return false unless auth_params
|
86
|
+
|
87
|
+
@access_token = auth_params[:access_token]
|
88
|
+
@user_id = auth_params[:user_id]
|
89
|
+
@expires_in = auth_params[:expires_in]
|
90
|
+
|
91
|
+
@api = Vkontakte::API.new(
|
92
|
+
@access_token,
|
93
|
+
proxy: @proxy,
|
94
|
+
api_version: @api_version,
|
95
|
+
timeout: @timeout
|
96
|
+
)
|
97
|
+
|
98
|
+
@authorize = true
|
99
|
+
|
100
|
+
@access_token
|
101
|
+
end
|
102
|
+
|
103
|
+
def submit_gain_access_form(page, open_captcha)
|
104
|
+
form = page.forms.first
|
105
|
+
|
106
|
+
return form.submit unless form.has_key?('captcha_key')
|
107
|
+
|
108
|
+
raise('Captcha needed.') unless open_captcha
|
109
|
+
|
110
|
+
captcha_img = page.search('img[id=captcha]').first
|
111
|
+
|
112
|
+
puts 'Captcha needed.'
|
113
|
+
puts "Open url: #{captcha_img['src']}"
|
114
|
+
print 'Enter captch: '
|
115
|
+
captcha = $stdin.gets.chomp
|
116
|
+
|
117
|
+
form.pass = @pass
|
118
|
+
form.captcha_key = captcha
|
119
|
+
allow_page = form.submit
|
120
|
+
|
121
|
+
allow_form = allow_page.forms.first
|
122
|
+
allow_page = allow_form.submit if allow_form&.buttons&.detect { |btn| btn.value == 'Allow' }
|
123
|
+
|
124
|
+
raise('Invalid captcha.') unless allow_page.uri.path == '/blank.html'
|
125
|
+
|
126
|
+
allow_page
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Vkontakte
|
4
|
+
class Proxy # :nodoc:
|
5
|
+
attr_reader :type, :addr, :port
|
6
|
+
|
7
|
+
VALID_PROXY_TYPES = %i[http socks].freeze
|
8
|
+
|
9
|
+
def initialize(type, addr, port)
|
10
|
+
raise(StandartError, "#{`type`} is an invalid proxy type. Available values: #{VALID_PROXY_TYPES.join(',')}") unless VALID_PROXY_TYPES.include?(type)
|
11
|
+
|
12
|
+
@type = type
|
13
|
+
@addr = addr
|
14
|
+
@port = port
|
15
|
+
end
|
16
|
+
|
17
|
+
VALID_PROXY_TYPES.each do |type|
|
18
|
+
define_method(:"#{type}?") do
|
19
|
+
@type == type
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'net/http'
|
5
|
+
require 'mechanize'
|
6
|
+
require 'socksify'
|
7
|
+
require 'socksify_mechanize'
|
8
|
+
|
9
|
+
require 'vkontakte/version'
|
10
|
+
require 'vkontakte/client'
|
11
|
+
require 'vkontakte/api'
|
12
|
+
require 'vkontakte/api_error'
|
13
|
+
require 'vkontakte/proxy'
|
14
|
+
require 'vkontakte/ask_for_credentials'
|
15
|
+
|
16
|
+
module Vkontakte
|
17
|
+
API_VERSION = '5.101'
|
18
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
$LOAD_PATH.push File.expand_path('lib', __dir__)
|
4
|
+
require 'vkontakte/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.authors = ['Anton Maminov']
|
8
|
+
gem.email = ['anton.maminov@gmail.com']
|
9
|
+
gem.description = 'VKontakte API Client for Ruby'
|
10
|
+
gem.summary = 'Unofficial VKontakte API Client for Ruby'
|
11
|
+
gem.homepage = 'https://github.com/mamantoha/vkontakte_client'
|
12
|
+
gem.licenses = ['MIT']
|
13
|
+
|
14
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
15
|
+
gem.files = `git ls-files`.split("\n")
|
16
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
17
|
+
gem.name = 'vkontakte_client'
|
18
|
+
gem.require_paths = ['lib']
|
19
|
+
gem.version = Vkontakte::VERSION
|
20
|
+
gem.required_ruby_version = '>= 2.7.0'
|
21
|
+
gem.add_runtime_dependency 'mechanize', '~> 2.8', '>= 2.8.0'
|
22
|
+
gem.add_runtime_dependency 'socksify', '~> 1.7', '>= 1.7.0'
|
23
|
+
gem.add_development_dependency 'pry', '~> 0.14', '>= 0.14.0'
|
24
|
+
gem.add_development_dependency 'rubocop', '~> 1.18', '>= 1.18.0'
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,150 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: vkontakte_client
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 2.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Anton Maminov
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-08-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: mechanize
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.8'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 2.8.0
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '2.8'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 2.8.0
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: socksify
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '1.7'
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 1.7.0
|
43
|
+
type: :runtime
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - "~>"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '1.7'
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 1.7.0
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: pry
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - "~>"
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '0.14'
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: 0.14.0
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - "~>"
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0.14'
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: 0.14.0
|
73
|
+
- !ruby/object:Gem::Dependency
|
74
|
+
name: rubocop
|
75
|
+
requirement: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - "~>"
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '1.18'
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 1.18.0
|
83
|
+
type: :development
|
84
|
+
prerelease: false
|
85
|
+
version_requirements: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '1.18'
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: 1.18.0
|
93
|
+
description: VKontakte API Client for Ruby
|
94
|
+
email:
|
95
|
+
- anton.maminov@gmail.com
|
96
|
+
executables: []
|
97
|
+
extensions: []
|
98
|
+
extra_rdoc_files: []
|
99
|
+
files:
|
100
|
+
- ".gitignore"
|
101
|
+
- ".rubocop.yml"
|
102
|
+
- LICENSE
|
103
|
+
- README.md
|
104
|
+
- README.ru.md
|
105
|
+
- examples/accept_all_requests.rb
|
106
|
+
- examples/add_suggestions.rb
|
107
|
+
- examples/ban_news_from_all_friends.rb
|
108
|
+
- examples/friends_of_friends.rb
|
109
|
+
- examples/get_online_friends.rb
|
110
|
+
- examples/last_seen.rb
|
111
|
+
- examples/long_poll.rb
|
112
|
+
- examples/mechanize.rb
|
113
|
+
- examples/remove_out_requests.rb
|
114
|
+
- examples/remove_suspended_friends.rb
|
115
|
+
- examples/users_get_offline.rb
|
116
|
+
- examples/users_info.rb
|
117
|
+
- gems.rb
|
118
|
+
- lib/socksify_mechanize.rb
|
119
|
+
- lib/vkontakte/api.rb
|
120
|
+
- lib/vkontakte/api_error.rb
|
121
|
+
- lib/vkontakte/ask_for_credentials.rb
|
122
|
+
- lib/vkontakte/client.rb
|
123
|
+
- lib/vkontakte/proxy.rb
|
124
|
+
- lib/vkontakte/version.rb
|
125
|
+
- lib/vkontakte_client.rb
|
126
|
+
- vkontakte_client.gemspec
|
127
|
+
homepage: https://github.com/mamantoha/vkontakte_client
|
128
|
+
licenses:
|
129
|
+
- MIT
|
130
|
+
metadata: {}
|
131
|
+
post_install_message:
|
132
|
+
rdoc_options: []
|
133
|
+
require_paths:
|
134
|
+
- lib
|
135
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - ">="
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: 2.7.0
|
140
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - ">="
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '0'
|
145
|
+
requirements: []
|
146
|
+
rubygems_version: 3.2.22
|
147
|
+
signing_key:
|
148
|
+
specification_version: 4
|
149
|
+
summary: Unofficial VKontakte API Client for Ruby
|
150
|
+
test_files: []
|