Update for Joomla 3.7.2

This commit is contained in:
Christoph Haas 2017-05-27 12:19:40 +02:00
parent 2bd7573770
commit a405edc8ce
1 changed files with 125 additions and 80 deletions

View File

@ -1,21 +1,22 @@
#!/usr/bin/env python3
from pathlib import Path
import re
import urllib.request
from urllib.request import urlretrieve
import zipfile
import shutil
import stat
import argparse
import hashlib
import os
import os.path
import hashlib
import re
import shutil
import stat
import sys
import argparse
import socket
import urllib.request
import urllib.error
import zipfile
from distutils.version import StrictVersion
from pathlib import Path
##############################################################
## CONFIG
# CONFIG
##############################################################
# BASE BASE
@ -27,52 +28,57 @@ csv_file_name = 'joomla_status.csv'
# TMP DOWNLOAD DIR
tmp_dl_dir = '/tmp'
#############################################################
def get_joomla_version(filepath):
fobj = open(filepath, "r", -1, None, 'replace')
version = -1
def get_joomla_version(version_file_path):
version_file = open(version_file_path, "r", -1, None, 'replace')
main_version = -1
dev_version = -1
for line in fobj:
if version != -1 and dev_version != -1:
for line in version_file:
if main_version != -1 and dev_version != -1:
break
match = re.search("""RELEASE[\s]*=[\s]*'?"?([0-9\.]+)'?"?""", line)
if match is not None:
#print(match.group(1))
version = match.group(1)
match = re.search("""DEV_LEVEL[\s]*=[\s]*'?"?([0-9]+)'?"?""", line)
if match is not None:
#print(match.group(1))
dev_version = match.group(1)
fobj.close()
version_match = re.search("""RELEASE[\s]*=[\s]*'?"?([0-9.]+)'?"?""", line)
if version_match is not None:
# print(version_match.group(1))
main_version = version_match.group(1)
if version != -1 and dev_version != -1:
return str(version + "." + dev_version)
version_match = re.search("""DEV_LEVEL[\s]*=[\s]*'?"?([0-9]+)'?"?""", line)
if version_match is not None:
# print(version_match.group(1))
dev_version = version_match.group(1)
version_file.close()
if main_version != -1 and dev_version != -1:
return str(main_version + "." + dev_version)
else:
return ""
def check_version(version, newest_version):
if StrictVersion(newest_version) > StrictVersion(version):
def check_version(current_version, latest_version):
if StrictVersion(latest_version) > StrictVersion(current_version):
return False
else:
return True
def get_newest_version():
response = urllib.request.urlopen("http://update.joomla.org/core/list.xml")
highest_version = "0.0"
for line in response:
match = re.search("""[\s]version="?'?([0-9\.]+)"?'?""", str(line))
if match is not None:
if StrictVersion(match.group(1)) > StrictVersion(highest_version):
highest_version = match.group(1)
version_match = re.search("""[\s]version="?'?([0-9.]+)"?'?""", str(line))
if version_match is not None:
if StrictVersion(version_match.group(1)) > StrictVersion(highest_version):
highest_version = version_match.group(1)
return highest_version
def download_joomla_version(version):
version_match = re.search("""(\d+)\.(\d+)(\.(\d+))?([ab](\d+))?""", version)
def download_joomla_version(joomla_version):
version_match = re.search("""(\d+)\.(\d+)(\.(\d+))?([ab](\d+))?""", joomla_version)
dst_path = ""
if version_match is not None:
if version_match.group(1) == "2":
@ -82,40 +88,56 @@ def download_joomla_version(version):
version_string = version_match.group(1) + "-" + version_match.group(2) + "-" + version_match.group(4)
# check if file has already been downloaded...
dst_path = tmp_dl_dir + "/orig_joomla_" + version + ".zip"
dst_path = tmp_dl_dir + "/orig_joomla_" + joomla_version + ".zip"
dst_file = Path(dst_path)
if not dst_file.is_file():
url = "https://downloads.joomla.org/cms/" + version_path + "/" + version_string + "/joomla_" + version_string + "-stable-full_package-zip?format=zip"
if StrictVersion(joomla_version) > StrictVersion('3.7.1'):
version_string2 = ".".join(version_string.rsplit('-', 1))
url = "https://downloads.joomla.org/cms/" + \
version_path + "/" + version_string + \
"/Joomla_" + version_string2 + \
"-Stable-Full_Package.zip?format=zip"
else:
url = "https://downloads.joomla.org/cms/" + \
version_path + "/" + version_string + \
"/joomla_" + version_string + \
"-stable-full_package-zip?format=zip"
try:
urllib.request.urlretrieve (url, dst_path)
except:
urllib.request.urlretrieve(url, dst_path)
except (urllib.error.URLError, urllib.error.HTTPError, socket.error):
# print("Download of", url, "failed!")
dst_path = ""
return dst_path
def extract_downloaded_joomla_version(version, path):
dst_path = tmp_dl_dir + "/orig_joomla_" + version
def extract_downloaded_joomla_version(joomla_version, zip_file_path):
dst_path = tmp_dl_dir + "/orig_joomla_" + joomla_version
# extract a fresh copy...
shutil.rmtree(dst_path, onerror=remove_readonly)
try:
with zipfile.ZipFile(path, "r") as zip_ref:
with zipfile.ZipFile(zip_file_path, "r") as zip_ref:
zip_ref.extractall(dst_path)
except:
except (urllib.error.URLError, urllib.error.HTTPError, socket.error):
dst_path = ""
return dst_path
def remove_readonly(func, path, excinfo):
if os.path.isdir(path):
os.chmod(path, stat.S_IWRITE)
func(path)
def get_dir_md5(dir_root):
exclude_dirs = {"installation", "tmp"}
hash = hashlib.md5()
md5_hash = hashlib.md5()
for dirpath, dirnames, filenames in os.walk(dir_root, topdown=True):
dirnames.sort(key=os.path.normcase)
@ -140,57 +162,69 @@ def get_dir_md5(dir_root):
f = open(filepath, 'rb')
for chunk in iter(lambda: f.read(65536), b''):
hash.update(chunk)
md5_hash.update(chunk)
return md5_hash.hexdigest()
return hash.hexdigest()
def cmp_joomla_directories(original_root, installation_root):
exclude_dirs = {"installation", "tmp", "logs"}
check_failures = []
for dirpath, dirnames, filenames in os.walk(original_root, topdown=True):
check_failures = []
dirnames.sort(key=os.path.normcase)
filenames.sort(key=os.path.normcase)
for dir_path, dir_names, file_names in os.walk(original_root, topdown=True):
dirnames[:] = [d for d in dirnames if d not in exclude_dirs]
dir_names.sort(key=os.path.normcase)
file_names.sort(key=os.path.normcase)
for filename in filenames:
relative_path = os.path.relpath(dirpath, original_root)
dir_names[:] = [d for d in dir_names if d not in exclude_dirs]
for filename in file_names:
relative_path = os.path.relpath(dir_path, original_root)
if relative_path == ".":
relative_path = ""
orig_filepath = os.path.join(dirpath, filename)
inst_filepath = os.path.join(installation_root, os.path.join(relative_path, filename))
if os.path.isfile(inst_filepath):
orig_file_path = os.path.join(dir_path, filename)
inst_file_path = os.path.join(installation_root, os.path.join(relative_path, filename))
if os.path.isfile(inst_file_path):
hash_orig = hashlib.md5()
f = open(orig_filepath, 'rb')
f = open(orig_file_path, 'rb')
for chunk in iter(lambda: f.read(65536), b''):
hash_orig.update(chunk)
f.close()
hash_inst = hashlib.md5()
f = open(inst_filepath, 'rb')
f = open(inst_file_path, 'rb')
for chunk in iter(lambda: f.read(65536), b''):
hash_inst.update(chunk)
f.close()
if hash_orig.hexdigest() == hash_inst.hexdigest():
#print("file ok", os.path.join(relative_path, filename), hash_orig.hexdigest(), hash_inst.hexdigest())
"""
print("file ok",
os.path.join(relative_path, filename),
hash_orig.hexdigest(),
hash_inst.hexdigest())
"""
pass
else:
#print("file NOT OK!!!!!!!!!!!!!!!!!!!!!!!", os.path.join(relative_path, filename), hash_orig.hexdigest(), hash_inst.hexdigest())
"""
print("file NOT OK!",
os.path.join(relative_path, filename),
hash_orig.hexdigest(),
hash_inst.hexdigest())
"""
check_failures.append(os.path.join(relative_path, filename))
else:
#print("File", os.path.join(relative_path, filename), "is missing!")
# print("File", os.path.join(relative_path, filename), "is missing!")
pass
return check_failures
class bcolors:
class ConsoleColors:
HEADER = '\033[95m'
OKBLUE = '\033[94m'
OKGREEN = '\033[92m'
@ -200,6 +234,7 @@ class bcolors:
BOLD = '\033[1m'
UNDERLINE = '\033[4m'
# MAIN
###########
@ -211,7 +246,7 @@ args = parser.parse_args()
newest_version = get_newest_version()
print(bcolors.HEADER + "Newest Joomla Version: ", bcolors.OKBLUE, newest_version, bcolors.ENDC, "\n")
print(ConsoleColors.HEADER + "Newest Joomla Version: ", ConsoleColors.OKBLUE, newest_version, ConsoleColors.ENDC, "\n")
fobj = open(csv_file_name, "w")
fobj.write("Status;Integrity;Actual Version;Newest Version;Domain;Path\n")
@ -229,30 +264,37 @@ for file_path in Path(base_path).glob('**/version.php'):
version_status = "UNKN"
integrity_status = "UNKN"
if not check_version(version, newest_version):
print(bcolors.FAIL, "[WARNING]", bcolors.ENDC, "Outdated Joomla version found!\t[", bcolors.FAIL + version + bcolors.ENDC, "] [", bcolors.WARNING + domain + bcolors.ENDC, "] \tin ", file_path)
print(ConsoleColors.FAIL, "[WARNING]", ConsoleColors.ENDC, "Outdated Joomla version found!\t[",
ConsoleColors.FAIL + version + ConsoleColors.ENDC, "] [",
ConsoleColors.WARNING + domain + ConsoleColors.ENDC, "] \tin ",
file_path)
version_status = "WARN"
else:
print(bcolors.OKGREEN, "[OK] ", bcolors.ENDC, "Up to date Joomla version found!\t[", bcolors.OKGREEN + version + bcolors.ENDC, "] [", bcolors.WARNING + domain + bcolors.ENDC, "] \tin ", file_path)
print(ConsoleColors.OKGREEN, "[OK] ", ConsoleColors.ENDC, "Up to date Joomla version found!\t[",
ConsoleColors.OKGREEN + version + ConsoleColors.ENDC, "] [",
ConsoleColors.WARNING + domain + ConsoleColors.ENDC, "] \tin ",
file_path)
version_status = "OKOK"
if not args.nointegrity:
print(bcolors.HEADER, " -> Checking file integrity: ", bcolors.ENDC, end=" ")
print(ConsoleColors.HEADER, " -> Checking file integrity: ", ConsoleColors.ENDC, end=" ")
sys.stdout.flush()
dl_path = download_joomla_version(version)
if not dl_path:
print(bcolors.FAIL, "Failed to download joomla source!", bcolors.ENDC)
print(ConsoleColors.FAIL, "Failed to download joomla source!", ConsoleColors.ENDC)
else:
orig_root = extract_downloaded_joomla_version(version, dl_path)
cms_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(str(file_path))))) # strip "libraries/cms/version/version.php" from filename
cms_root = os.path.dirname(os.path.dirname(os.path.dirname(
os.path.dirname(str(file_path))))) # strip "libraries/cms/version/version.php" from filename
if not orig_root:
print(bcolors.FAIL, "Failed to extract joomla source!", bcolors.ENDC)
print(ConsoleColors.FAIL, "Failed to extract joomla source!", ConsoleColors.ENDC)
else:
result_list = cmp_joomla_directories(orig_root, cms_root)
if len(result_list) == 0:
print(bcolors.OKGREEN, "OK", bcolors.ENDC)
print(ConsoleColors.OKGREEN, "OK", ConsoleColors.ENDC)
integrity_status = "OKOK"
else:
# check if only image files differ... if so ignore it.
@ -265,18 +307,21 @@ for file_path in Path(base_path).glob('**/version.php'):
real_fail_count = real_fail_count + 1
if real_fail_count == 0:
print(bcolors.WARNING, "OK", bcolors.ENDC, "Use -v to get details!")
print(ConsoleColors.WARNING, "OK", ConsoleColors.ENDC, "Use -v to get details!")
integrity_status = "WARN"
else:
print(bcolors.FAIL, "FAIL", bcolors.ENDC, "Use -v to get details!")
print(ConsoleColors.FAIL, "FAIL", ConsoleColors.ENDC, "Use -v to get details!")
integrity_status = "FAIL"
if args.verbose:
if len(result_list) > 0:
print('\tMissmatch: %s' % '\n\tMissmatch: '.join(map(str, result_list)))
fobj.write(version_status + ";" + integrity_status + ";" + version + ";" + newest_version + ";" + domain + ";" + str(file_path) + "\n")
print("") # empty last line
fobj.write(
version_status + ";" + integrity_status + ";" + version + ";" + newest_version + ";" + domain + ";" + str(
file_path) + "\n")
print("") # empty last line
fobj.close()
print("\n" + bcolors.HEADER + "All versions written to: ", bcolors.OKBLUE, csv_file_name, bcolors.ENDC)
print("\n" + ConsoleColors.HEADER + "All versions written to: ",
ConsoleColors.OKBLUE, csv_file_name, ConsoleColors.ENDC)