diff --git a/dislocker_client.py b/dislocker_client.py index d538189..aa493bd 100644 --- a/dislocker_client.py +++ b/dislocker_client.py @@ -12,7 +12,6 @@ import random import tkinter import threading import sys -import shutil import uuid import time import win32com.client @@ -31,6 +30,9 @@ sp_startupinfo.wShowWindow = subprocess.SW_HIDE resource_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "resource") config_dir_path = "./config/" client_config_path = config_dir_path + "client.json" +lang_dir_path = "./lang/" +lang_path = lang_dir_path + "lang_client.json" + if not os.path.isfile(client_config_path): if not os.path.isdir(config_dir_path): os.mkdir(config_dir_path) @@ -52,14 +54,22 @@ if not os.path.isfile(client_config_path): "pc_token": "", "hard_lock": False, "cover_image": "dislocker", - "language": "ja", - "language_file": "lang.json" + "language": "ja" } elif os.path.isfile(client_config_path): - with open(client_config_path, "r") as r: + with open(client_config_path, "r", encoding="utf-8") as r: client_config = json.load(r) +if os.path.isfile(lang_path): + with open(lang_path, "r", encoding="utf-8") as r: + lang_json = json.load(r) + lang = lang_json[client_config["language"]] +else: + print("言語ファイルが見つかりません。") + lang_not_found = tkinter.messagebox.showerror(title=f"{app_name} | 重大なエラー", message=f"言語ファイルが見つかりません。\n言語ファイルが削除されているか、ファイル名が間違っている可能性があります。\n{app_name} は起動できません。") + + def get_input_devices(): str_computer = "." obj_wmi_service = win32com.client.Dispatch("WbemScripting.SWbemLocator") @@ -129,13 +139,13 @@ def init(**kwargs): if "pc_number" in kwargs: client_config["pc_number"] = int(kwargs["pc_number"]) else: - tkinter.messagebox.showerror(title=f"{app_name} | 登録時にエラー", message=f"登録時にエラーが発生しました。\nPC番号が指定されていません。1個目の引数にPC番号、2個目の引数にワンタイムパスワードを指定して、もう一度お試しください。") + tkinter.messagebox.showerror(title=f"{app_name} | {lang["init"]["msgbox"]["not_found_pc_number"]["title"]}", message=f"{lang["init"]["msgbox"]["not_found_pc_number"]["details"]}") return 2 if "onetime" in kwargs: onetime = str(kwargs["onetime"]) else: - tkinter.messagebox.showerror(title=f"{app_name} | 登録時にエラー", message=f"登録時にエラーが発生しました。\nワンタイムパスワードが指定されていません。1個目の引数にPC番号、2個目の引数にワンタイムパスワードを指定して、もう一度お試しください。") + tkinter.messagebox.showerror(title=f"{app_name} | {lang["init"]["msgbox"]["not_found_onetime_password"]["title"]}", message=f"{lang["init"]["msgbox"]["not_found_onetime_password"]["details"]}") return 2 if "host_url" in kwargs: @@ -153,7 +163,7 @@ def init(**kwargs): responce = requests.post(register_url, json=register_json) if responce.status_code == 200: - print("PCの情報が登録されました。") + print(f"{lang["init"]["print"]["init_ok"]}") responce_json = responce.json() pc_token = str(responce_json["pc_token"]) master_password_hash = str(responce_json["master_password_hash"]) @@ -161,23 +171,23 @@ def init(**kwargs): client_config["pc_token"] = pc_token client_config["master_password_hash"] = master_password_hash - msgbox = tkinter.messagebox.showinfo(title=f"{app_name} | 初回起動を検出", message=f"初回起動のようです。\nマスターパスワードを記録しておいてください。\nBotが起動している場合は、管理者がDiscordから確認することもできます。\n\n{master_password}\n\n") + msgbox = tkinter.messagebox.showinfo(title=f"{app_name} | {lang["init"]["msgbox"]["init_ok"]["title"]}", message=f"{lang["init"]["msgbox"]["init_ok"]["details"]}\n\n{master_password}\n\n") client_config["initial"] = False - with open(client_config_path, "w") as w: - json.dump(client_config, w, indent=4) + with open(client_config_path, "w", encoding="utf-8") as w: + json.dump(client_config, w, indent=4, ensure_ascii=False) return 2 elif responce.status_code == 400: - msgbox = tkinter.messagebox.showerror(title=f"{app_name} | 登録時にエラー", message=f"登録時にエラーが発生しました。\n指定されたPC番号には既に登録されています。PCを置き換えたい場合は、Botから登録を解除してください。") + msgbox = tkinter.messagebox.showerror(title=f"{app_name} | {lang["init"]["msgbox"]["exist_pc_number"]["title"]}", message=f"{lang["init"]["msgbox"]["exist_pc_number"]["details"]}") return 2 elif responce.status_code == 401: - msgbox = tkinter.messagebox.showerror(title=f"{app_name} | 登録時にエラー", message=f"登録時にエラーが発生しました。\nワンタイムパスワードが間違っている可能性があります。") + msgbox = tkinter.messagebox.showerror(title=f"{app_name} | {lang["init"]["msgbox"]["wrong_onetime_password"]["title"]}", message=f"{lang["init"]["msgbox"]["wrong_onetime_password"]["details"]}") return 2 elif responce.status_code == 500: - msgbox = tkinter.messagebox.showerror(title=f"{app_name} | 登録時にエラー", message=f"登録時にエラーが発生しました。\nサーバーで内部エラーが発生しています。") + msgbox = tkinter.messagebox.showerror(title=f"{app_name} | {lang["init"]["msgbox"]["internal_error"]["title"]}", message=f"{lang["init"]["msgbox"]["internal_error"]["details"]}") return 2 else: return 0 @@ -202,9 +212,9 @@ class App(customtkinter.CTk): pass else: signout_session = subprocess.run('shutdown /l /f /t 3', startupinfo=sp_startupinfo, stdout=subprocess.PIPE, text=True) - error_msgbox = tkinter.messagebox.showerror(title=f"{app_name} | 初回処理のエラー", message=f"初回処理の実行にエラーが発生しました。\n自動的にサインアウトされます。") + error_msgbox = tkinter.messagebox.showerror(title=f"{app_name} | {lang["App"]["msgbox"]["init_error"]["title"]}", message=f"{lang["App"]["msgbox"]["init_error"]["details"]}") - self.title(f"{app_name} | ロック中") + self.title(f"{app_name} | {lang["App"]["title"]}") self.iconbitmap(default=resource_path + '\\icon\\dislocker.ico') self.frame = customtkinter.CTkFrame(self, corner_radius=0, fg_color='transparent') self.frame.grid(row=0, column=0, sticky='nsew') @@ -240,9 +250,9 @@ class App(customtkinter.CTk): def toast(self): success = Notification( - app_id='Dislocker', - title='ご協力ありがとうございます!', - msg='パスワード認証に成功しました。\n現在使われたパスワードは削除されます。', + app_id=f'{app_name}', + title=f'{lang["App"]["notification"]["success"]["title"]}', + msg=f'{lang["App"]["notification"]["success"]["details"]}', icon=resource_path + r'\success.png' ) success.set_audio(audio.Default, loop=False) @@ -256,9 +266,9 @@ class Lock(customtkinter.CTkToplevel): def __init__(self): super().__init__() if client_config["testing"] == True: - self.title(f'{app_name} | PC番号 {client_config["pc_number"]} | テストモード') + self.title(f'{app_name} | {lang["Lock"]["gui"]["pc_number"]} {client_config["pc_number"]} | {lang["Lock"]["gui"]["testing"]}') else: - self.title(f'{app_name} | PC番号 {client_config["pc_number"]} | ロックされています') + self.title(f'{app_name} | {lang["Lock"]["gui"]["pc_number"]} {client_config["pc_number"]} | {lang["Lock"]["gui"]["locked"]}') self.iconbitmap(default=resource_path + '\\icon\\dislocker.ico') self.window_width = 760 @@ -283,7 +293,7 @@ class Lock(customtkinter.CTkToplevel): self.textbox_font = customtkinter.CTkFont(family="meiryo", size=14) self.button_font = customtkinter.CTkFont(family="meiryo", size=14) - self.cover_img = customtkinter.CTkImage(light_image=Image.open(f'{resource_path}\\cover\\{client_config["cover_image"]}_light.png'), dark_image=Image.open(f'{resource_path}\\cover\\{client_config["cover_image"]}_dark.png'), size=(160, 320)) + self.cover_img = customtkinter.CTkImage(light_image=Image.open(f'{resource_path}\\cover\\{client_config["cover_image"]}\\light.png'), dark_image=Image.open(f'{resource_path}\\cover\\{client_config["cover_image"]}\\dark.png'), size=(160, 320)) self.grid_columnconfigure(0, weight=1) self.grid_columnconfigure(1, weight=6) @@ -297,33 +307,30 @@ class Lock(customtkinter.CTkToplevel): self.msg_title_frame = customtkinter.CTkFrame(self, corner_radius=0, fg_color='transparent') self.msg_title_frame.grid(row=0, column=1, padx=10, pady=10, sticky="nsew") - #self.icon_title_1 = customtkinter.CTkLabel(self.msg_title_frame, text='😎', font=self.emoji_font, justify="left") - #self.icon_title_1.grid(row=0, column=0, padx=10, sticky="w") - - self.msg_title_1 = customtkinter.CTkLabel(self.msg_title_frame, text=f'ちょっと待って!! ', font=self.title_font, justify="left") + self.msg_title_1 = customtkinter.CTkLabel(self.msg_title_frame, text=f'{lang["Lock"]["gui"]["msg_title_1"]}', font=self.title_font, justify="left") self.msg_title_1.grid(row=0, column=0, padx=10, sticky="we") - self.pc_number_title_1 = customtkinter.CTkLabel(self.msg_title_frame, text=f'PC番号 | {client_config["pc_number"]}', font=self.title_font, justify="right") + self.pc_number_title_1 = customtkinter.CTkLabel(self.msg_title_frame, text=f'{lang["Lock"]["gui"]["pc_number_title_1"]} | {client_config["pc_number"]}', font=self.title_font, justify="right") self.pc_number_title_1.grid(row=0, column=1, padx=10, sticky="e") - self.msg_title_2 = customtkinter.CTkLabel(self.msg_title_frame, text="本当にあなたですか?", font=self.title_small_font, justify="left") + self.msg_title_2 = customtkinter.CTkLabel(self.msg_title_frame, text=f"{lang["Lock"]["gui"]["msg_title_2"]}", font=self.title_small_font, justify="left") self.msg_title_2.grid(row=1, column=0, padx=10, columnspan=2, sticky="w") self.msg_subtitle_frame = customtkinter.CTkFrame(self, corner_radius=0, fg_color='transparent') self.msg_subtitle_frame.grid(row=1, column=1, padx=10, pady=0, sticky="nsew") self.msg_subtitle_frame.grid_columnconfigure(0, weight=1) - self.msg_subtitle_1 = customtkinter.CTkLabel(self.msg_subtitle_frame, text='サインインするには、Discordを開き、Dislockerから送信された\nパスワードを入力してください。', font=self.general_font, justify="left") + self.msg_subtitle_1 = customtkinter.CTkLabel(self.msg_subtitle_frame, text=f'{lang["Lock"]["gui"]["msg_subtitle_1"]}', font=self.general_font, justify="left") self.msg_subtitle_1.grid(row=0, column=0, padx=10, sticky="w") - self.msg_subtitle_2 = customtkinter.CTkLabel(self.msg_subtitle_frame, text='※ パスワードの有効期限は発行から5分間です。期限が切れた場合は、もう一度発行してください。', font=self.general_small_font, justify="left") + self.msg_subtitle_2 = customtkinter.CTkLabel(self.msg_subtitle_frame, text=f'{lang["Lock"]["gui"]["msg_subtitle_2"]}', font=self.general_small_font, justify="left") self.msg_subtitle_2.grid(row=1, column=0, padx=10, sticky="w") self.input_frame = customtkinter.CTkFrame(self, corner_radius=0, fg_color='transparent') self.input_frame.grid(row=2, column=1, padx=10, pady=0, sticky="nsew") self.input_frame.columnconfigure(0, weight=1) - self.password_entry = customtkinter.CTkEntry(self.input_frame, placeholder_text='パスワード', show='*', font=self.textbox_font) + self.password_entry = customtkinter.CTkEntry(self.input_frame, placeholder_text=f'{lang["Lock"]["gui"]["password_entry"]}', show='*', font=self.textbox_font) self.password_entry.grid(row=0, column=0, padx=10, sticky="ew") self.password_entry.bind("", self.auth_start_ev) @@ -333,13 +340,13 @@ class Lock(customtkinter.CTkToplevel): self.button_frame.columnconfigure(1, weight=1) self.button_frame.columnconfigure(2, weight=1) - self.signin_button = customtkinter.CTkButton(self.button_frame, text='サインイン', command=self.auth_start, font=self.button_font) + self.signin_button = customtkinter.CTkButton(self.button_frame, text=f'{lang["Lock"]["gui"]["signin_button"]}', command=self.auth_start, font=self.button_font) self.signin_button.grid(row=0, column=2, padx=10, sticky="e") - self.signout_button = customtkinter.CTkButton(self.button_frame, text='サインアウト', command=self.signout, font=self.button_font) + self.signout_button = customtkinter.CTkButton(self.button_frame, text=f'{lang["Lock"]["gui"]["signout_button"]}', command=self.signout, font=self.button_font) self.signout_button.grid(row=0, column=1, padx=10, sticky="e") - self.help_button = customtkinter.CTkButton(self.button_frame, text='ヘルプ', command=self.help_dummy, font=self.button_font) + self.help_button = customtkinter.CTkButton(self.button_frame, text=f'{lang["Lock"]["gui"]["help_button"]}', command=self.help_dummy, font=self.button_font) self.help_button.grid(row=0, column=0, padx=10, sticky="w") self.keyboard_listener_thread = threading.Thread(target=self.keyboard_listener) @@ -410,20 +417,20 @@ class Lock(customtkinter.CTkToplevel): devices = [] if len(password) == 10: - print("マスターパスワードで認証を試行します。") + print(f'{lang["Lock"]["auth"]["print"]["try_master_password"]}') master_password_hash = self.hash_genarate(str(self.password_entry.get())) if client_config["master_password_hash"] == master_password_hash: - print("マスターパスワードで認証しました。") + print(f'{lang["Lock"]["auth"]["print"]["success_master_password"]}') self.exit() else: - print("マスターパスワードで認証できませんでした。") + print(f'{lang["Lock"]["auth"]["print"]["error_master_password"]}') self.withdraw() - msgbox = tkinter.messagebox.showinfo(title=f"{app_name} | 誤ったパスワード", message=f"パスワードが間違っています!") - self.msg_subtitle_1.configure(text='パスワードが間違っています! ') + msgbox = tkinter.messagebox.showinfo(title=f"{app_name} | {lang["Lock"]["auth"]["msgbox"]["wrong_password"]["title"]}", message=f"{lang["Lock"]["auth"]["msgbox"]["wrong_password"]["details"]}") + self.msg_subtitle_1.configure(text=f'{lang["Lock"]["auth"]["configure"]["wrong_password"]}') self.button_enable() self.deiconify() - print("認証サーバーにアクセスします。") + print(f'{lang["Lock"]["auth"]["print"]["access_auth_server"]}') auth_url = client_config["auth_host_url"] + "/verify" auth_json = { "pc_number": int(client_config["pc_number"]), @@ -435,33 +442,33 @@ class Lock(customtkinter.CTkToplevel): try: responce = requests.post(auth_url, json=auth_json) if responce.status_code == 200: - print("認証サーバー経由で認証しました。") + print(f'{lang["Lock"]["auth"]["print"]["success_auth_server"]}') self.exit() elif responce.status_code == 401: - print("認証サーバー経由での認証に失敗しました。") + print(f'{lang["Lock"]["auth"]["print"]["error_wrong_password"]}') self.withdraw() - msgbox = tkinter.messagebox.showinfo(title=f"{app_name} | 誤ったパスワード", message=f"パスワードが間違っています!") - self.msg_subtitle_1.configure(text='パスワードが間違っています! ') + msgbox = tkinter.messagebox.showinfo(title=f"{app_name} | {lang["Lock"]["auth"]["msgbox"]["wrong_password"]["title"]}", message=f"{lang["Lock"]["auth"]["msgbox"]["wrong_password"]["details"]}") + self.msg_subtitle_1.configure(text=f'{lang["Lock"]["auth"]["configure"]["wrong_password"]}') self.button_enable() self.deiconify() elif responce.status_code == 500: - print("内部エラーにより認証に失敗しました。") + print(f'{lang["Lock"]["auth"]["print"]["error_internal_server"]}') self.withdraw() - msgbox = tkinter.messagebox.showinfo(title=f"{app_name} | 内部エラー", message=f"サーバーの内部エラーにより認証に失敗しました。") - self.msg_subtitle_1.configure(text='内部エラーにより認証に失敗しました。 ') + msgbox = tkinter.messagebox.showinfo(title=f"{app_name} | {lang["Lock"]["auth"]["msgbox"]["internal_error"]["title"]}", message=f"{lang["Lock"]["auth"]["msgbox"]["internal_error"]["details"]}") + self.msg_subtitle_1.configure(text=f'{lang["Lock"]["auth"]["configure"]["internal_error"]}') self.button_enable() self.deiconify() except: - print("認証サーバーにアクセスできません。マスターパスワードで認証を試行します。") + print(f'{lang["Lock"]["auth"]["print"]["cant_access_auth_server"]}') master_password_hash = self.hash_genarate(str(self.password_entry.get())) if client_config["master_password_hash"] == master_password_hash: - print("マスターパスワードで認証しました。") + print(f'{lang["Lock"]["auth"]["print"]["success_master_password"]}') self.exit() else: - print("マスターパスワードで認証できませんでした。") + print(f'{lang["Lock"]["auth"]["print"]["error_master_password"]}') self.withdraw() - msgbox = tkinter.messagebox.showinfo(title=f"{app_name} | ネットワークエラー", message=f"認証サーバーにアクセスできませんでした。\n続行するには、マスターパスワードを入力してください。") - self.msg_subtitle_1.configure(text='ネットワークエラーが発生しています。\n続行するには、マスターパスワードを入力して下さい。 ') + msgbox = tkinter.messagebox.showinfo(title=f"{app_name} | {lang["Lock"]["auth"]["msgbox"]["cant_access_auth_server"]["title"]}", message=f"{lang["Lock"]["auth"]["msgbox"]["cant_access_auth_server"]["details"]}") + self.msg_subtitle_1.configure(text=f'{lang["Lock"]["auth"]["configure"]["cant_access_auth_server"]}') self.button_enable() self.deiconify() @@ -477,7 +484,7 @@ class Lock(customtkinter.CTkToplevel): def help_dummy(self): self.withdraw() - msgbox = tkinter.messagebox.showinfo(title=f"{app_name} | 未実装", message=f"ヘルプページは製作途中です。\nDiscordサーバーの指示に従って、認証を進めてください。") + msgbox = tkinter.messagebox.showinfo(title=f"{app_name} | {lang["Lock"]["auth"]["msgbox"]["help"]["title"]}", message=f"{lang["Lock"]["auth"]["msgbox"]["help"]["details"]}") self.deiconify() def wakeup_shutdown_background(self): @@ -514,106 +521,10 @@ class Help(customtkinter.CTkToplevel): self.destroy() -class Stop(): - def __init__(self) -> None: - pass - - def run(self): - stop_thread = threading.Thread(target=self.stop) - stop_thread.run() - - def delete_appdata(self, **kwargs): - process_name = kwargs["process_name"] - dir_path = kwargs["dir_path"] - - if not os.path.exists(dir_path): - print(f"エラー: 指定されたディレクトリ {dir_path} が存在しません。") - return 1 - - i = 0 - i_max = 10 - result = 1 - while i != i_max: - i += 1 - try: - # プロセスの終了 - subprocess.run(f'taskkill /f /t /im {process_name}', startupinfo=sp_startupinfo, stdout=subprocess.PIPE, text=True) - print(f"{process_name} を終了しました。") - time.sleep(0.1) - # ディレクトリの削除 - shutil.rmtree(dir_path) - if os.path.isdir(dir_path): - pass - else: - print(f"{dir_path} を削除しました。") - result = 0 - i = i_max - - except subprocess.CalledProcessError as e: - print(f"プロセス終了エラー: {e}") - - except PermissionError as e: - print(f"権限エラー: {e}") - - except Exception as e: - print("エラーが発生しました。\nエラー内容:") - print(f"エラータイプ: {e.__class__.__name__}") - print(f"エラー引数: {e.args}") - print(f"エラーメッセージ: {str(e)}") - - return result - - - def shutdown(self): - shutdown_command = subprocess.run('shutdown /s /f /t 0', startupinfo=sp_startupinfo, stdout=subprocess.PIPE, text=True) - - def stop(self): - print("停止処理を実行。") - if client_config["eraser"] == True: - appdata_local = os.path.expandvars("%LOCALAPPDATA%") - appdata_roaming = os.path.expandvars("%APPDATA%") - epic_del = self.delete_appdata(process_name="EpicGamesLauncher.exe", dir_path=f"{appdata_local}\\EpicGamesLauncher\\Saved") - chrome_del = self.delete_appdata(process_name="chrome.exe", dir_path=f"{appdata_local}\\Google\\Chrome\\User Data") - discord_del = self.delete_appdata(process_name="discord.exe", dir_path=f"{appdata_roaming}\\discord") - steam_del = self.delete_appdata(process_name="steam.exe", dir_path=f"{appdata_local}\\Steam") - ea_del = self.delete_appdata(process_name="EADesktop.exe", dir_path=f"{appdata_local}\\Electronic Arts") - riot_del = self.delete_appdata(process_name="RiotClientServices.exe", dir_path=f"{appdata_local}\\Riot Games\\Riot Client") - else: - print("削除処理をスキップ。") - stop_url = client_config["auth_host_url"] + "/stop" - stop_json = { - "pc_number": int(client_config["pc_number"]), - "pc_uuid": str(client_config["pc_uuid"]), - "pc_token": str(client_config["pc_token"]) - } - try: - responce = requests.post(stop_url, json=stop_json) - if responce.status_code == 200: - print("停止処理は成功しました。") - elif responce.status_code == 401: - print("認証に失敗しました。") - else: - print("内部エラーにより停止処理に失敗しました。") - except: - print("ネットワークエラーにより停止処理に失敗しました。") - finally: - self.shutdown() - - if __name__ == '__main__': args = sys.argv if len(args) >= 2: - if args[1] == "stop": - init_result = init() - if init_result == 1: - print("多重起動を検出。") - elif init_result == 2: - pass - else: - stop = Stop() - stop.run() - - elif args[1] == "setup": + if args[1] == "setup": if len(args) == 4: init_result = init(pc_number=args[2], onetime=args[3]) elif len(args) == 5: