Updated to new oauth format. Removed pypasser dependency.
This commit is contained in:
parent
c1b7056838
commit
51aabe8b53
102
dmmBypass.py
102
dmmBypass.py
|
@ -9,6 +9,10 @@ import urllib.parse
|
||||||
from uuid import getnode
|
from uuid import getnode
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
# Set to False to allow packet sniffing/capture.
|
||||||
|
# Set separately for dmmUpdater
|
||||||
|
SSL_VERIFY = True
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description='DMM bypass script')
|
parser = argparse.ArgumentParser(description='DMM bypass script')
|
||||||
parser.add_argument('-g', '--game', type=str, help="DMM code name of the game", default="kfp2g")
|
parser.add_argument('-g', '--game', type=str, help="DMM code name of the game", default="kfp2g")
|
||||||
parser.add_argument('-t', '--type', help="DMM game type (ACL/GCL)", default="GCL")
|
parser.add_argument('-t', '--type', help="DMM game type (ACL/GCL)", default="GCL")
|
||||||
|
@ -30,7 +34,7 @@ def save_config(game_id, config):
|
||||||
config = load_config(args.game)
|
config = load_config(args.game)
|
||||||
|
|
||||||
if config is None:
|
if config is None:
|
||||||
subprocess.check_call([sys.executable, "-m", "pip", "install", "requests", "beautifulsoup4", "PyPasser"])
|
subprocess.check_call([sys.executable, "-m", "pip", "install", "requests", "beautifulsoup4"])
|
||||||
config = {
|
config = {
|
||||||
"game_id" : args.game,
|
"game_id" : args.game,
|
||||||
"file_path" : input('Enter full file path to KF3 .exe: ').strip('\"'),
|
"file_path" : input('Enter full file path to KF3 .exe: ').strip('\"'),
|
||||||
|
@ -49,7 +53,6 @@ config["game_type"] = args.type
|
||||||
import requests
|
import requests
|
||||||
import dmmUpdater
|
import dmmUpdater
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
from pypasser import reCaptchaV3
|
|
||||||
|
|
||||||
def get_hash(data):
|
def get_hash(data):
|
||||||
sha_obj = hashlib.sha256()
|
sha_obj = hashlib.sha256()
|
||||||
|
@ -75,38 +78,48 @@ def get_game_root_path(user_path, game_dir, exe_name):
|
||||||
else:
|
else:
|
||||||
raise Exception(f"Path to game files is incorrect! Ensure it points to {exe_name} or contains {game_dir}!")
|
raise Exception(f"Path to game files is incorrect! Ensure it points to {exe_name} or contains {game_dir}!")
|
||||||
|
|
||||||
def retrieve_login_token(session : requests.Session):
|
def retrieve_oauth_code(login, password, session : requests.Session):
|
||||||
try:
|
try:
|
||||||
print("Retrieving login form")
|
print("Retrieving login url")
|
||||||
url = "https://accounts.dmm.com/service/login/password"
|
url = "https://apidgp-gameplayer.games.dmm.com/v5/auth/login/url"
|
||||||
result = session.get(url)
|
data = {"prompt":"choose"}
|
||||||
|
result = session.post(url, json=data, verify=SSL_VERIFY)
|
||||||
|
result.raise_for_status()
|
||||||
|
url = result.json()["data"]["url"]
|
||||||
|
encoded_url = urllib.parse.quote_plus(url.replace("https://accounts.dmm.com/service/oauth/select/=/path=", "").replace("oauth/select/", "oauth/").replace("accounts?prompt=choose", "accounts"))
|
||||||
|
|
||||||
|
print("Retrieving login form token")
|
||||||
|
result = session.get(url, verify=SSL_VERIFY)
|
||||||
result.raise_for_status()
|
result.raise_for_status()
|
||||||
page = BeautifulSoup(result.content, 'html.parser')
|
page = BeautifulSoup(result.content, 'html.parser')
|
||||||
token = page.find('input', attrs={"name":"token"}).get("value")
|
token = page.find('input', attrs={"name":"token"}).get("value")
|
||||||
return token
|
|
||||||
|
print("Retrieving oauth link")
|
||||||
|
url = "https://accounts.dmm.com/service/oauth/authenticate"
|
||||||
|
headers = {"Content-Type": "application/x-www-form-urlencoded",
|
||||||
|
"check_done_login":"true"}
|
||||||
|
data = f"token={token}&login_id={login}&password={password}&use_auto_login=1&path={encoded_url}&recaptchaToken="
|
||||||
|
result = session.post(url, data, headers=headers, verify=SSL_VERIFY)
|
||||||
|
result.raise_for_status()
|
||||||
|
page = BeautifulSoup(result.content, 'html.parser')
|
||||||
|
final_url = page.find('input', attrs={"id":"ga-param-service-url"}).get("value")
|
||||||
|
|
||||||
|
print("Retrieving oauth token")
|
||||||
|
result = session.get(final_url, allow_redirects=False, verify=SSL_VERIFY)
|
||||||
|
redirect_url = result.next.url
|
||||||
|
oauth_token = redirect_url.split("=")[-1]
|
||||||
|
|
||||||
|
return oauth_token
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print("Failed to retrieve login form:", e)
|
print("Failed to retrieve login form:", e)
|
||||||
|
|
||||||
def retrieve_captcha_token():
|
def retrieve_access_token(oauth_token, session: requests.Session):
|
||||||
try:
|
url = "https://apidgp-gameplayer.games.dmm.com/v5/auth/accesstoken/issue"
|
||||||
captcha = reCaptchaV3("https://www.google.com/recaptcha/enterprise/anchor?ar=1&k=6LfZLQEVAAAAAC-8pKwFNuzVoJW4tfUCghBX_7ZE&co=aHR0cHM6Ly9hY2NvdW50cy5kbW0uY29tOjQ0Mw..&hl=ja&v=1Bq_oiMBd4XPUhKDwr0YL1Js&size=invisible")
|
result = session.post(url, json={"code":oauth_token}, verify=SSL_VERIFY)
|
||||||
return captcha
|
result.raise_for_status()
|
||||||
except Exception as e:
|
data = result.json()["data"]
|
||||||
print("Failed to solve captcha:", e)
|
return data["access_token"], data["expires_in_seconds"]
|
||||||
|
|
||||||
def retrieve_auth_keys(login, password, token, captcha, session : requests.Session):
|
|
||||||
try:
|
|
||||||
print("Logging in")
|
|
||||||
url = "https://accounts.dmm.com/service/login/password/authenticate"
|
|
||||||
data = f"token={token}&login_id={login}&password={password}&prompt=&device=games-player&recaptchaToken={captcha}"
|
|
||||||
headers = {"Content-Type": "application/x-www-form-urlencoded"}
|
|
||||||
result = session.post(url, data, headers=headers)
|
|
||||||
result.raise_for_status()
|
|
||||||
cookies = result.cookies.get_dict()
|
|
||||||
return cookies["login_secure_id"], cookies["login_session_id"]
|
|
||||||
except Exception as e:
|
|
||||||
print("Failed to log in:", e)
|
|
||||||
return None, None
|
|
||||||
|
|
||||||
def agree_to_game_terms(game_id, use_proxy):
|
def agree_to_game_terms(game_id, use_proxy):
|
||||||
try:
|
try:
|
||||||
|
@ -124,22 +137,25 @@ def agree_to_game_terms(game_id, use_proxy):
|
||||||
print("Failed to accept terms of use:", e)
|
print("Failed to accept terms of use:", e)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def retrieve_launch_params(game_id, game_type, mac_addr, hdd_serial, motherboard, login_secure, login_session, use_proxy = False, update_game = False):
|
def retrieve_launch_params(game_id, game_type, mac_addr, hdd_serial, motherboard, access_token, session: requests.Session, use_proxy = False, update_game = False):
|
||||||
try:
|
try:
|
||||||
print("Retrieving launch arguments")
|
print("Retrieving launch arguments")
|
||||||
data = {"product_id":game_id,"game_type":game_type,"game_os":"win","launch_type":"LIB","mac_address":mac_addr,"hdd_serial":hdd_serial,"motherboard":motherboard,"user_os":"win"}
|
data = {"product_id":game_id,"game_type":game_type,"game_os":"win","launch_type":"LIB","mac_address":mac_addr,"hdd_serial":hdd_serial,"motherboard":motherboard,"user_os":"win"}
|
||||||
headers = {"User-Agent": "DMMGamePlayer5-Win/5.3.12 Electron/32.1.0", "Client-App": "DMMGamePlayer5", "Client-version": "5.3.12", "Content-Type": "application/json"}
|
headers = {"User-Agent": "DMMGamePlayer5-Win/5.3.12 Electron/32.1.0",
|
||||||
cookies = {"login_secure_id":login_secure, "login_session_id":login_session}
|
"Client-App": "DMMGamePlayer5",
|
||||||
|
"Client-version": "5.3.12",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"actauth":access_token}
|
||||||
if update_game:
|
if update_game:
|
||||||
url = "https://katworks.sytes.net/proxy/launchAndUpdate" if use_proxy else "https://apidgp-gameplayer.games.dmm.com/v5/r2/launch/cl"
|
url = "https://katworks.sytes.net/proxy/launchAndUpdate" if use_proxy else "https://apidgp-gameplayer.games.dmm.com/v5/r2/launch/cl"
|
||||||
else:
|
else:
|
||||||
url = "https://katworks.sytes.net/proxy/launch" if use_proxy else "https://apidgp-gameplayer.games.dmm.com/v5/launch/cl"
|
url = "https://katworks.sytes.net/proxy/launch" if use_proxy else "https://apidgp-gameplayer.games.dmm.com/v5/launch/cl"
|
||||||
result = requests.post(url, cookies=cookies, headers=headers, json=data)
|
result = session.post(url, headers=headers, json=data, verify=SSL_VERIFY)
|
||||||
result.raise_for_status()
|
result.raise_for_status()
|
||||||
result_json = result.json()
|
result_json = result.json()
|
||||||
if result_json["result_code"] == 308:
|
if result_json["result_code"] == 308:
|
||||||
if agree_to_game_terms(game_id, use_proxy):
|
if agree_to_game_terms(game_id, use_proxy):
|
||||||
result = requests.post(url, cookies=cookies, headers=headers, json=data)
|
result = session.post(url, headers=headers, json=data, verify=SSL_VERIFY)
|
||||||
result.raise_for_status()
|
result.raise_for_status()
|
||||||
result_json = result.json()
|
result_json = result.json()
|
||||||
if result_json["result_code"] != 100:
|
if result_json["result_code"] != 100:
|
||||||
|
@ -185,28 +201,24 @@ def main(config):
|
||||||
saved_login = None
|
saved_login = None
|
||||||
|
|
||||||
if saved_login is not None:
|
if saved_login is not None:
|
||||||
login_secure, login_session = saved_login["login_secure"], saved_login["login_session"]
|
access_token = saved_login["access_token"]
|
||||||
print("Loaded login data from previous session")
|
print("Loaded token from previous session")
|
||||||
else:
|
else:
|
||||||
token = retrieve_login_token(session)
|
oauth_code = retrieve_oauth_code(login, password, session)
|
||||||
captcha = retrieve_captcha_token()
|
if oauth_code == None:
|
||||||
|
|
||||||
if token == None or captcha == None:
|
|
||||||
return
|
|
||||||
|
|
||||||
login_secure, login_session = retrieve_auth_keys(login, password, token, captcha, session)
|
|
||||||
if login_secure == None or login_session == None:
|
|
||||||
return
|
return
|
||||||
|
|
||||||
login_expiration = int((current_time + timedelta(days=364)).timestamp()) #expire in less than a year
|
access_token, expiration_seconds = retrieve_access_token(oauth_code, session)
|
||||||
config["saved_login"] = saved_login = {"login_secure" : login_secure, "login_session" : login_session, "expiration": login_expiration}
|
|
||||||
|
token_expiration = int((current_time + timedelta(seconds=expiration_seconds)).timestamp())
|
||||||
|
config["saved_login"] = saved_login = {"access_token" : access_token, "expiration": token_expiration}
|
||||||
del(config["update_game"])
|
del(config["update_game"])
|
||||||
save_config(game_id, config)
|
save_config(game_id, config)
|
||||||
|
|
||||||
if not use_proxy: input("Enable VPN now and press Enter")
|
if not use_proxy: input("Enable VPN now and press Enter")
|
||||||
|
|
||||||
#execute_args, file_list_url, file_access_params
|
#execute_args, file_list_url, file_access_params
|
||||||
launch_data : dict = retrieve_launch_params(game_id, game_type, mac_addr, hdd_serial, motherboard, login_secure, login_session, use_proxy, update_game)
|
launch_data : dict = retrieve_launch_params(game_id, game_type, mac_addr, hdd_serial, motherboard, access_token, session, use_proxy, update_game)
|
||||||
|
|
||||||
if launch_data == None:
|
if launch_data == None:
|
||||||
return
|
return
|
||||||
|
|
|
@ -6,10 +6,14 @@ import urllib.parse
|
||||||
from urllib.request import urlretrieve
|
from urllib.request import urlretrieve
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
# Set to False to allow packet sniffing/capture.
|
||||||
|
# Set separately for dmmBypass
|
||||||
|
SSL_VERIFY = True
|
||||||
|
|
||||||
def get_file_list(url):
|
def get_file_list(url):
|
||||||
url = "https://apidgp-gameplayer.games.dmm.com" + url
|
url = "https://apidgp-gameplayer.games.dmm.com" + url
|
||||||
print("Retrieving file list from " + url)
|
print("Retrieving file list from " + url)
|
||||||
result = requests.get(url)
|
result = requests.get(url, verify=SSL_VERIFY)
|
||||||
result.raise_for_status()
|
result.raise_for_status()
|
||||||
data = result.json()["data"]
|
data = result.json()["data"]
|
||||||
return data["domain"], data["file_list"]
|
return data["domain"], data["file_list"]
|
||||||
|
@ -71,7 +75,7 @@ def update_game(game_path, files_url, files_param):
|
||||||
file = files_to_download[index]
|
file = files_to_download[index]
|
||||||
url, path = file["url"], file["path"]
|
url, path = file["url"], file["path"]
|
||||||
|
|
||||||
response = requests.get(url, timeout=10, stream=True)
|
response = requests.get(url, timeout=10, stream=True, verify=SSL_VERIFY)
|
||||||
total_size = int(response.headers.get("content-length", 0))
|
total_size = int(response.headers.get("content-length", 0))
|
||||||
block_size = 1024 * 1024
|
block_size = 1024 * 1024
|
||||||
downloaded = 0
|
downloaded = 0
|
||||||
|
|
Loading…
Reference in New Issue