Skip to content

Commit a39741c

Browse files
Two Factor Authentication Added
1 parent f878d81 commit a39741c

File tree

2 files changed

+132
-35
lines changed

2 files changed

+132
-35
lines changed

keyauth.py

+97-26
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@
44
import binascii # hex encoding
55
import platform # check platform
66
import subprocess # needed for mac device
7-
from datetime import datetime, timedelta
7+
import qrcode
8+
from datetime import datetime, timezone, timedelta
89
from discord_interactions import verify_key # used for signature verification
10+
from PIL import Image
11+
912

1013
try:
1114
if os.name == 'nt':
@@ -143,7 +146,7 @@ def upgrade(self, user, license):
143146
time.sleep(3)
144147
os._exit(1)
145148

146-
def login(self, user, password, hwid=None):
149+
def login(self, user, password, code=None, hwid=None):
147150
self.checkinit()
148151
if hwid is None:
149152
hwid = others.get_hwid()
@@ -155,8 +158,11 @@ def login(self, user, password, hwid=None):
155158
"hwid": hwid,
156159
"sessionid": self.sessionid,
157160
"name": self.name,
158-
"ownerid": self.ownerid
161+
"ownerid": self.ownerid,
159162
}
163+
164+
if code is not None:
165+
post_data["code"] = code
160166

161167
response = self.__do_request(post_data)
162168

@@ -170,7 +176,7 @@ def login(self, user, password, hwid=None):
170176
time.sleep(3)
171177
os._exit(1)
172178

173-
def license(self, key, hwid=None):
179+
def license(self, key, code=None, hwid=None):
174180
self.checkinit()
175181
if hwid is None:
176182
hwid = others.get_hwid()
@@ -183,6 +189,9 @@ def license(self, key, hwid=None):
183189
"name": self.name,
184190
"ownerid": self.ownerid
185191
}
192+
193+
if code is not None:
194+
post_data["code"] = code
186195

187196
response = self.__do_request(post_data)
188197

@@ -507,15 +516,87 @@ def logout(self):
507516
else:
508517
print(json["message"])
509518
time.sleep(3)
510-
os._exit(1)
519+
os._exit(1)
520+
521+
def enable2fa(self, code=None):
522+
self.checkinit()
523+
524+
post_data = {
525+
"type": "2faenable",
526+
"sessionid": self.sessionid,
527+
"name": self.name,
528+
"ownerid": self.ownerid,
529+
"code": code
530+
}
531+
532+
response = self.__do_request(post_data)
533+
534+
json = jsond.loads(response)
535+
536+
if json["success"]:
537+
if code is None:
538+
# First request: Display the 2FA secret code
539+
print(f"Your 2FA secret code is: {json['2fa']['secret_code']}")
540+
qr_code = json['2fa']['QRCode']
541+
self.display_qr_code(qr_code)
542+
code_input = input("Enter the 6 digit 2fa code to enable 2fa: ")
543+
self.enable2fa(code_input);
544+
else:
545+
# Second request: Confirm successful 2FA activation
546+
print("2FA has been successfully enabled!")
547+
time.sleep(3)
548+
else:
549+
print(f"Error: {json['message']}")
550+
time.sleep(3)
551+
os._exit(1)
552+
553+
def disable2fa(self, code=None):
554+
self.checkinit()
555+
556+
code = input("Enter the 6 digit 2fa code to disable 2fa: ")
557+
558+
post_data = {
559+
"type": "2fadisable",
560+
"sessionid": self.sessionid,
561+
"name": self.name,
562+
"ownerid": self.ownerid,
563+
"code": code
564+
}
565+
566+
response = self.__do_request(post_data)
567+
568+
json = jsond.loads(response)
569+
570+
print(json['message'])
571+
time.sleep(3)
572+
573+
574+
def display_qr_code(self, qr_code_url):
575+
# Generate QR code image
576+
qr = qrcode.QRCode(
577+
version=1,
578+
error_correction=qrcode.constants.ERROR_CORRECT_L,
579+
box_size=10,
580+
border=4,
581+
)
582+
583+
# Add the QR code URL data
584+
qr.add_data(qr_code_url)
585+
qr.make(fit=True)
586+
587+
# Create an image from the QR code
588+
img = qr.make_image(fill='black', back_color='white')
589+
590+
# Display the QR code image
591+
img.show()
511592

512593
def __do_request(self, post_data):
513594
try:
514595
response = requests.post(
515-
"https://keyauth.win/api/1.3/", data=post_data, timeout=10
596+
"https://keyauth.win/api/1.3/", data=post_data, timeout=10
516597
)
517598

518-
if post_data["type"] == "log" or post_data["type"] == "file":
599+
if post_data["type"] == "log" or post_data["type"] == "file" or post_data["type"] == "2faenable" or post_data["type"] == "2fadisable":
519600
return response.text
520601

521602
# Get the signature and timestamp from the headers
@@ -527,8 +608,12 @@ def __do_request(self, post_data):
527608
time.sleep(3)
528609
os._exit(1)
529610

530-
server_time = datetime.utcfromtimestamp(int(timestamp))
531-
current_time = datetime.utcnow()
611+
server_time = datetime.fromtimestamp(int(timestamp), timezone.utc)
612+
current_time = datetime.now(timezone.utc)
613+
614+
#print(f"Server Timestamp (UTC seconds): {timestamp}")
615+
#print(f"Server Time (UTC seconds): {server_time.timestamp()}")
616+
#print(f"Current Time (UTC seconds): {current_time.timestamp()}")
532617

533618
buffer_seconds = 5
534619
time_difference = current_time - server_time
@@ -538,31 +623,17 @@ def __do_request(self, post_data):
538623
time.sleep(3)
539624
os._exit(1)
540625

