Skip to content

Instantly share code, notes, and snippets.

@Sarverott
Last active August 21, 2025 08:01
Show Gist options
  • Save Sarverott/98bf99ef92e0aa8abe1bbc89e6b7f592 to your computer and use it in GitHub Desktop.
Save Sarverott/98bf99ef92e0aa8abe1bbc89e6b7f592 to your computer and use it in GitHub Desktop.
old updater script, currenty deprecated and archived - MIT licensed, you use it on your own risk!
import ftplib
import os
from dotenv import load_dotenv
load_dotenv()
MODE = os.getenv('FTP_MODE')
HOST = os.getenv('FTP_HOST')
USER = os.getenv('FTP_USER')
PASS = os.getenv('FTP_PASS')
#idea from https://stackoverflow.com/questions/10042838/delete-all-files-and-folders-after-connecting-to-ftp
def delDirTree(ftphook, path):
ftphook.cwd(path)
for item in ftphook.nlst():
try:
ftphook.delete(item)
except Exception:
delDirTree(ftphook, item)
ftphook.cwd("..")
ftphook.rmd(path)
def updateApp(appname, zipFilePath):
global MODE, HOST, USER, PASS
ftpHost=None
appPath="/main_webapps/"+appname
if "_" in [appname[0], appname[-1]] or "." in appname:
raise NameError('forbidden appname first char')
appDomain=".".join(appname.split("_"))
if MODE.lower()=="ftp":
ftpHost=ftplib.FTP(HOST)
elif MODE.lower()=="ftps":
ftpHost=ftplib.FTP_TLS(HOST)
else:
raise RuntimeError("unknown mode of FTP")
ftpsHost.login(USER, PASS)
if appname in ftphook.nlst(appPath):
delDirTree(ftpsHost, appPath)
ftpsHost.mkd(appPath)
ftpsHost.close()
import ftplib
import os
from dotenv import load_dotenv
import time
import io
import requests
load_dotenv()
MODE = os.getenv('FTP_MODE')
HOST = os.getenv('FTP_HOST')
USER = os.getenv('FTP_USER')
PASS = os.getenv('FTP_PASS')
class Overlord():
rootPath="/public_html"
systemPath="/_overlord"
systemDirtree=[
systemPath,
systemPath+"/to_unpack",
systemPath+"/update_backup",
systemPath+"/snet_logs"
]
#webappList=[
# "ssubwebapp_com",
# "beboki_pl"
#]
def config(self, host, username, password):
self.ftpHost=host
self.ftpUser=username
self.ftpPass=password
def connect(self):
self.ftpHook=ftplib.FTP_TLS(self.ftpHost)
self.ftpHook.login(self.ftpUser, self.ftpPass)
def end(self):
self.ftpHook.close()
def delDirTree(self, path, withThisDir=True): #idea from https://stackoverflow.com/questions/10042838/delete-all-files-and-folders-after-connecting-to-ftp
self.ftpHook.cwd(path)
for item in self.ftpHook.nlst():
try:
self.ftpHook.delete(item)
except Exception:
self.delDirTree(item)
self.ftpHook.cwd("..")
if withThisDir:
self.ftpHook.rmd(path)
def clearWebapp(self):
self.delDirTree(Overlord.rootPath, False)
def purgeFromServer(self):
#self.delDirTree(Overlord.rootPath, False)
self.delDirTree(Overlord.systemPath)
#self.ftpHook.mkd(Overlord.rootPath)
def installOnServer(self):
for internalDir in Overlord.systemDirtree:
self.ftpHook.mkd(internalDir)
phpFilesDir=os.path.dirname(__file__)#+"/server-internal"
self.ftpHook.cwd(Overlord.systemDirtree[0])
for phpFile in os.listdir(phpFilesDir):
with open(phpFilesDir+"/"+phpFile, 'rb') as file:
self.ftpHook.storbinary('STOR '+Overlord.systemDirtree[0]+"/"+phpFile, file)
#for appDir in Overlord.webappList:
# appDirPath=Overlord.rootPath+"/"+appDir
# self.ftpHook.mkd(appDirPath)
self.ftpHook.cwd(Overlord.rootPath)
#self.ftpHook.dir()
def updateApp(self, appname, zipFilePath):
if "_" in [appname[0], appname[-1]] or "." in appname:
raise NameError('forbidden appname first char')
#if not appname in Overlord.webappList:
# raise NameError('webapp not exists')
appPath=Overlord.rootPath
appRemoteZip=appname+"."+str(int(time.time()))+".zip"
with open(zipFilePath, 'rb') as file:
self.ftpHook.storbinary('STOR '+Overlord.systemDirtree[1]+"/"+appRemoteZip, file)
indexInstallScript=io.BytesIO()
with open("./packed-installer.php", 'r') as template:
for line in template.readlines():
replacer=line
replacer=replacer.replace("<<<APPNAME>>>", appname)
replacer=replacer.replace("<<<ZIPNAME>>>", appRemoteZip)
replacer=replacer.replace("<<<SYSTEMDIR>>>", Overlord.systemDirtree[0])
indexInstallScript.write(bytes(replacer, "utf-8"))
indexInstallScript.seek(0)
#if appname in self.ftpHook.nlst(Overlord.rootPath):
# self.delDirTree(appPath)
#self.ftpHook.mkd(appPath)
self.clearWebapp()
self.ftpHook.storbinary('STOR '+appPath+"/meowmeowmeow.php", indexInstallScript)
with open("./reloc-index.php", 'rb') as template:
self.ftpHook.storbinary('STOR '+appPath+"/index.php", template)
#self.end()
def lounchServerSideAct(self, appname):
appDomain=".".join(appname.split("_"))
result=requests.get("http://"+appDomain+"/")
return (result.text, result)
ovrlrdClient=Overlord()
ovrlrdClient.config(HOST, USER, PASS)
ovrlrdClient.connect()
#ovrlrdClient.purgeFromServer()
#ovrlrdClient.installOnServer()
ovrlrdClient.updateApp("subwebapp_com", "/media/asterisk/snet-A0010/__WORKSHOP/forge/examplescope/webapp.com/subwebapp_com-1692723639.zip")
ovrlrdClient.end()
time.sleep(3)
print(ovrlrdClient.lounchServerSideAct("subwebapp_com"))
#def updateApp(appname, zipFilePath):
# global MODE, HOST, USER, PASS
# ftpHost=None
# appPath="/main_webapps/"+appname
#
# if "_" in [appname[0], appname[-1]] or "." in appname:
# raise NameError('forbidden appname first char')
# appDomain=".".join(appname.split("_"))
# if MODE.lower()=="ftp":
# ftpHost=ftplib.FTP(HOST)
# elif MODE.lower()=="ftps":
# ftpHost=ftplib.FTP_TLS(HOST)
# else:
# raise RuntimeError("unknown mode of FTP")
# ftpsHost.login(USER, PASS)
# if appname in ftpHook.nlst(appPath):
# delDirTree(ftpsHost, appPath)
# ftpsHost.mkd(appPath)
# ftpsHost.close()
import ftplib
import os
from dotenv import load_dotenv
load_dotenv()
HOST = os.getenv('FTPS_HOST')
USER = os.getenv('FTPS_USER')
PASS = os.getenv('FTPS_PASS')
#print(HOST)
#print(HOST is None)
#print(os.path.exists(".env"))
#exit()
with ftplib.FTP_TLS(HOST) as ftp:
ftp.login(USER, PASS)
#ftp.prot_p() ## wykonało pierwsze, nie wykonało drugiego
print(ftp.pwd())
print(ftp.nlst())
print(ftp.cwd("/public_html"))
print(ftp.pwd())
print(ftp.nlst())
print(ftp.sendcmd("help"))
ftp.close()
FTP_MODE=FTPS
FTP_HOST=hostingverse.example.net
FTP_USER=asterisk
FTP_PASS=[email protected]

