mirror of
https://github.com/bunkerity/bunkerweb
synced 2026-05-24 09:28:37 +00:00
Merge branch 'dev' of github.com:bunkerity/bunkerweb into dev
This commit is contained in:
commit
189f2749d4
16 changed files with 121 additions and 66 deletions
|
|
@ -43,3 +43,8 @@ sed -i "s@${OLD_VERSION}@${NEW_VERSION}@g" src/common/db/model.py
|
|||
sed -i "s@${OLD_VERSION}@${NEW_VERSION}@g" .github/ISSUE_TEMPLATE/bug_report.yml
|
||||
# pyproject
|
||||
sed -i "s@${OLD_VERSION}@${NEW_VERSION}@g" pyproject.toml
|
||||
# Dockerfiles
|
||||
sed -i "s@LABEL version.*@LABEL version \"$NEW_VERSION\"@g" src/bw/Dockerfile
|
||||
sed -i "s@LABEL version.*@LABEL version \"$NEW_VERSION\"@g" src/scheduler/Dockerfile
|
||||
sed -i "s@LABEL version.*@LABEL version \"$NEW_VERSION\"@g" src/ui/Dockerfile
|
||||
sed -i "s@LABEL version.*@LABEL version \"$NEW_VERSION\"@g" src/autoconf/Dockerfile
|
||||
|
|
|
|||
|
|
@ -58,6 +58,10 @@ RUN apk add --no-cache bash && \
|
|||
# Fix CVEs
|
||||
# There are no CVEs to fix for this image
|
||||
|
||||
LABEL maintainer "Bunkerity <contact@bunkerity.com>"
|
||||
LABEL version "1.5.6"
|
||||
LABEL url "https://www.bunkerweb.io"
|
||||
|
||||
VOLUME /data
|
||||
|
||||
WORKDIR /usr/share/bunkerweb/autoconf
|
||||
|
|
|
|||
|
|
@ -70,6 +70,10 @@ RUN apk add --no-cache openssl pcre bash python3 yajl geoip libxml2 libgd curl &
|
|||
# Fix CVEs
|
||||
# There are no CVEs to fix for this image
|
||||
|
||||
LABEL maintainer "Bunkerity <contact@bunkerity.com>"
|
||||
LABEL version "1.5.6"
|
||||
LABEL url "https://www.bunkerweb.io"
|
||||
|
||||
EXPOSE 8080/tcp 8443/tcp
|
||||
|
||||
USER nginx:nginx
|
||||
|
|
|
|||
|
|
@ -69,16 +69,17 @@ class Job:
|
|||
extract_path = cache_path.parent
|
||||
if job_cache_file["file_name"].startswith("folder:"):
|
||||
extract_path = Path(job_cache_file["file_name"].split("folder:", 1)[1].rsplit(".tgz", 1)[0])
|
||||
ignored_dirs.add(extract_path)
|
||||
ignored_dirs.add(extract_path.as_posix())
|
||||
if job_cache_file["job_name"] != job_name:
|
||||
continue
|
||||
rmtree(extract_path, ignore_errors=True)
|
||||
extract_path.mkdir(parents=True, exist_ok=True)
|
||||
with tar_open(fileobj=BytesIO(job_cache_file["data"]), mode="r:gz") as tar:
|
||||
try:
|
||||
tar.extractall(extract_path, filter="fully_trusted")
|
||||
except TypeError:
|
||||
tar.extractall(extract_path)
|
||||
with LOCK:
|
||||
rmtree(extract_path, ignore_errors=True)
|
||||
extract_path.mkdir(parents=True, exist_ok=True)
|
||||
with tar_open(fileobj=BytesIO(job_cache_file["data"]), mode="r:gz") as tar:
|
||||
try:
|
||||
tar.extractall(extract_path, filter="fully_trusted")
|
||||
except TypeError:
|
||||
tar.extractall(extract_path)
|
||||
continue
|
||||
elif job_cache_file["job_name"] != job_name:
|
||||
continue
|
||||
|
|
@ -88,27 +89,29 @@ class Job:
|
|||
self.logger.error(f"Exception while restoring cache file {job_cache_file['file_name']} :\n{e}")
|
||||
ret = False
|
||||
|
||||
if not manual and self.job_path.is_dir():
|
||||
for file in self.job_path.glob("**/*"):
|
||||
skipped = False
|
||||
for ignored_dir in ignored_dirs:
|
||||
if file.as_posix().startswith(ignored_dir.as_posix()):
|
||||
with LOCK:
|
||||
if not manual and self.job_path.is_dir():
|
||||
for file in self.job_path.rglob("*"):
|
||||
skipped = False
|
||||
if file.as_posix().startswith(tuple(ignored_dirs)):
|
||||
skipped = True
|
||||
break
|
||||
|
||||
if skipped:
|
||||
continue
|
||||
if skipped:
|
||||
continue
|
||||
|
||||
self.logger.debug(f"Checking if {file} should be removed")
|
||||
if file not in plugin_cache_files and file.is_file():
|
||||
self.logger.debug(f"Removing non-cached file {file}")
|
||||
file.unlink(missing_ok=True)
|
||||
if file.parent.is_dir() and not list(file.parent.iterdir()):
|
||||
self.logger.debug(f"Removing empty directory {file.parent}")
|
||||
rmtree(file.parent, ignore_errors=True)
|
||||
elif file.is_dir() and not list(file.iterdir()):
|
||||
self.logger.debug(f"Removing empty directory {file}")
|
||||
rmtree(file, ignore_errors=True)
|
||||
self.logger.debug(f"Checking if {file} should be removed")
|
||||
if file not in plugin_cache_files and file.is_file():
|
||||
self.logger.debug(f"Removing non-cached file {file}")
|
||||
file.unlink(missing_ok=True)
|
||||
if file.parent.is_dir() and not list(file.parent.iterdir()):
|
||||
self.logger.debug(f"Removing empty directory {file.parent}")
|
||||
rmtree(file.parent, ignore_errors=True)
|
||||
if file.parent == self.job_path:
|
||||
break
|
||||
elif file.is_dir() and not list(file.iterdir()):
|
||||
self.logger.debug(f"Removing empty directory {file}")
|
||||
rmtree(file, ignore_errors=True)
|
||||
|
||||
return ret
|
||||
|
||||
|
|
|
|||
|
|
@ -66,10 +66,10 @@ fi
|
|||
|
||||
# Create wizard config
|
||||
if [ "$UI_WIZARD" != "" ] ; then
|
||||
echo -ne 'DNS_RESOLVERS=8.8.8.8 8.8.4.4\nHTTP_PORT=80\nHTTPS_PORT=443\nAPI_LISTEN_IP=127.0.0.1\nMULTISITE=yes\nUI_HOST=http://127.0.0.1:7000\nSERVER_NAME=\n' > /etc/bunkerweb/variables.env
|
||||
echo -ne 'DNS_RESOLVERS=9.9.9.9 8.8.8.8 8.8.4.4\nHTTP_PORT=80\nHTTPS_PORT=443\nAPI_LISTEN_IP=127.0.0.1\nMULTISITE=yes\nUI_HOST=http://127.0.0.1:7000\nSERVER_NAME=\n' > /etc/bunkerweb/variables.env
|
||||
do_and_check_cmd chown nginx:nginx /etc/bunkerweb/variables.env
|
||||
do_and_check_cmd chmod 660 /etc/bunkerweb/variables.env
|
||||
echo "" > /etc/bunkerweb/ui.env
|
||||
touch /etc/bunkerweb/ui.env
|
||||
do_and_check_cmd chown nginx:nginx /etc/bunkerweb/ui.env
|
||||
do_and_check_cmd chmod 660 /etc/bunkerweb/ui.env
|
||||
do_and_check_cmd systemctl enable bunkerweb-ui
|
||||
|
|
|
|||
|
|
@ -66,6 +66,10 @@ COPY --chown=root:scheduler --chmod=770 src/bw/misc/country.mmdb /var/tmp/bunker
|
|||
# Fix CVEs
|
||||
# There are no CVEs to fix for this image
|
||||
|
||||
LABEL maintainer "Bunkerity <contact@bunkerity.com>"
|
||||
LABEL version "1.5.6"
|
||||
LABEL url "https://www.bunkerweb.io"
|
||||
|
||||
VOLUME /data
|
||||
|
||||
WORKDIR /usr/share/bunkerweb/scheduler
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ class JobScheduler(ApiCaller):
|
|||
self.__lock = lock
|
||||
self.__thread_lock = Lock()
|
||||
self.__job_success = True
|
||||
self.__job_reload = False
|
||||
self.__semaphore = Semaphore(cpu_count() or 1)
|
||||
|
||||
@property
|
||||
|
|
@ -187,7 +188,11 @@ class JobScheduler(ApiCaller):
|
|||
with self.__thread_lock:
|
||||
self.__job_success = False
|
||||
|
||||
if self.__job_success and ret >= 2:
|
||||
if ret == 1:
|
||||
with self.__thread_lock:
|
||||
self.__job_reload = True
|
||||
|
||||
if self.__job_success and (ret < 0 or ret >= 2):
|
||||
success = False
|
||||
self.__logger.error(f"Error while executing job {name} from plugin {plugin}")
|
||||
with self.__thread_lock:
|
||||
|
|
@ -220,24 +225,25 @@ class JobScheduler(ApiCaller):
|
|||
self.__logger.error(f"Exception while scheduling jobs for plugin {plugin} : {format_exc()}")
|
||||
|
||||
def run_pending(self) -> bool:
|
||||
if self.__lock:
|
||||
self.__lock.acquire()
|
||||
threads = []
|
||||
self.__job_success = True
|
||||
self.__job_reload = False
|
||||
|
||||
jobs = [job for job in schedule_jobs if job.should_run]
|
||||
success = True
|
||||
reload = False
|
||||
for job in jobs:
|
||||
ret = job.run()
|
||||
for job in schedule_jobs:
|
||||
if not job.should_run:
|
||||
continue
|
||||
threads.append(Thread(target=self.__run_in_thread, args=((job.run,),)))
|
||||
|
||||
if not isinstance(ret, int):
|
||||
ret = -1
|
||||
for thread in threads:
|
||||
thread.start()
|
||||
|
||||
if ret == 1:
|
||||
reload = True
|
||||
elif ret < 0 or ret >= 2:
|
||||
success = False
|
||||
for thread in threads:
|
||||
thread.join()
|
||||
|
||||
if reload:
|
||||
success = self.__job_success
|
||||
self.__job_success = True
|
||||
|
||||
if self.__job_reload:
|
||||
try:
|
||||
if self.apis:
|
||||
cache_path = join(sep, "var", "cache", "bunkerweb")
|
||||
|
|
@ -247,28 +253,27 @@ class JobScheduler(ApiCaller):
|
|||
self.__logger.error(f"Error while sending {cache_path} folder")
|
||||
else:
|
||||
self.__logger.info(f"Successfully sent {cache_path} folder")
|
||||
|
||||
if not self.__reload():
|
||||
success = False
|
||||
except:
|
||||
except BaseException:
|
||||
success = False
|
||||
self.__logger.error(f"Exception while reloading after job scheduling : {format_exc()}")
|
||||
self.__job_reload = False
|
||||
|
||||
if threads:
|
||||
self.__logger.info("All scheduled jobs have been executed")
|
||||
|
||||
if self.__lock:
|
||||
self.__lock.release()
|
||||
return success
|
||||
|
||||
def run_once(self) -> bool:
|
||||
threads = []
|
||||
self.__job_success = True
|
||||
self.__job_reload = False
|
||||
|
||||
for plugin, jobs in self.__jobs.items():
|
||||
jobs_jobs = []
|
||||
|
||||
for job in jobs:
|
||||
path = job["path"]
|
||||
name = job["name"]
|
||||
file = job["file"]
|
||||
|
||||
# Add job to the list of jobs to run in the order they are defined
|
||||
jobs_jobs.append(partial(self.__job_wrapper, path, plugin, name, file))
|
||||
# Add job to the list of jobs to run in the order they are defined
|
||||
jobs_jobs = [partial(self.__job_wrapper, job["path"], plugin, job["name"], job["file"]) for job in jobs]
|
||||
|
||||
# Create a thread for each plugin
|
||||
threads.append(Thread(target=self.__run_in_thread, args=(jobs_jobs,)))
|
||||
|
|
@ -279,7 +284,7 @@ class JobScheduler(ApiCaller):
|
|||
for thread in threads:
|
||||
thread.join()
|
||||
|
||||
ret = self.__job_success is True
|
||||
ret = self.__job_success
|
||||
self.__job_success = True
|
||||
|
||||
return ret
|
||||
|
|
@ -288,7 +293,7 @@ class JobScheduler(ApiCaller):
|
|||
if self.__lock:
|
||||
self.__lock.acquire()
|
||||
|
||||
job_plugin = None
|
||||
job_plugin = ""
|
||||
job_to_run = None
|
||||
for plugin, jobs in self.__jobs.items():
|
||||
for job in jobs:
|
||||
|
|
@ -297,7 +302,7 @@ class JobScheduler(ApiCaller):
|
|||
job_to_run = job
|
||||
break
|
||||
|
||||
if not job_to_run:
|
||||
if not job_plugin or not job_to_run:
|
||||
self.__logger.warning(f"Job {job_name} not found")
|
||||
return False
|
||||
|
||||
|
|
|
|||
|
|
@ -58,6 +58,10 @@ RUN apk add --no-cache bash libmagic && \
|
|||
# Fix CVEs
|
||||
# There are no CVEs to fix for this image
|
||||
|
||||
LABEL maintainer "Bunkerity <contact@bunkerity.com>"
|
||||
LABEL version "1.5.6"
|
||||
LABEL url "https://www.bunkerweb.io"
|
||||
|
||||
VOLUME /data
|
||||
|
||||
EXPOSE 7000
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -88,6 +88,14 @@ class TabsSelect {
|
|||
//close dropdown and change btn textcontent on mobile
|
||||
this.setDropBtnText(tabAtt, text);
|
||||
this.closeDropdown();
|
||||
// Change URL fragment
|
||||
if (window.location.pathname.endsWith("global_config")) {
|
||||
window.history.replaceState(
|
||||
null,
|
||||
"",
|
||||
`${window.location.pathname}#${tabAtt}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
|
|
@ -101,6 +109,24 @@ class TabsSelect {
|
|||
}
|
||||
} catch (err) {}
|
||||
});
|
||||
|
||||
// If fragment exists, click on the corresponding tab
|
||||
if (
|
||||
window.location.hash &&
|
||||
window.location.pathname.endsWith("global_config")
|
||||
) {
|
||||
const fragment = window.location.hash.substring(1);
|
||||
if (fragment) {
|
||||
const tab = this.tabContainer.querySelector(
|
||||
`button[data-tab-select-handler='${fragment}']`,
|
||||
);
|
||||
tab.click();
|
||||
// Scroll to the top of the page (with a delay to ensure the tab is clicked first)
|
||||
setTimeout(() => {
|
||||
window.scrollTo(0, 0);
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resetTabsStyle() {
|
||||
|
|
|
|||
2
src/ui/templates/bans_modal.html
vendored
2
src/ui/templates/bans_modal.html
vendored
|
|
@ -125,7 +125,7 @@
|
|||
<input data-ban-add-inp type="hidden" name="data" value="" />
|
||||
<!-- action button -->
|
||||
<div class="w-full justify-center flex mt-6 mb-4">
|
||||
<button data-bans-modal-close type="button" class="close-btn mr-3 text-base">Close</button>
|
||||
<button data-bans-modal-close type="button" class="dark:bg-slate-800 close-btn mr-3 text-base">Close</button>
|
||||
<button disabled data-bans-modal-submit type="submit" class="valid-btn">Add</button>
|
||||
</div>
|
||||
<!-- end action button-->
|
||||
|
|
|
|||
2
src/ui/templates/file_manager.html
vendored
2
src/ui/templates/file_manager.html
vendored
|
|
@ -273,7 +273,7 @@
|
|||
</div>
|
||||
<!-- editor-->
|
||||
<div class="mt-4 w-full justify-end flex">
|
||||
<button type="button" data-{{ current_endpoint }}-modal-close class="close-btn text-xs mr-2">
|
||||
<button type="button" data-{{ current_endpoint }}-modal-close class="dark:bg-slate-800 close-btn text-xs mr-2">
|
||||
Close
|
||||
</button>
|
||||
<button data-{{ current_endpoint }}-modal-submit type="submit" class="valid-btn text-xs">
|
||||
|
|
|
|||
4
src/ui/templates/flashs.html
vendored
4
src/ui/templates/flashs.html
vendored
|
|
@ -9,14 +9,14 @@
|
|||
aria-expanded="false"
|
||||
aria-label="Open flash action sidebar"
|
||||
data-flash-sidebar-open
|
||||
class="transition scale-90 sm:scale-100 dark:brightness-95 p-3 text-xl bg-white shadow-sm cursor-pointer rounded-circle text-slate-700">
|
||||
class="transition scale-90 sm:scale-100 dark:bg-slate-750 dark:brightness-95 dark:hover:brightness-105 hover:brightness-75 p-3 text-xl bg-white shadow-sm cursor-pointer rounded-circle text-slate-700">
|
||||
<svg class="fill-yellow-500 -translate-y-0.4 h-6 w-6"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 448 512">
|
||||
<path d="M224 0c-17.7 0-32 14.3-32 32V51.2C119 66 64 130.6 64 208v18.8c0 47-17.3 92.4-48.5 127.6l-7.4 8.3c-8.4 9.4-10.4 22.9-5.3 34.4S19.4 416 32 416H416c12.6 0 24-7.4 29.2-18.9s3.1-25-5.3-34.4l-7.4-8.3C401.3 319.2 384 273.9 384 226.8V208c0-77.4-55-142-128-156.8V32c0-17.7-14.3-32-32-32zm45.3 493.3c12-12 18.7-28.3 18.7-45.3H224 160c0 17 6.7 33.3 18.7 45.3s28.3 18.7 45.3 18.7s33.3-6.7 45.3-18.7z" />
|
||||
</svg>
|
||||
</button>
|
||||
<div class="dark:brightness-95 px-2 translate-x-2 bottom-0 right-0 absolute rounded-full bg-white">
|
||||
<div class="dark:bg-slate-700 dark:brightness-95 px-2 translate-x-2 bottom-0 right-0 absolute rounded-full bg-white">
|
||||
<p data-flash-count class="mb-0 text-sm text-bold text-red-500">
|
||||
{% if messages %}
|
||||
{{ messages|length }}
|
||||
|
|
|
|||
2
src/ui/templates/loading.html
vendored
2
src/ui/templates/loading.html
vendored
|
|
@ -43,7 +43,7 @@
|
|||
res = await response.json();
|
||||
if (res.reloading === false) {
|
||||
clearInterval(reloading);
|
||||
window.location.replace("{{ next }}");
|
||||
window.location.replace("{{ next }}" + (window.location.hash ? window.location.hash : ""));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
2
src/ui/templates/news.html
vendored
2
src/ui/templates/news.html
vendored
|
|
@ -3,7 +3,7 @@
|
|||
aria-controls="sidebar-news"
|
||||
aria-expanded="false"
|
||||
aria-label="Open news sidebar"
|
||||
class="transition-all scale-90 sm:scale-100 dark:brightness-95 dark:hover:brightness-105 hover:brightness-75 fixed p-3 text-xl bg-white shadow-sm cursor-pointer top-[4.5rem] right-5 sm:right-40 xl:right-6 z-990 rounded-circle text-slate-700">
|
||||
class="transition-all scale-90 sm:scale-100 dark:bg-slate-750 dark:brightness-95 dark:hover:brightness-105 hover:brightness-75 fixed p-3 text-xl bg-white shadow-sm cursor-pointer top-[4.5rem] right-5 sm:right-40 xl:right-6 z-990 rounded-circle text-slate-700">
|
||||
<svg class="fill-sky-500 h-6 w-6"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512">
|
||||
|
|
|
|||
4
src/ui/templates/services_modal.html
vendored
4
src/ui/templates/services_modal.html
vendored
|
|
@ -91,7 +91,7 @@
|
|||
<div class="flex justify-center">
|
||||
<button data-services-modal-close
|
||||
type="button"
|
||||
class="close-btn mb-4 mr-3 text-base">Close</button>
|
||||
class="dark:bg-slate-800 close-btn mb-4 mr-3 text-base">Close</button>
|
||||
<button data-services-modal-submit type="submit" class="mb-4 valid-btn">Save</button>
|
||||
</div>
|
||||
<!-- end action button-->
|
||||
|
|
@ -118,7 +118,7 @@
|
|||
<div class="w-full justify-center flex mt-10">
|
||||
<button data-services-modal-close
|
||||
type="button"
|
||||
class="close-btn mb-4 mr-3 text-base">Close</button>
|
||||
class="dark:bg-slate-800 close-btn mb-4 mr-3 text-base">Close</button>
|
||||
<button type="submit" class="delete-btn mb-4 mr-3 text-base">Delete</button>
|
||||
</div>
|
||||
<!-- end action button-->
|
||||
|
|
|
|||
Loading…
Reference in a new issue