Added a new authentication method to replace official Kate's tokens
This commit is contained in:
parent
076f64788a
commit
29ceca055e
@ -2,6 +2,9 @@
|
||||
|
||||
## changes in this version
|
||||
|
||||
* Changed authentication tokens in Socializer. It is mandatory to download a fresh copy of socializer and start a new configuration for your account.
|
||||
* Stable versions of Socializer are built with Python 3. Previous versions are built with Python 2, however support for Python 2 will be dropped very soon.
|
||||
* There is an installer file for Socializer, available in our downloads page. Installed version of Socializer will be more confortable for some people.
|
||||
* For users from countries where VK is not allowed, Socializer includes a proxy to bypass country restrictions. The first time you start socializer, it will ask you whether you need a proxy or not. It is suggested to use a proxy only if you need it.
|
||||
* Now it is possible to post in someone else's wall. When viewing a timeline of an user, the "post" button will post in his/her wall. To post in your own wall, you'll need to go to the newsfeed or your own wall and press the post button.
|
||||
* If you are not allowed to post in someone's wall, the post button will not be visible.
|
||||
|
0
src/authenticator/__init__.py
Normal file
0
src/authenticator/__init__.py
Normal file
96
src/authenticator/official.py
Normal file
96
src/authenticator/official.py
Normal file
@ -0,0 +1,96 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
""" Set of methods used to retrieve access tokens by simulating the official VK application for Android. """
|
||||
import random
|
||||
import requests
|
||||
import logging
|
||||
from hashlib import md5
|
||||
from .wxUI import two_factor_auth
|
||||
|
||||
log = logging.getLogger("authenticator.official")
|
||||
|
||||
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_sig(method, values, secret):
|
||||
""" Create a signature for parameters passed to VK API. """
|
||||
postdata = ""
|
||||
for key in values:
|
||||
postdata = postdata + "{key}={value}&".format(key=key, value=values[key])
|
||||
# Remove the last "&" character.
|
||||
postdata = postdata[:-1]
|
||||
sig = md5(b"/method/"+method.encode("utf-8")+b"?"+postdata.encode("utf-8")+secret.encode("utf-8"))
|
||||
return sig.hexdigest()
|
||||
|
||||
def perform_request(method, postdata, secret):
|
||||
""" Send a request to VK servers by signing the data with the 'sig' parameter."""
|
||||
url = api_url+method
|
||||
sig = get_sig(method, postdata, secret)
|
||||
postdata.update(sig=sig)
|
||||
headers = {'User-Agent': user_agent}
|
||||
r = requests.post(url, data=postdata, headers=headers)
|
||||
return r.json()
|
||||
|
||||
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, device_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",
|
||||
client_id=client_id, client_secret=client_secret, username=login,
|
||||
password=password, v=api_ver, scope=scope, lang="en", 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 and secret.
|
||||
access_token = res['access_token']
|
||||
secret = res['secret']
|
||||
return access_token, secret, device_id
|
||||
else:
|
||||
raise AuthenticationError(r.text)
|
||||
|
||||
def refresh_token(token, secret, device_id):
|
||||
method = "execute.getUserInfo"
|
||||
postdata = dict(v=api_ver, 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 = dict(v=api_ver, https=1, timestamp=0, receipt2="", device_id=device_id, receipt="", lang="en", nonce="", access_token=token)
|
||||
return perform_request(method, postdata, secret)
|
||||
|
||||
def login(user, password):
|
||||
access_token, secret, device_id = get_non_refreshed(user, password)
|
||||
response = refresh_token(access_token, secret, device_id)
|
||||
try:
|
||||
return response["response"]["token"], secret, device_id
|
||||
except KeyError:
|
||||
log.exception("An exception has occurred while attempting to authenticate. Printing response returned by vk...")
|
||||
log.exception(response)
|
24
src/authenticator/wxUI.py
Normal file
24
src/authenticator/wxUI.py
Normal file
@ -0,0 +1,24 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
import time
|
||||
import wx
|
||||
import widgetUtils
|
||||
|
||||
code = None
|
||||
remember = True
|
||||
|
||||
def two_factor_auth():
|
||||
global code, remember
|
||||
wx.CallAfter(get_code)
|
||||
while code == None:
|
||||
time.sleep(0.5)
|
||||
return (code, remember)
|
||||
|
||||
def get_code():
|
||||
global code, remember
|
||||
dlg = wx.TextEntryDialog(None, _("Please provide the authentication code you have received from VK."), _("Two factor authentication code"))
|
||||
response = dlg.ShowModal()
|
||||
if response == widgetUtils.OK:
|
||||
code = dlg.GetValue()
|
||||
dlg.Destroy()
|
||||
dlg.Destroy()
|
@ -1,16 +0,0 @@
|
||||
import os
|
||||
import ssl
|
||||
from . import utils
|
||||
|
||||
try:
|
||||
context = ssl.create_default_context()
|
||||
der_certs = context.get_ca_certs(binary_form=True)
|
||||
pem_certs = [ssl.DER_cert_to_PEM_cert(der) for der in der_certs]
|
||||
path = os.path.join(utils.getBundleDir(), 'nativecacerts.pem')
|
||||
|
||||
with open(path, 'w') as outfile:
|
||||
for pem in pem_certs:
|
||||
outfile.write(pem + '\n')
|
||||
os.environ['REQUESTS_CA_BUNDLE'] = path
|
||||
except:
|
||||
pass
|
@ -1,132 +0,0 @@
|
||||
from builtins import range
|
||||
import webbrowser
|
||||
import random
|
||||
import requests
|
||||
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 .wxUI import two_factor_auth
|
||||
|
||||
class AuthenticationError(Exception):
|
||||
pass
|
||||
|
||||
class ValidationError(Exception):
|
||||
pass
|
||||
|
||||
class C2DMError(Exception):
|
||||
pass
|
||||
|
||||
client_id = '2685278'
|
||||
client_secret = 'lxhD8OD7dMsqtXIm5IUY'
|
||||
api_ver='5.92'
|
||||
scope = 'all'
|
||||
user_agent = 'KateMobileAndroid/47-427 (Android 6.0.1; SDK 23; armeabi-v7a; samsung SM-G900F; ru)'
|
||||
|
||||
mac_int = getnode()
|
||||
device_id = create_mac_string(mac_int)
|
||||
android_id = device_id.replace(':', '')
|
||||
|
||||
#android_id = '4119748609680577006'
|
||||
|
||||
android_token = '5228540069896927210'
|
||||
api_url = 'https://api.vk.com/method/'
|
||||
|
||||
def requestAuth(login, password, scope=scope):
|
||||
if not (login or password):
|
||||
raise ValueError
|
||||
url = 'https://oauth.vk.com/token?grant_type=password&2fa_supported=1&force_sms=1&client_id='+client_id+'&client_secret='+client_secret+'&username='+login+'&password='+password+'&v='+api_ver+'&scope='+scope
|
||||
headers = {
|
||||
'User-Agent': user_agent
|
||||
}
|
||||
r = requests.get(url, 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)
|
||||
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?grant_type=password&client_id='+client_id+'&client_secret='+client_secret+'&username='+login+'&password='+password+'&v='+api_ver+'&scope='+scope+'&code='+code
|
||||
r = requests.get(url, headers=headers)
|
||||
if r.status_code == 200 and 'access_token' in r.text:
|
||||
res = r.json()
|
||||
access_token = res['access_token']
|
||||
user_id = str(res['user_id'])
|
||||
return access_token, user_id
|
||||
else:
|
||||
raise AuthenticationError(r.text)
|
||||
|
||||
def getReceipt(user_id):
|
||||
if not user_id:
|
||||
raise ValueError
|
||||
url = 'https://android.clients.google.com/c2dm/register3'
|
||||
headers = {
|
||||
'Authorization': 'AidLogin {0}:{1}'.format(android_id, android_token),
|
||||
'app': 'com.perm.kate',
|
||||
'Gcm-ver': '11951438',
|
||||
'Gcm-cert': 'ca7036ce4c5abe56b9f4439ea275171ceb0d35a4',
|
||||
#'User-Agent': 'Android-GCM/1.5 (klte NJH47F)',
|
||||
'content-type': 'application/x-www-form-urlencoded',
|
||||
}
|
||||
data = {
|
||||
'X-subtype': '54740537194',
|
||||
'X-X-subscription': '54740537194',
|
||||
'X-X-subtype': '54740537194',
|
||||
'X-app_ver': '427',
|
||||
'X-kid': '|ID|1|',
|
||||
#'X-osv': '23',
|
||||
'X-cliv': 'iid-9452000',
|
||||
'X-gmsv': '11951438',
|
||||
'X-X-kid': '|ID|1|',
|
||||
'X-appid': ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(11)),
|
||||
'X-scope': 'id'+user_id,
|
||||
'X-subscription': '54740537194',
|
||||
'X-app_ver_name': '47',
|
||||
'app': 'com.perm.kate',
|
||||
'sender': '54740537194',
|
||||
'device': android_id,
|
||||
'cert': 'ca7036ce4c5abe56b9f4439ea275171ceb0d35a4',
|
||||
'app_ver': '427',
|
||||
'gcm_ver': '11951438'
|
||||
}
|
||||
r = requests.post(url, headers=headers, data=data)
|
||||
if r.status_code == 200 and 'token' in r.text:
|
||||
return r.text[13:]
|
||||
else:
|
||||
raise C2DMError(r.text)
|
||||
|
||||
def validateToken(token, receipt):
|
||||
if not (token or receipt):
|
||||
raise ValueError
|
||||
url = api_url+'auth.refreshToken?access_token='+token+'&receipt='+receipt+'&v='+api_ver
|
||||
headers = {'User-Agent': user_agent}
|
||||
r = requests.get(url, headers=headers)
|
||||
if r.status_code == 200 and 'token' in r.text:
|
||||
res = r.json()
|
||||
received_token = res['response']['token']
|
||||
if token == received_token or received_token is None :
|
||||
raise ValidationError(r.text)
|
||||
else:
|
||||
return received_token
|
||||
else:
|
||||
raise ValidationError(r.text)
|
@ -1,80 +0,0 @@
|
||||
""" 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)
|
@ -111,9 +111,10 @@ class vkSession(object):
|
||||
def login(self):
|
||||
try:
|
||||
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"], secret=self.settings["vk"]["secret"], device_id=self.settings["vk"]["device_id"], 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"]["secret"] = self.vk.session_object.secret
|
||||
self.settings["vk"]["device_id"] = self.vk.session_object.device_id
|
||||
self.settings.write()
|
||||
self.logged = True
|
||||
self.get_my_data()
|
||||
|
@ -1,9 +1,9 @@
|
||||
#!/usr/bin/python
|
||||
import keys
|
||||
import logging
|
||||
from . import gettokens
|
||||
from authenticator import official
|
||||
from vk_api.audio import VkAudio
|
||||
from . wxUI import two_factor_auth
|
||||
from authenticator.wxUI import two_factor_auth
|
||||
|
||||
log = logging.getLogger("vkSessionHandler")
|
||||
|
||||
@ -12,14 +12,14 @@ class vkObject(object):
|
||||
def __init__(self):
|
||||
self.api_key = keys.keyring.get_api_key()
|
||||
|
||||
def login(self, user, password, token, alt_token, filename):
|
||||
def login(self, user, password, token, secret, device_id, alt_token, filename):
|
||||
if alt_token == False:
|
||||
log.info("Using kate's token...")
|
||||
# Let's import the patched vk_api module for using a different user agent
|
||||
from . import vk_api_patched as vk_api
|
||||
if token == "" or token == None:
|
||||
log.info("Token is not valid. Generating one...")
|
||||
original_token = gettokens.get_non_refreshed(user, password)
|
||||
original_token = official.login(user, password)
|
||||
token = original_token[0]
|
||||
secret = original_token[1]
|
||||
device_id = original_token[2]
|
||||
|
@ -7,6 +7,7 @@ import logging
|
||||
import vk_api
|
||||
import threading
|
||||
import requests
|
||||
from authenticator.official import get_sig
|
||||
from . import jconfig_patched as jconfig
|
||||
from vk_api.enums import VkUserPermissions
|
||||
from vk_api.exceptions import *
|
||||
@ -93,7 +94,7 @@ class VkApi(vk_api.VkApi):
|
||||
if delay > 0:
|
||||
time.sleep(delay)
|
||||
values.update(https=1, device_id=self.device_id)
|
||||
sig = self.get_sig(method, values, self.secret)
|
||||
sig = get_sig(method, values, self.secret)
|
||||
values.update(sig=sig)
|
||||
response = self.http.post(
|
||||
'https://api.vk.com/method/' + method,
|
||||
@ -134,11 +135,3 @@ class VkApi(vk_api.VkApi):
|
||||
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()
|
@ -1,31 +1,11 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
import time
|
||||
import wx
|
||||
import widgetUtils
|
||||
|
||||
code = None
|
||||
remember = True
|
||||
|
||||
def new_account_dialog():
|
||||
return wx.MessageDialog(None, _("In order to continue, you need to configure your VK account before. Would you like to autorhise a new account now?"), _("Authorisation"), wx.YES_NO).ShowModal()
|
||||
|
||||
def two_factor_auth():
|
||||
global code, remember
|
||||
wx.CallAfter(get_code)
|
||||
while code == None:
|
||||
time.sleep(0.5)
|
||||
return (code, remember)
|
||||
|
||||
def get_code():
|
||||
global code, remember
|
||||
dlg = wx.TextEntryDialog(None, _("Please provide the authentication code you have received from VK."), _("Two factor authentication code"))
|
||||
response = dlg.ShowModal()
|
||||
if response == widgetUtils.OK:
|
||||
code = dlg.GetValue()
|
||||
dlg.Destroy()
|
||||
dlg.Destroy()
|
||||
|
||||
class newSessionDialog(widgetUtils.BaseDialog):
|
||||
def __init__(self):
|
||||
super(newSessionDialog, self).__init__(parent=None, id=wx.NewId(), title=_("Authorise VK"))
|
||||
|
Loading…
Reference in New Issue
Block a user