DIR TREE on server

after update uploaded, in moment

/main_webapps

  • _setternet
    • backup-archivize.php
    • meowing-notice.html
    • webapp-update.php
    • to_unpack
      • {appname}.{timestamp}.zip
      • ...
    • update_backup
      • {appname}.{timestamp}.zip
      • {appname}.{timestamp}.archived-note.ini
      • ...
    • snet_logs
      • {{some logs idk}}
  • {appname}
    • index.php

_setternet/webapp-update.php - instalation procedures

  1. replaces index.php content with dumb-wait dislpay to avoid multiple running updates
  2. renames [update].zip to tmp.[update].zip zip (another emergency way to avoid multiple unpacks)
  3. display absorbing attention loading frontend
  4. unpack tmp.[update].zip to app's dir
  5. move to_unpack/tmp.[update].zip to update_backup/[update].zip
  6. echo js that reloads page
  7. die script <- because content of including script has been altered

{appname}/index.php - installer before operation

  1. setup constant defines
  2. include webapp-update.php
  3. die script <- this point should be never reachable for execution

{appname}/index.php - replacement dumb-wait display

  1. include meowing-notice.html
  2. die script

_setternet/backup_archivize.php - check update packs and reduces them to short info raport about file

  • {{TODO: informations like checksum, time of all that, uploading entity (setternet host), point in git story, ip that lounches install, etc. about [update].zip write to [update].zip.archived-note.ini and delete [update].zip}}