541-
# Proceed with creating debug folders and logging
542-
if not os.path.exists("C:\\ProgramData\\KeyAuth"):
543-
os.makedirs("C:\\ProgramData\\KeyAuth\\Debug")
544-
545-
exe_name = os.path.basename(__file__)
546-
log_dir = f"C:\\ProgramData\\KeyAuth\\Debug\\{exe_name}"
547-
if not os.path.exists(log_dir):
548-
os.makedirs(log_dir)
549-
550-
with open(f"{log_dir}\\log.txt", "a") as log_file:
551-
if len(response.text) <= 200:
552-
execution_time = time.strftime("%I:%M %p | %m/%d/%Y")
553-
log_file.write(f"\n{execution_time} | {post_data['type']} \nResponse: {response.text}")
554-
555626
if not verify_key(response.text.encode('utf-8'), signature, timestamp, '5586b4bc69c7a4b487e4563a4cd96afd39140f919bd31cea7d1c6a1e8439422b'):
556627
print("Signature checksum failed. Request was tampered with or session ended most likely.")
557-
print("Response: " + response.text)
558628
time.sleep(3)
559629
os._exit(1)
560630

561631
return response.text
562632

563-
except requests.exceptions.Timeout:
633+
except requests.exceptions.Timeout:
564634
print("Request timed out. Server is probably down/slow at the moment")
565-
635+
636+
566637
class application_data_class:
567638
numUsers = numKeys = app_ver = customer_panel = onlineUsers = ""
568639

main.py

+35-9
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,12 @@ def clear():
2828
if platform.system() == 'Windows':
2929
os.system('cls & title Python Example') # clear console, change title
3030
elif platform.system() == 'Linux':
31-
os.system('clear') # clear console
32-
sys.stdout.write("\x1b]0;Python Example\x07") # change title
31+
os.system('clear') # Clear the terminal
32+
sys.stdout.write("\033]0;Python Example\007") # Set terminal title
33+
sys.stdout.flush()
3334
elif platform.system() == 'Darwin':
34-
os.system("clear && printf '\e[3J'") # clear console
35-
os.system('''echo - n - e "\033]0;Python Example\007"''') # change title
35+
os.system("clear && printf '\033[3J'") # Clear terminal and scrollback
36+
os.system('echo -n -e "\033]0;Python Example\007"') # Set terminal title
3637

3738
print("Initializing")
3839

@@ -46,9 +47,9 @@ def getchecksum():
4647

4748

4849
keyauthapp = api(
49-
name = "", # Application Name
50-
ownerid = "", # Owner ID
51-
version = "1.0", # Application Version
50+
name = "", # App name
51+
ownerid = "", # Account ID
52+
version = "", # Application version. Used for automatic downloads see video here https://www.youtube.com/watch?v=kW195PLCBKs
5253
hash_to_check = getchecksum()
5354
)
5455

@@ -63,7 +64,8 @@ def answer():
6364
if ans == "1":
6465
user = input('Provide username: ')
6566
password = input('Provide password: ')
66-
keyauthapp.login(user, password)
67+
code = input('Enter 2fa code: (not using 2fa? Just press enter)')
68+
keyauthapp.login(user, password, code)
6769
elif ans == "2":
6870
user = input('Provide username: ')
6971
password = input('Provide password: ')
@@ -75,7 +77,8 @@ def answer():
7577
keyauthapp.upgrade(user, license)
7678
elif ans == "4":
7779
key = input('Enter your license: ')
78-
keyauthapp.license(key)
80+
code = input('Enter 2fa code: (not using 2fa? Just press enter)')
81+
keyauthapp.license(key, code)
7982
else:
8083
print("\nInvalid option")
8184
sleep(1)
@@ -164,7 +167,16 @@ def answer():
164167
print(e)
165168
os._exit(1)'''
166169

170+
keyauthapp.fetchStats()
171+
# Display Application Data
172+
print("\nApplication data: ")
173+
print("App Version: " + keyauthapp.app_data.app_ver)
174+
print("Customer Panel Link: " + keyauthapp.app_data.customer_panel)
175+
print("Number of Keys: " + keyauthapp.app_data.numKeys)
176+
print("Number of Users: " + keyauthapp.app_data.numUsers)
177+
print("Online Users: " + keyauthapp.app_data.onlineUsers)
167178

179+
# Display User Data
168180
print("\nUser data: ")
169181
print("Username: " + keyauthapp.user_data.username)
170182
print("IP address: " + keyauthapp.user_data.ip)
@@ -182,6 +194,20 @@ def answer():
182194
print("Created at: " + datetime.fromtimestamp(int(keyauthapp.user_data.createdate), UTC).strftime('%Y-%m-%d %H:%M:%S'))
183195
print("Last login at: " + datetime.fromtimestamp(int(keyauthapp.user_data.lastlogin), UTC).strftime('%Y-%m-%d %H:%M:%S'))
184196
print("Expires at: " + datetime.fromtimestamp(int(keyauthapp.user_data.expires), UTC).strftime('%Y-%m-%d %H:%M:%S'))
197+
198+
# Two Factor Authentication
199+
print("\nTwo Factor Authentication:")
200+
print("1. Enable 2FA")
201+
print("2. Disable 2FA")
202+
203+
tfaans = input("Select Option: ")
204+
if tfaans == "1":
205+
keyauthapp.enable2fa() # You only need to call this once as it's called in the API file.
206+
elif tfaans == "2":
207+
keyauthapp.disable2fa() # You only need to call this once as it's called in the API file, and should ideally only need to be called once anyways.
208+
else:
209+
print("\nInvalid Option")
210+
185211
print("\nExiting in five seconds..")
186212
sleep(5)
187213
os._exit(1)

0 commit comments

Comments
 (0)