You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
sqlmap/src/sqlmap-master/lib/core/update.py

195 lines
8.9 KiB

#!/usr/bin/env python
"""
Copyright (c) 2006-2024 sqlmap developers (https://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
# 导入所需的Python标准库
import glob # 用于文件路径模式匹配
import os # 提供与操作系统交互的功能
import re # 正则表达式模块
import shutil # 提供高级文件操作功能
import subprocess # 用于创建子进程
import time # 时间相关功能
import zipfile # ZIP文件操作
# 从自定义库中导入所需函数
from lib.core.common import dataToStdout # 输出数据到标准输出
from lib.core.common import extractRegexResult # 提取正则表达式结果
from lib.core.common import getLatestRevision # 获取最新版本号
from lib.core.common import getSafeExString # 安全地获取异常字符串
from lib.core.common import openFile # 打开文件
from lib.core.common import pollProcess # 轮询进程
from lib.core.common import readInput # 读取用户输入
from lib.core.convert import getText # 文本转换
from lib.core.data import conf # 配置数据
from lib.core.data import logger # 日志记录器
from lib.core.data import paths # 路径信息
from lib.core.revision import getRevisionNumber # 获取版本号
from lib.core.settings import GIT_REPOSITORY # Git仓库地址
from lib.core.settings import IS_WIN # 是否为Windows系统
from lib.core.settings import VERSION # 版本信息
from lib.core.settings import TYPE # 安装类型
from lib.core.settings import ZIPBALL_PAGE # ZIP包下载页面
from thirdparty.six.moves import urllib as _urllib # URL处理
def update():
"""
更新sqlmap的主函数
"""
# 如果未启用更新全部选项,直接返回
if not conf.updateAll:
return
success = False # 更新是否成功的标志
# 如果是通过pip安装的
if TYPE == "pip":
infoMsg = "updating sqlmap to the latest stable version from the "
infoMsg += "PyPI repository"
logger.info(infoMsg) # 记录更新信息
debugMsg = "sqlmap will try to update itself using 'pip' command"
logger.debug(debugMsg) # 记录调试信息
dataToStdout("\r[%s] [INFO] update in progress" % time.strftime("%X")) # 显示更新进度
output = ""
try:
# 执行pip更新命令
process = subprocess.Popen("pip install -U sqlmap", shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=paths.SQLMAP_ROOT_PATH)
pollProcess(process, True) # 轮询进程
output, _ = process.communicate() # 获取输出
success = not process.returncode # 检查返回码
except Exception as ex:
success = False
output = getSafeExString(ex)
finally:
output = getText(output)
# 根据更新结果输出相应信息
if success:
logger.info("%s the latest revision '%s'" % ("already at" if "already up-to-date" in output else "updated to", extractRegexResult(r"\binstalled sqlmap-(?P<result>\d+\.\d+\.\d+)", output) or extractRegexResult(r"\((?P<result>\d+\.\d+\.\d+)\)", output)))
else:
logger.error("update could not be completed ('%s')" % re.sub(r"[^a-z0-9:/\\]+", " ", output).strip())
# 如果不是Git仓库
elif not os.path.exists(os.path.join(paths.SQLMAP_ROOT_PATH, ".git")):
warnMsg = "not a git repository. It is recommended to clone the 'sqlmapproject/sqlmap' repository "
warnMsg += "from GitHub (e.g. 'git clone --depth 1 %s sqlmap')" % GIT_REPOSITORY
logger.warning(warnMsg) # 提示用户使用git克隆
# 检查是否已是最新版本
if VERSION == getLatestRevision():
logger.info("already at the latest revision '%s'" % (getRevisionNumber() or VERSION))
return
# 询问用户是否尝试下载ZIP包更新
message = "do you want to try to fetch the latest 'zipball' from repository and extract it (experimental) ? [y/N]"
if readInput(message, default='N', boolean=True):
directory = os.path.abspath(paths.SQLMAP_ROOT_PATH)
try:
# 尝试创建/更新主程序文件
open(os.path.join(directory, "sqlmap.py"), "w+b")
except Exception as ex:
errMsg = "unable to update content of directory '%s' ('%s')" % (directory, getSafeExString(ex))
logger.error(errMsg)
else:
# 保存原文件属性
attrs = os.stat(os.path.join(directory, "sqlmap.py")).st_mode
# 清理目录内容
for wildcard in ('*', ".*"):
for _ in glob.glob(os.path.join(directory, wildcard)):
try:
if os.path.isdir(_):
shutil.rmtree(_)
else:
os.remove(_)
except:
pass
# 检查目录是否清空
if glob.glob(os.path.join(directory, '*')):
errMsg = "unable to clear the content of directory '%s'" % directory
logger.error(errMsg)
else:
try:
# 下载并解压最新的ZIP包
archive = _urllib.request.urlretrieve(ZIPBALL_PAGE)[0]
with zipfile.ZipFile(archive) as f:
for info in f.infolist():
info.filename = re.sub(r"\Asqlmap[^/]+", "", info.filename)
if info.filename:
f.extract(info, directory)
# 获取并显示新版本信息
filepath = os.path.join(paths.SQLMAP_ROOT_PATH, "lib", "core", "settings.py")
if os.path.isfile(filepath):
with openFile(filepath, "rb") as f:
version = re.search(r"(?m)^VERSION\s*=\s*['\"]([^'\"]+)", f.read()).group(1)
logger.info("updated to the latest version '%s#dev'" % version)
success = True
except Exception as ex:
logger.error("update could not be completed ('%s')" % getSafeExString(ex))
else:
if not success:
logger.error("update could not be completed")
else:
try:
# 恢复文件属性
os.chmod(os.path.join(directory, "sqlmap.py"), attrs)
except OSError:
logger.warning("could not set the file attributes of '%s'" % os.path.join(directory, "sqlmap.py"))
# 如果是Git仓库
else:
infoMsg = "updating sqlmap to the latest development revision from the "
infoMsg += "GitHub repository"
logger.info(infoMsg)
debugMsg = "sqlmap will try to update itself using 'git' command"
logger.debug(debugMsg)
dataToStdout("\r[%s] [INFO] update in progress" % time.strftime("%X"))
output = ""
try:
# 执行git更新命令
process = subprocess.Popen("git checkout . && git pull %s HEAD" % GIT_REPOSITORY, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=paths.SQLMAP_ROOT_PATH)
pollProcess(process, True)
output, _ = process.communicate()
success = not process.returncode
except Exception as ex:
success = False
output = getSafeExString(ex)
finally:
output = getText(output)
# 根据git更新结果输出信息
if success:
logger.info("%s the latest revision '%s'" % ("already at" if "Already" in output else "updated to", getRevisionNumber()))
else:
if "Not a git repository" in output:
errMsg = "not a valid git repository. Please checkout the 'sqlmapproject/sqlmap' repository "
errMsg += "from GitHub (e.g. 'git clone --depth 1 %s sqlmap')" % GIT_REPOSITORY
logger.error(errMsg)
else:
logger.error("update could not be completed ('%s')" % re.sub(r"\W+", " ", output).strip())
# 如果更新失败,根据操作系统给出建议
if not success:
if IS_WIN:
infoMsg = "for Windows platform it's recommended "
infoMsg += "to use a GitHub for Windows client for updating "
infoMsg += "purposes (https://desktop.github.com/) or just "
infoMsg += "download the latest snapshot from "
infoMsg += "https://github.com/sqlmapproject/sqlmap/downloads"
else:
infoMsg = "for Linux platform it's recommended "
infoMsg += "to install a standard 'git' package (e.g.: 'apt install git')"
logger.info(infoMsg)