<html>
<head>
<meta charset="utf-8">
<title>ERROR - this problem is meowed!</title>
<meta http-equiv="refresh" content="600">
<link rel="icon" type="image/x-icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABhWlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AcxV9TtUUqHewg4pChioMFURFHrUIRKoRaoVUHk0u/oElDkuLiKLgWHPxYrDq4OOvq4CoIgh8gri5Oii5S4v+SQotYD4778e7e4+4dINTLTLO6xgFNt81UIi5msqti4BUhBNGDUYRlZhlzkpREx/F1Dx9f72I8q/O5P0efmrMY4BOJZ5lh2sQbxNObtsF5nzjCirJKfE48ZtIFiR+5rnj8xrngssAzI2Y6NU8cIRYLbay0MSuaGvEUcVTVdMoXMh6rnLc4a+Uqa96TvzCU01eWuU5zCAksYgkSRCioooQybMRo1UmxkKL9eAf/oOuXyKWQqwRGjgVUoEF2/eB/8LtbKz854SWF4kD3i+N8DAOBXaBRc5zvY8dpnAD+Z+BKb/krdWDmk/RaS4seAeFt4OK6pSl7wOUOMPBkyKbsSn6aQj4PvJ/RN2WB/lugd83rrbmP0wcgTV0lb4CDQ2CkQNnrHd4dbO/t3zPN/n4APDlykY9kztsAAAAGYktHRAAAAAAAAPlDu38AAAAJcEhZcwAALiMAAC4jAXilP3YAAAAHdElNRQfnDAgGKSnFqD9BAAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAAAEJJREFUOMtj/P///38GAoCRkRGr+P///xlYCCkgBJgYKATD2YC8vDyiDGAhNrRp5gVGBgaG/6PROMAGsBCTBvDlVgBvsRVktun80QAAAABJRU5ErkJggg==">
<style>
*{
overflow:hidden;
}
img{
position:absolute;
top:0;
left:0;
width:100vw;
height:100vh;
}
</style>
</head>
<script>
const noticeContent=`
Hi there!!!
Unfortunately website can't play with you right now ;/
This website is currently in the middle of meowing!
Come back later, this should take couple minutes...
in the darkest scenario... less than hour :)
See you later ;P
PS.:
We automaticly refresh this site after 10min for you!
`;
function informAboutMeowing(){
alert(noticeContent);
document.title="Thank you for your patience! Meowing in progress...";
}
function withTinyDelay(f){
setTimeout(f ,100);
}
window.onload=withTinyDelay(informAboutMeowing);
</script>
<body>
<img src="https://http.cat/401.jpg">
</body>
</html>
<?php
function dumbWaitedIndex(){
$tmpindex=fopen(UPDATING_LOUNCHER, "w");
$dumbwaitinclude='<?php include "';
$dumbwaitinclude.=dirname(__FILE__);
$dumbwaitinclude.='/meowing-notice.html";die(); ?>';
fwrite($tmpindex, $dumbwaitinclude);
fclose($tmpindex);
}
function TemporaryRenameOpenedZip(){
$currentpath=dirname(__FILE__)."/to_unpack/".UPDATING_ZIPNAME;
$tmppath=dirname(__FILE__)."/to_unpack/tmp.".UPDATING_ZIPNAME;
rename($currentpath,$tmppath);
return $tmppath;
}
function displayLoading(){
#cos fajnego tu
echo "loading...";
}
function unpackZipToAppDir($zippath){
$ziphook= new ZipArchive;
if($ziphook->open($zippath)===TRUE){
$ziphook->extractTo(UPDATING_PATH);
$ziphook->close();
}else{
throw new Exception("zip error", 1);
}
}
function moveUpdateZipToBackups($zippath){
$backupzip=dirname(__FILE__)."/update_backup/".UPDATING_ZIPNAME;
rename($zippath,$backupzip);
}
function reloadSiteByJs(){
echo "<script>setTimeout(function(){location.reload()},2000);</script>";
}
if(
defined("UPDATING_APPNAME")
&&
defined("UPDATING_PATH")
&&
defined("UPDATING_ZIPNAME")
&&
defined("UPDATING_LOUNCHER")
){
#dumbWaitedIndex();
#$zippath=TemporaryRenameOpenedZip();
$zippath=dirname(__FILE__)."/to_unpack/".UPDATING_ZIPNAME
displayLoading();
unpackZipToAppDir($zippath);
moveUpdateZipToBackups($zippath);
reloadSiteByJs();
die();
}else{
include dirname(__FILE__)."/meowing-notice.html";
die();
}
<?php
define("UPDATING_APPNAME", '<<<APPNAME>>>');
define("UPDATING_PATH", dirname(__FILE__));
define("UPDATING_ZIPNAME", '<<<ZIPNAME>>>');
define("UPDATING_LOUNCHER", __FILE__);
include UPDATING_PATH.'/webapp-update.php';
die();
<?php
system("unzip -oq overlord-update.zip -d /");
unlink("overlord-update.zip");
unlink(__FILE__);
echo "OK";
die();
<?php
define("UPDATING_APPNAME", '<<<APPNAME>>>');
define("UPDATING_PATH", "/public_html");
define("UPDATING_ZIPNAME", '<<<ZIPNAME>>>');
define("UPDATING_LOUNCHER", __FILE__);
function TemporaryRenameOpenedZip(){
$currentpath="/_overlord/to_unpack/".UPDATING_ZIPNAME;
$tmppath="/_overlord/to_unpack/tmp.".UPDATING_ZIPNAME;
rename($currentpath,$tmppath);
return $tmppath;
}
function displayLoading(){
#cos fajnego tu
echo "loading...";
}
function unpackZipToAppDir($zippath){
exec("unzip -oq $zippath")
}
function moveUpdateZipToBackups($zippath){
$backupzip="/_overlord/update_backup/".UPDATING_ZIPNAME;
rename($zippath,$backupzip);
}
#dumbWaitedIndex();
#$zippath=TemporaryRenameOpenedZip();
$zippath="/_overlord/to_unpack/".UPDATING_ZIPNAME;
displayLoading();
unpackZipToAppDir($zippath);
moveUpdateZipToBackups($zippath);
die();
<?php header("Location: /meowmeowmeow.php");die();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment