Added some code to get alternative tokens
This commit is contained in:
parent
b9dca52e52
commit
076f64788a
@ -14,7 +14,7 @@ import output
|
|||||||
import logging
|
import logging
|
||||||
import keys
|
import keys
|
||||||
import application
|
import application
|
||||||
sys.excepthook = lambda x, y, z: logging.critical(''.join(traceback.format_exception(x, y, z)))
|
#sys.excepthook = lambda x, y, z: logging.critical(''.join(traceback.format_exception(x, y, z)))
|
||||||
from mysc.thread_utils import call_threaded
|
from mysc.thread_utils import call_threaded
|
||||||
from wxUI import commonMessages
|
from wxUI import commonMessages
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
user = string(default="")
|
user = string(default="")
|
||||||
password = string(default="")
|
password = string(default="")
|
||||||
token = string(default="")
|
token = string(default="")
|
||||||
|
secret = string(default="")
|
||||||
use_alternative_tokens = boolean(default=False)
|
use_alternative_tokens = boolean(default=False)
|
||||||
invited_to_group = boolean(default=False)
|
invited_to_group = boolean(default=False)
|
||||||
|
|
||||||
|
@ -3,6 +3,29 @@ import webbrowser
|
|||||||
import random
|
import random
|
||||||
import requests
|
import requests
|
||||||
import string
|
import string
|
||||||
|
from uuid import getnode
|
||||||
|
|
||||||
|
def create_mac_string(num, splitter=':'):
|
||||||
|
"""Return the mac address interpretation of num,
|
||||||
|
in the form eg '00:11:22:33:AA:BB'.
|
||||||
|
|
||||||
|
:param num: a 48-bit integer (eg from uuid.getnode)
|
||||||
|
:param spliiter: a string to join the hex pairs with
|
||||||
|
"""
|
||||||
|
|
||||||
|
mac = hex(num)[2:]
|
||||||
|
|
||||||
|
# trim trailing L for long consts
|
||||||
|
if mac[-1] == 'L':
|
||||||
|
mac = mac[:-1]
|
||||||
|
|
||||||
|
pad = max(12 - len(mac), 0)
|
||||||
|
mac = '0' * pad + mac
|
||||||
|
mac = splitter.join([mac[x:x + 2] for x in range(0, 12, 2)])
|
||||||
|
mac = mac.upper()
|
||||||
|
|
||||||
|
return mac
|
||||||
|
|
||||||
from . import _sslfixer
|
from . import _sslfixer
|
||||||
from .wxUI import two_factor_auth
|
from .wxUI import two_factor_auth
|
||||||
|
|
||||||
@ -20,7 +43,13 @@ client_secret = 'lxhD8OD7dMsqtXIm5IUY'
|
|||||||
api_ver='5.92'
|
api_ver='5.92'
|
||||||
scope = 'all'
|
scope = 'all'
|
||||||
user_agent = 'KateMobileAndroid/47-427 (Android 6.0.1; SDK 23; armeabi-v7a; samsung SM-G900F; ru)'
|
user_agent = 'KateMobileAndroid/47-427 (Android 6.0.1; SDK 23; armeabi-v7a; samsung SM-G900F; ru)'
|
||||||
android_id = '4119748609680577006'
|
|
||||||
|
mac_int = getnode()
|
||||||
|
device_id = create_mac_string(mac_int)
|
||||||
|
android_id = device_id.replace(':', '')
|
||||||
|
|
||||||
|
#android_id = '4119748609680577006'
|
||||||
|
|
||||||
android_token = '5228540069896927210'
|
android_token = '5228540069896927210'
|
||||||
api_url = 'https://api.vk.com/method/'
|
api_url = 'https://api.vk.com/method/'
|
||||||
|
|
||||||
|
80
src/sessionmanager/gettokens.py
Normal file
80
src/sessionmanager/gettokens.py
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
""" Set of methods used to retrieve access tokens by simulating an official VK application. """
|
||||||
|
import random
|
||||||
|
import requests
|
||||||
|
from hashlib import md5
|
||||||
|
from .wxUI import two_factor_auth
|
||||||
|
|
||||||
|
class AuthenticationError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Data extracted from official VK android APP.
|
||||||
|
client_id = '2274003'
|
||||||
|
client_secret = 'hHbZxrka2uZ6jB1inYsH'
|
||||||
|
api_ver='5.93'
|
||||||
|
scope = 'nohttps,all'
|
||||||
|
user_agent = 'VKAndroidApp/5.23-2978 (Android 4.4.2; SDK 19; x86; unknown Android SDK built for x86; en; 320x240)'
|
||||||
|
|
||||||
|
api_url = 'https://api.vk.com/method/'
|
||||||
|
|
||||||
|
def get_device_id():
|
||||||
|
""" Generate a random device ID, consisting in 16 alphanumeric characters."""
|
||||||
|
return "".join(random.choice(["1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "a", "b", "c", "d", "e", "f"]) for _ in range(16))
|
||||||
|
|
||||||
|
def get_non_refreshed(login, password, scope=scope):
|
||||||
|
""" Retrieves a non-refreshed token, this should be the first token needed to authenticate in VK.
|
||||||
|
returns the access_token which still needs to be refreshed, current user_id, and secret code, needed to sign all petitions in VK."""
|
||||||
|
if not (login or password):
|
||||||
|
raise ValueError
|
||||||
|
device_id = get_device_id()
|
||||||
|
# Let's authenticate.
|
||||||
|
url = "https://oauth.vk.com/token"
|
||||||
|
params = dict(grant_type="password", lang="en",
|
||||||
|
client_id=client_id, client_secret=client_secret, username=login,
|
||||||
|
password=password, v=api_ver, scope=scope, device_id=device_id)
|
||||||
|
# Add two factor auth later due to python's syntax.
|
||||||
|
params["2fa_supported"] = 1
|
||||||
|
headers = {'User-Agent': user_agent}
|
||||||
|
r = requests.get(url, params=params, headers=headers)
|
||||||
|
# If a 401 error is raised, we need to use 2FA here.
|
||||||
|
# see https://vk.com/dev/auth_direct (switch lang to russian, english docs are very incomplete in the matter)
|
||||||
|
# ToDo: this needs testing after implemented official VK tokens.
|
||||||
|
if r.status_code == 401 and "phone_mask" in r.text:
|
||||||
|
t = r.json()
|
||||||
|
code, remember = two_factor_auth()
|
||||||
|
url = "https://oauth.vk.com/token"
|
||||||
|
params = dict(grant_type="password", lang="en",
|
||||||
|
client_id=client_id, client_secret=client_secret, username=login,
|
||||||
|
password=password, v=api_ver, scope=scope, device_id=device_id, code=code)
|
||||||
|
r = requests.get(url, params=params, headers=headers)
|
||||||
|
if r.status_code == 200 and 'access_token' in r.text:
|
||||||
|
res = r.json()
|
||||||
|
# Retrieve access_token, user_id and secret.
|
||||||
|
access_token = res['access_token']
|
||||||
|
print(access_token)
|
||||||
|
user_id = str(res['user_id'])
|
||||||
|
secret = res['secret']
|
||||||
|
# return access_token, user_id, secret
|
||||||
|
response = refresh_token(access_token, secret, device_id)
|
||||||
|
print(response["response"]["token"])
|
||||||
|
return response["response"]["token"], secret, device_id
|
||||||
|
else:
|
||||||
|
raise AuthenticationError(r.text)
|
||||||
|
|
||||||
|
def perform_request(method, postdata, secret):
|
||||||
|
""" Send a request to VK servers by signing the data with the 'sig' parameter."""
|
||||||
|
url = "https://api.vk.com/method/"+method
|
||||||
|
sig = md5(b"/method/"+method.encode("utf-8")+b"?"+postdata.encode("utf-8")+secret.encode("utf-8"))
|
||||||
|
postdata = postdata+"&sig="+sig.hexdigest()
|
||||||
|
headers = {
|
||||||
|
'User-Agent': user_agent
|
||||||
|
}
|
||||||
|
r = requests.post(url+"?"+postdata, headers=headers)
|
||||||
|
return r.json()
|
||||||
|
|
||||||
|
def refresh_token(token, secret, device_id):
|
||||||
|
method = "execute.getUserInfo"
|
||||||
|
postdata = "v=5.93&https=1&androidVersion=19&androidModel=Android SDK built for x86&info_fields=audio_ads,audio_background_limit,country,discover_design_version,discover_preload,discover_preload_not_seen,gif_autoplay,https_required,inline_comments,intro,lang,menu_intro,money_clubs_p2p,money_p2p,money_p2p_params,music_intro,audio_restrictions,profiler_settings,raise_to_record_enabled,stories,masks,subscriptions,support_url,video_autoplay,video_player,vklive_app,community_comments,webview_authorization,story_replies,animated_stickers,community_stories,live_section,playlists_download,calls,security_issue,eu_user,wallet,vkui_community_create,vkui_profile_edit,vkui_community_manage,vk_apps,stories_photo_duration,stories_reposts,live_streaming,live_masks,camera_pingpong,role,video_discover&device_id="+device_id+"&lang=en&func_v=11&androidManufacturer=unknown&fields=photo_100,photo_50,exports,country,sex,status,bdate,first_name_gen,last_name_gen,verified,trending&access_token="+token
|
||||||
|
perform_request(method, postdata, secret)
|
||||||
|
method = "auth.refreshToken"
|
||||||
|
postdata = "v=5.93&https=1×tamp=0&receipt=''&receipt2=''&device_id="+device_id+"&lang=en&nonce=''&access_token="+token
|
||||||
|
return perform_request(method, postdata, secret)
|
@ -113,6 +113,7 @@ class vkSession(object):
|
|||||||
config_filename = os.path.join(paths.config_path(), self.session_id, "vkconfig.json")
|
config_filename = os.path.join(paths.config_path(), self.session_id, "vkconfig.json")
|
||||||
self.vk.login(self.settings["vk"]["user"], self.settings["vk"]["password"], token=self.settings["vk"]["token"], alt_token=self.settings["vk"]["use_alternative_tokens"], filename=config_filename)
|
self.vk.login(self.settings["vk"]["user"], self.settings["vk"]["password"], token=self.settings["vk"]["token"], alt_token=self.settings["vk"]["use_alternative_tokens"], filename=config_filename)
|
||||||
self.settings["vk"]["token"] = self.vk.session_object.token["access_token"]
|
self.settings["vk"]["token"] = self.vk.session_object.token["access_token"]
|
||||||
|
self.settings["vk"]["secret"] = self.vk.session_object.secret
|
||||||
self.settings.write()
|
self.settings.write()
|
||||||
self.logged = True
|
self.logged = True
|
||||||
self.get_my_data()
|
self.get_my_data()
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
import keys
|
import keys
|
||||||
import logging
|
import logging
|
||||||
from . import core
|
from . import gettokens
|
||||||
from vk_api.audio import VkAudio
|
from vk_api.audio import VkAudio
|
||||||
from . wxUI import two_factor_auth
|
from . wxUI import two_factor_auth
|
||||||
|
|
||||||
@ -19,12 +19,12 @@ class vkObject(object):
|
|||||||
from . import vk_api_patched as vk_api
|
from . import vk_api_patched as vk_api
|
||||||
if token == "" or token == None:
|
if token == "" or token == None:
|
||||||
log.info("Token is not valid. Generating one...")
|
log.info("Token is not valid. Generating one...")
|
||||||
token = core.requestAuth(user, password)
|
original_token = gettokens.get_non_refreshed(user, password)
|
||||||
token = token[0]
|
token = original_token[0]
|
||||||
receipt = core.getReceipt(token)
|
secret = original_token[1]
|
||||||
token = core.validateToken(token, receipt)
|
device_id = original_token[2]
|
||||||
log.info("Token validated...")
|
log.info("Token validated...")
|
||||||
self.session_object = vk_api.VkApi(app_id=self.api_key, login=user, password=password, token=token, scope="offline, wall, notify, friends, photos, audio, video, docs, notes, pages, status, groups, messages, notifications, stats", config_filename=filename)
|
self.session_object = vk_api.VkApi(app_id=self.api_key, login=user, password=password, token=token, secret=secret, device_id=device_id, scope="offline, wall, notify, friends, photos, audio, video, docs, notes, pages, status, groups, messages, notifications, stats", config_filename=filename)
|
||||||
else:
|
else:
|
||||||
import vk_api
|
import vk_api
|
||||||
self.session_object = vk_api.VkApi(app_id=self.api_key, login=user, password=password, scope="offline, wall, notify, friends, photos, audio, video, docs, notes, pages, status, groups, messages, notifications, stats", config_filename=filename, auth_handler=two_factor_auth)
|
self.session_object = vk_api.VkApi(app_id=self.api_key, login=user, password=password, scope="offline, wall, notify, friends, photos, audio, video, docs, notes, pages, status, groups, messages, notifications, stats", config_filename=filename, auth_handler=two_factor_auth)
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
""" this is a patched version of vk_api to use a different user agent for authenticating against VK.
|
""" this is a patched version of vk_api to use a different user agent for authenticating against VK.
|
||||||
Everything else looks the same, the only change in the module is the new user agent, emulating a kate mobile session."""
|
Everything else looks the same, the only change in the module is the new user agent, emulating a kate mobile session."""
|
||||||
|
import time
|
||||||
|
import hashlib
|
||||||
import logging
|
import logging
|
||||||
import vk_api
|
import vk_api
|
||||||
import threading
|
import threading
|
||||||
@ -13,7 +15,7 @@ DEFAULT_USER_SCOPE = sum(VkUserPermissions)
|
|||||||
|
|
||||||
class VkApi(vk_api.VkApi):
|
class VkApi(vk_api.VkApi):
|
||||||
|
|
||||||
def __init__(self, login=None, password=None, token=None,
|
def __init__(self, login=None, password=None, token=None, secret=None, device_id=None,
|
||||||
auth_handler=None, captcha_handler=None,
|
auth_handler=None, captcha_handler=None,
|
||||||
config=jconfig.Config, config_filename='vk_config.v2.json',
|
config=jconfig.Config, config_filename='vk_config.v2.json',
|
||||||
api_version='5.92', app_id=2685278, scope=DEFAULT_USER_SCOPE,
|
api_version='5.92', app_id=2685278, scope=DEFAULT_USER_SCOPE,
|
||||||
@ -23,7 +25,8 @@ class VkApi(vk_api.VkApi):
|
|||||||
self.password = password
|
self.password = password
|
||||||
|
|
||||||
self.token = {'access_token': token}
|
self.token = {'access_token': token}
|
||||||
|
self.secret = secret
|
||||||
|
self.device_id = device_id
|
||||||
self.api_version = api_version
|
self.api_version = api_version
|
||||||
self.app_id = app_id
|
self.app_id = app_id
|
||||||
self.scope = scope
|
self.scope = scope
|
||||||
@ -32,7 +35,7 @@ class VkApi(vk_api.VkApi):
|
|||||||
self.storage = config(self.login, filename=config_filename)
|
self.storage = config(self.login, filename=config_filename)
|
||||||
|
|
||||||
self.http = requests.Session()
|
self.http = requests.Session()
|
||||||
self.http.headers.update({'User-agent': 'KateMobileAndroid/47-427 (Android 6.0.1; SDK 23; armeabi-v7a; samsung SM-G900F; ru)'})
|
self.http.headers.update({'User-agent': 'VKAndroidApp/5.23-2978 (Android 4.4.2; SDK 19; x86; unknown Android SDK built for x86; en; 320x240)'})
|
||||||
|
|
||||||
self.last_request = 0.0
|
self.last_request = 0.0
|
||||||
|
|
||||||
@ -46,4 +49,96 @@ class VkApi(vk_api.VkApi):
|
|||||||
self.lock = threading.Lock()
|
self.lock = threading.Lock()
|
||||||
|
|
||||||
self.logger = logging.getLogger('vk_api_patched')
|
self.logger = logging.getLogger('vk_api_patched')
|
||||||
self.logger.info('Started patched VK API client...')
|
self.logger.info('Started patched VK API client...')
|
||||||
|
|
||||||
|
def method(self, method, values=None, captcha_sid=None, captcha_key=None,
|
||||||
|
raw=False):
|
||||||
|
""" Вызов метода API
|
||||||
|
|
||||||
|
:param method: название метода
|
||||||
|
:type method: str
|
||||||
|
|
||||||
|
:param values: параметры
|
||||||
|
:type values: dict
|
||||||
|
|
||||||
|
:param captcha_sid: id капчи
|
||||||
|
:type captcha_key: int or str
|
||||||
|
|
||||||
|
:param captcha_key: ответ капчи
|
||||||
|
:type captcha_key: str
|
||||||
|
|
||||||
|
:param raw: при False возвращает `response['response']`
|
||||||
|
при True возвращает `response`
|
||||||
|
(может понадобиться для метода execute для получения
|
||||||
|
execute_errors)
|
||||||
|
:type raw: bool
|
||||||
|
"""
|
||||||
|
|
||||||
|
values = values.copy() if values else {}
|
||||||
|
|
||||||
|
if 'v' not in values:
|
||||||
|
values['v'] = self.api_version
|
||||||
|
|
||||||
|
if self.token:
|
||||||
|
values['access_token'] = self.token['access_token']
|
||||||
|
|
||||||
|
if captcha_sid and captcha_key:
|
||||||
|
values['captcha_sid'] = captcha_sid
|
||||||
|
values['captcha_key'] = captcha_key
|
||||||
|
|
||||||
|
with self.lock:
|
||||||
|
# Ограничение 3 запроса в секунду
|
||||||
|
delay = self.RPS_DELAY - (time.time() - self.last_request)
|
||||||
|
|
||||||
|
if delay > 0:
|
||||||
|
time.sleep(delay)
|
||||||
|
values.update(https=1, device_id=self.device_id)
|
||||||
|
sig = self.get_sig(method, values, self.secret)
|
||||||
|
values.update(sig=sig)
|
||||||
|
response = self.http.post(
|
||||||
|
'https://api.vk.com/method/' + method,
|
||||||
|
values
|
||||||
|
)
|
||||||
|
self.last_request = time.time()
|
||||||
|
|
||||||
|
if response.ok:
|
||||||
|
response = response.json()
|
||||||
|
else:
|
||||||
|
error = ApiHttpError(self, method, values, raw, response)
|
||||||
|
response = self.http_handler(error)
|
||||||
|
|
||||||
|
if response is not None:
|
||||||
|
return response
|
||||||
|
|
||||||
|
raise error
|
||||||
|
|
||||||
|
if 'error' in response:
|
||||||
|
error = ApiError(self, method, values, raw, response['error'])
|
||||||
|
|
||||||
|
if error.code in self.error_handlers:
|
||||||
|
if error.code == CAPTCHA_ERROR_CODE:
|
||||||
|
error = Captcha(
|
||||||
|
self,
|
||||||
|
error.error['captcha_sid'],
|
||||||
|
self.method,
|
||||||
|
(method,),
|
||||||
|
{'values': values, 'raw': raw},
|
||||||
|
error.error['captcha_img']
|
||||||
|
)
|
||||||
|
|
||||||
|
response = self.error_handlers[error.code](error)
|
||||||
|
|
||||||
|
if response is not None:
|
||||||
|
return response
|
||||||
|
|
||||||
|
raise error
|
||||||
|
|
||||||
|
return response if raw else response['response']
|
||||||
|
|
||||||
|
def get_sig(self, method, values, secret):
|
||||||
|
postdata = ""
|
||||||
|
for key in values:
|
||||||
|
postdata = postdata + "{key}={value}&".format(key=key, value=values[key])
|
||||||
|
postdata = postdata[:-1]
|
||||||
|
sig = hashlib.md5(b"/method/"+method.encode("utf-8")+b"?"+postdata.encode("utf-8")+secret.encode("utf-8"))
|
||||||
|
return sig.hexdigest()
|
Loading…
Reference in New Issue
Block a user