From 42d563f35b3a6487b347c19f25c24f6b868bc01d Mon Sep 17 00:00:00 2001 From: lanbinshijie Date: Sun, 7 Jan 2024 00:47:56 +0800 Subject: [PATCH 1/8] =?UTF-8?q?docs:=20=E6=96=B0=E5=A2=9E=E5=9B=BE?= =?UTF-8?q?=E7=89=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index b22d7b3..3ffb160 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,12 @@ Ice Shell(简称IShell,中文名“冰壳”),是一个Python编写的 **2024,回归更新咕咕咕!** +![Run Shell](./docs/img/runShell.png) + +(老版图片) + + + ## IShell设计初衷 往往我们在用Python完成某个小功能时,我们都会直接新建单个Python文件,写完之后就放在一个不知名的小角落,然后使用的时候直接双击运行。 From 5ac25d37bf7529c68465ed85feb11b8df9ceb6c4 Mon Sep 17 00:00:00 2001 From: lanbinshijie Date: Sun, 7 Jan 2024 00:59:40 +0800 Subject: [PATCH 2/8] chore: update GIN --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index d9d181c..858ec90 100644 --- a/.gitignore +++ b/.gitignore @@ -130,3 +130,5 @@ dmypy.json .vscode .vscode/* + +alias.user.conf \ No newline at end of file From 2aeac0b4dcee3f17448f1f8b95ec72b296d1ec3e Mon Sep 17 00:00:00 2001 From: lanbinshijie Date: Sun, 7 Jan 2024 00:59:58 +0800 Subject: [PATCH 3/8] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E4=BA=86?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E8=87=AA=E4=BF=9D=E5=AD=98=E5=88=AB=E5=90=8D?= =?UTF-8?q?=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- models/alias.py | 33 ++++++++++++++++++++++----------- tools/Phraser.py | 20 ++++++++++++++------ 2 files changed, 36 insertions(+), 17 deletions(-) diff --git a/models/alias.py b/models/alias.py index 00abdcd..4a75877 100644 --- a/models/alias.py +++ b/models/alias.py @@ -13,27 +13,38 @@ class Aliaser: """ This class manages command aliases stored in a configuration file. """ - def __init__(self, path=ProgramInfo.basedir + "/tools/alias.conf"): + def __init__(self, path=ProgramInfo.basedir + "/tools/alias.conf", userPath=ProgramInfo.basedir + "/tools/alias.user.conf"): self.path = path + self.userPath = userPath self.alias = alias(path) - def _update_file(self, config): + def _update_file(self, config, user=True): """Writes the updated configuration to the file.""" - with open(self.path, "w") as f: - for alias, command in config.items(): - f.write(f"{alias}={command}\n") + if user: + with open(self.userPath, "w") as f: + for alias, command in config.items(): + f.write(f"{alias}={command}\n") + else: + with open(self.path, "w") as f: + for alias, command in config.items(): + f.write(f"{alias}={command}\n") - def add(self, alias, command): + def add(self, alias, command, user=True): """Adds a new alias.""" - if self.alias.exist(alias): + if self.alias.exsist(alias): print(f"Alias {alias} already exists!") return - with open(self.path, "a") as f: - f.write(f"\n{alias}={command}") + + if user: + with open(self.userPath, "a") as f: + f.write(f"\n{alias}={command}") + else: + with open(self.path, "a") as f: + f.write(f"\n{alias}={command}") def set(self, alias, command): """Sets an existing alias to a new command.""" - if not self.alias.exist(alias): + if not self.alias.exsist(alias): print(f"Alias {alias} does not exist!") return config = self.alias.getAll() @@ -42,7 +53,7 @@ def set(self, alias, command): def delete(self, alias): """Deletes an existing alias.""" - if not self.alias.exist(alias): + if not self.alias.exsist(alias): print(f"Alias {alias} does not exist!") return config = self.alias.getAll() diff --git a/tools/Phraser.py b/tools/Phraser.py index 4985705..4ec3f7e 100644 --- a/tools/Phraser.py +++ b/tools/Phraser.py @@ -19,9 +19,13 @@ def paraphraser(prompt="[IShell] %u> "): return prompt class alias: - def __init__(self, path=ProgramInfo.basedir + "/tools/alias.conf"): - with open(path, "r") as f: - conf = f.read() + def __init__(self, path=ProgramInfo.basedir + "/tools/alias.conf", userPath=ProgramInfo.basedir + "/tools/alias.user.conf", user=True): + if user: + with open(userPath, "r") as f: + conf = f.read() + else: + with open(path, "r") as f: + conf = f.read() conf = conf.split("\n") self.conf_dict = {} @@ -44,9 +48,13 @@ def getAll(self): self.reRead() return self.conf_dict - def reRead(self, path="../tools/alias.conf"): - with open(path, "r") as f: - conf = f.read() + def reRead(self, path="../tools/alias.conf", userPath="../tools/alias.user.conf", user=True): + if user: + with open(userPath, "r") as f: + conf = f.read() + else: + with open(path, "r") as f: + conf = f.read() conf = conf.split("\n") self.conf_dict = {} From a307aed9beee94aa1e07accf864e6e3cb94f571f Mon Sep 17 00:00:00 2001 From: lanbinshijie Date: Sun, 7 Jan 2024 18:45:11 +0800 Subject: [PATCH 4/8] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0StarHistory?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 3ffb160..7dff201 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,7 @@ IShell本质上作为一个模块化Shell,装载了一些小工具。 - 报错易寻找具体位置 ...... + # 使用方法 1. 下载最新版Release [点我前往Release](https://github.com/lanbinshijie/IceShell/releases) @@ -127,6 +128,12 @@ Demo输出 ![Demo Screen](./docs/img/bashDemo.png) +## Star History + +[![Star History Chart](https://api.star-history.com/svg?repos=lanbinshijie/iceshell&type=Date)](https://star-history.com/#lanbinshijie/iceshell&Date) + + + # 参与开发 您可以联系我的 @@ -134,6 +141,7 @@ Demo输出 或者直接提交issue + ## 近期任务 - [X] 一键检测依赖并询问是否安装 From 0e519803a90869ed2a785f1fcc5bc8c1c2c38d2c Mon Sep 17 00:00:00 2001 From: lanbinshijie Date: Sun, 7 Jan 2024 18:45:40 +0800 Subject: [PATCH 5/8] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.py | 52 +++++++++++++++++- tools/Configure.py | 124 +++++++++++++++++++++++++++++++++++++++++++ tools/configure.conf | 4 ++ 3 files changed, 179 insertions(+), 1 deletion(-) create mode 100644 tools/Configure.py create mode 100644 tools/configure.conf diff --git a/main.py b/main.py index bf4008b..5243636 100644 --- a/main.py +++ b/main.py @@ -14,9 +14,14 @@ from tools.Phraser import PS1 from tools.Phraser import alias from misc.Info import StartAction +from tools.Configure import * # from models.bash import Ish + + ALIAS = alias() +PS1O = PS1() +CONFIGURATION = Configuration() # ish = Ish() def ExecuteModel(args, moduleName): @@ -38,13 +43,58 @@ def ExecuteModel(args, moduleName): # 因为 checkModel 会给出提示信息,所以就不用给出了 ... +def SafetyMode(lock): + if int(lock): + print(Colors.RED + Logo.div_line_n_m + Colors.END) + print(Colors.RED + "Safety Mode is on." + Colors.END) + print(Colors.RED + "Please input your password to continue." + Colors.END) + print(Colors.RED + Logo.div_line_n_m + Colors.END + "\n") + + while True: + try: + userName = input("Username: >> ") + password = input("Password: >> ") + passwordHashed = Hash(password) + if userName == CONFIGURATION.userName and passwordHashed == str(CONFIGURATION.passwordHashed).split("%%")[0]: + print() + print(Colors.GREEN + Logo.div_line_n_m + Colors.END) + print(Colors.GREEN + "Welcome back, " + userName + "!" + Colors.END) + print(Colors.GREEN + Logo.div_line_n_m + Colors.END + "\n") + break + else: + print() + print(Colors.RED + Logo.div_line_n_m + Colors.END) + print(Colors.RED + "Wrong username or password!" + Colors.END) + print(Colors.RED + Logo.div_line_n_m + Colors.END + "\n") + continue + except KeyboardInterrupt: + print("\nBye~") + exit(0) + def IceShell(): extra = "" commandN = input(Colors.RED + extra + PS1.paraphraser() + Colors.END) command = commandN.split(" ") + SECLEVEL = 0 if command[0] == "q": print("Bye~") exit(0) + elif CONFIGURATION.ifexist(str(commandN.split("=")[0]).strip()[1:]) and commandN.startswith("$"): + conf = commandN.split("=") + conf = [str(item).strip() for item in conf] + conf[0] = conf[0][1:] + sec = CONFIGURATION.get(conf[0]).split("%%") # 安全等级,如果越大,需要的等级越高 + sec = int(sec[1]) if len(sec) > 1 else 0 + if sec > SECLEVEL: + Error.printError(30001) + print() + return + if len(conf) == 2: + CONFIGURATION.set_value(conf[0], conf[1]) + CONFIGURATION.save() + print(Colors.GREEN + "Configuration saved." + Colors.END) + elif len(conf) == 1: + print(CONFIGURATION.get(conf[0])) elif command[0] in ProgramInfo.registered_modules or "*" in ProgramInfo.registered_modules: ExecuteModel(" ".join(command[1:]), command[0]) else: @@ -62,7 +112,7 @@ def IceShell(): if os.path.exists(mfol_stp): ExecuteModel(mdls_stp, "bash") print(Colors.BLUE + Logo.div_line_n_m + Colors.END + "\n") - + pass_ = SafetyMode(CONFIGURATION.lock) while True: try: IceShell() diff --git a/tools/Configure.py b/tools/Configure.py new file mode 100644 index 0000000..f6c75ab --- /dev/null +++ b/tools/Configure.py @@ -0,0 +1,124 @@ +from misc.Info import ProgramInfo +import hashlib + +def Hash(password: str, salt: str = "IceShell"): + return hashlib.sha256((password + salt).encode("utf-8")).hexdigest() + +class ConfigurationData: + def __init__(self, userName="root", passwordHashed=Hash("root"), config={}): + self.userName = userName + self.passwordHashed = passwordHashed + + self.variables = [] + + self.config = config + self.phrase() + if self.config is not {}: + self.loadConfig(config) + self.updateVarList() + + def phrase(self): + # 设置config内容 + self.config = { + "userName": self.userName, # 设置用户名 + "passwordHashed": self.passwordHashed, # 设置密码 + "lock": "0", + "variables": self.variables, + } + self.updateVarList() + + def updateVarList(self): + # self.variables设置为config的key + self.variables = [] + for key in self.config.keys(): + self.variables.append(key) + self.config["variables"] = self.variables + + + def loadConfig(self, config): + # 传入的config是configuration读取的key=value + for key, value in config.items(): + self.config[key] = value + return self.config + + def setKeyValue(self, key: str, value): + # 设置key的值为value + self.config[key] = value + + def __call__(self): + return self.config + + def update_internal_attributes(self, key, value): + if hasattr(self, key): + setattr(self, key, value) + +class Configuration: + def __init__(self, configPath=ProgramInfo.basedir + "/tools/configure.conf", configurationData: ConfigurationData | None = None): + self.__dict__['configPath'] = configPath + if configurationData is None: + self.readConfig(configPath) + else: + self.__dict__['config'] = configurationData + self.save() + + def readConfig(self, configPath): + # 数据格式:key=value + # 读取配置文件,然后创建一个ConfigurationData数据,尝试填入数据 + try: + with open(configPath, "r", encoding="utf-8") as f: + config = f.read().split("\n") + # 删除所有config为空或者没有等号在中间的行 + config = [line for line in config if "=" in line] + + config = { + key: value for key, value in [line.split("=") for line in config] + } + self.config = ConfigurationData(config=config) + except FileNotFoundError as e: + print(e) + self.config = ConfigurationData() + except Exception as e: + print(e) + self.config = ConfigurationData() + + + def get(self, name): + return self.config()[name] + + def __call__(self): + return self.config() + + def __getattr__(self, name): + if 'config' in self.__dict__: + return self.__dict__['config']()[name] + else: + raise AttributeError(f"No such attribute: {name}") + + def __setattr__(self, name, value): + if name in ['config', 'configPath'] or '_config' not in self.__dict__: + self.__dict__[name] = value + elif name in self.__dict__['config'](): + self.__dict__['config'].setKeyValue(name, value) + self.__dict__['config'].update_internal_attributes(name, value) + else: + object.__setattr__(self, name, value) + def save(self): + with open(self.configPath, "w", encoding="utf-8") as f: + for key, value in self.config().items(): + value = str(value) + f.write(key + "=" + value + "\n") + f.flush() + + def ifexist(self, configKey): + if configKey in self.config(): + return True + else: + return False + + def set_value(self, key, value): + if key in self.config(): + self.config.setKeyValue(key, value) + self.config.update_internal_attributes(key, value) + else: + raise KeyError(f"No such configuration key: {key}") + diff --git a/tools/configure.conf b/tools/configure.conf new file mode 100644 index 0000000..69cf0a0 --- /dev/null +++ b/tools/configure.conf @@ -0,0 +1,4 @@ +userName=Lanbin +passwordHashed=8ac8c452cf1deb9785b4d8a3a778f5b8d80a096f8acc9968b4e54234881a4463%%1 +lock=0 +variables=['userName', 'passwordHashed', 'lock', 'variables'] From 8b43f0708567e30b5658c0e676f3e2a0f25a1c41 Mon Sep 17 00:00:00 2001 From: lanbinshijie Date: Sun, 7 Jan 2024 18:45:58 +0800 Subject: [PATCH 6/8] =?UTF-8?q?chore:=20=E6=8A=A5=E9=94=99=E5=92=8C?= =?UTF-8?q?=E6=A0=87=E5=87=86=E5=BA=93=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- misc/Error.py | 6 ++++++ misc/Info.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/misc/Error.py b/misc/Error.py index f1660b4..11dc54c 100644 --- a/misc/Error.py +++ b/misc/Error.py @@ -15,6 +15,12 @@ class Error: "title": "Deleting error!", "solve": "Please check pip\'s environment" }, + 30001: { + "typer": "error", + "model": "SECURITY", + "title": "PERMISSION DENIED!", + "solve": "UPGRADE YOUR PERMISSION" + }, } def printError(code: int): err = Error.error_list[code] diff --git a/misc/Info.py b/misc/Info.py index ff2334a..17aef83 100644 --- a/misc/Info.py +++ b/misc/Info.py @@ -10,7 +10,7 @@ class ProgramInfo: # Program Version version = "v1.0.0-alphav1.2.1" author = "Lanbin" - using_libs = ["os", "sys"] + using_libs = ["os", "sys", "re"] models_path = r"./models/" registered_modules = ["print", "downlib", "dellib", "scan", "models", "shell", "alias", "bash", "*"] debug_mode = True From 45c0037d1c11868f1cbeaf5bc4fa9c1744dc6af3 Mon Sep 17 00:00:00 2001 From: lanbinshijie Date: Tue, 30 Jan 2024 22:03:05 +0800 Subject: [PATCH 7/8] fix: Fix command execution issue in main.py #15 --- main.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/main.py b/main.py index 5243636..223780d 100644 --- a/main.py +++ b/main.py @@ -28,14 +28,14 @@ def ExecuteModel(args, moduleName): if SelfCheck.CheckModel(moduleName): os.chdir(rf"{ProgramInfo.basedir}/models") if os.path.exists(f"{moduleName}.py"): - command = sys.executable + f" ./{moduleName}.py " + args + command = f"\"{sys.executable}\"" + f" ./{moduleName}.py " + args elif os.path.exists(f"./{moduleName}/main.py"): os.chdir(rf"./{moduleName}") - command = sys.executable + f" ./main.py " + args + command = f"\"{sys.executable}\"" + f" ./main.py " + args else: if ALIAS.exsist(moduleName): command = ALIAS.get(moduleName) - command = sys.executable + f" ./{command}.py " + args + command = f"\"{sys.executable}\"" + f" ./{command}.py " + args os.system(command) os.chdir(rf"{ProgramInfo.basedir}") # elif moduleName in From 41469e1fdcc0605223e7d0244b81ca5fe3676c38 Mon Sep 17 00:00:00 2001 From: lanbinshijie Date: Tue, 30 Jan 2024 22:05:01 +0800 Subject: [PATCH 8/8] fix: Module not found error --- tools/Phraser.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tools/Phraser.py b/tools/Phraser.py index 4ec3f7e..6d18854 100644 --- a/tools/Phraser.py +++ b/tools/Phraser.py @@ -21,8 +21,12 @@ def paraphraser(prompt="[IShell] %u> "): class alias: def __init__(self, path=ProgramInfo.basedir + "/tools/alias.conf", userPath=ProgramInfo.basedir + "/tools/alias.user.conf", user=True): if user: - with open(userPath, "r") as f: - conf = f.read() + try: + with open(userPath, "r") as f: + conf = f.read() + except: + with open(path, "r") as f: + conf = f.read() else: with open(path, "r") as f: conf = f.read()