diff --git a/.gitignore b/.gitignore index c38fa4e..cf9cb08 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .idea *.iml +node_modules/ diff --git a/README.md b/README.md index 619ff70..1d87dfa 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,22 @@ This volume can get quite large. It will require at least 2G of disk space for t Some map mods are as large as 10G. Make sure you have that much disk space in the location where docker stores its volumes, usually `/var/lib/docker/volumes`. +## TL;DR for this branch and release DayZ server + +```shell +git clone https://ceregatti.org/git/daniel/dayzdockerserver.git +cd dayzdockerserver +git checkout volume-refactor +docker compose up -d --build +docker compose exec main bash +dz login # Use a real login, as anonymous cannot download mods +dz install +cd /serverfiles +mv DayZServer DayZServer.release +wget https://cdn.discordapp.com/attachments/491622000935305217/1105089599983853698/DayZServer +chmod 755 DayZServer +dz start # Will start a vanilla Chernarus map +``` ## Configure and Build Ensure [Docker](https://docs.docker.com/engine/install/) and [Docker compose](https://docs.docker.com/compose/install/) diff --git a/docker-compose.yml b/docker-compose.yml index bdada0d..12b97ba 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,7 +2,9 @@ version: "3.3" volumes: # For steamcmd files and resource files used by the scripts - homedir: + homedir_main: + # For workshop.cfg, for now + homedir_server: # Where the server files will be installed serverfiles: # Server profile files @@ -15,14 +17,28 @@ volumes: services: main: - build: . + build: web volumes: - - homedir:/home/user + - homedir_main:/home/user - serverfiles:/serverfiles - mods:/serverfiles/steamapps/workshop/content - mpmissions:/serverfiles/mpmissions + - ./files:/files:ro + - ./web:/web:ro + ports: + - "8000:8000/tcp" + restart: no + + server: + build: server + volumes: + - homedir_server:/home/user + - serverfiles:/serverfiles:ro + - mods:/serverfiles/steamapps/workshop/content:ro + - mpmissions:/serverfiles/mpmissions - profiles:/profiles - ./files:/files + - ./bin:/files/bin # To have the server show up in the LAN tab of the DayZ launcher, # it must run under host mode. network_mode: host @@ -39,13 +55,10 @@ services: # Always restart, unless stopped restart: unless-stopped # Allows attaching a debugger from the host -# cap_add: -# - SYS_PTRACE + cap_add: + - SYS_PTRACE # Allows core files to be created within the container. These are VERY LARGE! Enable only for debugging! -# ulimits: -# core: -# soft: -1 -# hard: -1 - # Do nothing instead of starting the server, which is the default. - # Helpful for development or debugging. -# command: tail -f /dev/null + ulimits: + core: + soft: -1 + hard: -1 diff --git a/files/dz b/files/dz deleted file mode 120000 index e2f5e73..0000000 --- a/files/dz +++ /dev/null @@ -1 +0,0 @@ -dayzserver \ No newline at end of file diff --git a/files/dz-common b/files/dz-common new file mode 100755 index 0000000..57db69e --- /dev/null +++ b/files/dz-common @@ -0,0 +1,170 @@ +#!/usr/bin/env bash + +set -eEa + +# If you want/need the server and rcon ports to be different, set them here. +# The steam query port is set in serverDZ.cfg. + +# Server port +port=2302 +rcon_port=2303 + +# Don't change anything else. + +# Colors +default="\e[0m" +red="\e[31m" +green="\e[32m" +yellow="\e[93m" +lightblue="\e[94m" +blue="\e[34m" +magenta="\e[35m" +cyan="\e[36m" + +# DayZ release server Steam app ID. +# Presumably once the Linux server is released, the binaries will come from this ID. +# But more importantly, if we have a release-compatible binary, the base files must be installed from this id. +release_server_appid=223350 +# Without a release binary, we must use the experimental server app id for everything. +#release_server_appid=1042420 + +# DayZ release client SteamID. This is for mods, as only the release client has them. +release_client_appid=221100 + +# Main container base directories +CFG_SRC_FILES="/files" +SERVER_FILES="/serverfiles" + +# Server container base directories +SERVER_PROFILE="/profiles" + +mkdir -p ${SERVER_FILES}/battleye + +# Server configuration file +SERVER_CFG_FILE="serverDZ.cfg" +SERVER_CFG_DST="${SERVER_FILES}/${SERVER_CFG_FILE}" +SERVER_CFG_SRC="${CFG_SRC_FILES}/${SERVER_CFG_FILE}" + +# Command line parameters except mod, as that is handled separately. +parameters="-config=${SERVER_CFG_FILE} -port=${port} -freezecheck -BEpath=${SERVER_FILES}/battleye -profiles=${SERVER_PROFILE} -nologs" + +# Used to check if dayZ is installed +SERVER_INSTALL_FILE="${SERVER_FILES}/DayZServer" + +# Steam files +STEAM_LOGIN="${HOME}/steamlogin" +STEAMCMD=steamcmd + +# Workshop. This file will store metadata about what mods are installed. +WORKSHOP_CFG="${HOME}/workshop.cfg" +if [ ! -f "${WORKSHOP_CFG}" ] +then + touch "${WORKSHOP_CFG}" +fi + +# An array to store Workshop items. Each element contains the mod's ID, name, and state (active or not). +declare -a workshopID +workshopfolder="${SERVER_FILES}/steamapps/workshop/content/${release_client_appid}" + +# Backups +BACKUP_DIR="${HOME}/backup" +if [ ! -d "${BACKUP_DIR}" ] +then + mkdir -p "${BACKUP_DIR}" +fi + +# Other stuff +YES="${green}yes${default}" +NO="${red}no${default}" + +# Functions + +checkInstall(){ + # See if this mod id exists in files/mods, and offer to install other server side files if an install.sh is found + if [ -f /files/mods/${1}/${2}.sh ] + then + echo "An ${2}.sh was found for mod id ${1}. Running..." + /files/mods/${1}/${2}.sh + fi + # A generic map install script. Presumes a git repo as the source + if [ -f /files/mods/${1}/install.env ] + then + echo "An ${2}.env was found for mod id ${1}. Performing ${2}..." + source /files/mods/${1}/install.env + /files/mods/install.sh ${1} ${2} + fi +} + +# Convenience function +prompt_yn(){ + echo -n "${1} (y|N) " >&2 + read -s -n 1 a + a=$(echo ${a} | tr A-Z a-z) + echo + if [[ "${a}" = "y" ]] + then + return 0 + else + return 1 + fi +} + +check_install(){ + if [ ! -f "${SERVER_INSTALL_FILE}" ] + then + echo + echo -e "The DayZ server files are not installed. Run '${green}docker-compose run --rm main dayzserver install${default}'" + echo + exit 1 + fi +} + +# Assemble the workshop variables +get_mods(){ + mapfile -t workshopID < "${WORKSHOP_CFG}" + workshoplist="" + for i in "${workshopID[@]}" + do + ID=$(echo ${i} | cut -d: -f1) + workshoplist+=" +workshop_download_item "${release_client_appid}" "${ID} + done +} + +get_mod_id_by_index(){ + # If we were passed a valid mod id, just return it + if [[ -d "${workshopdir}/${1}" ]] + then + echo ${1} + return + fi + X=1 + # Loop over mod list + for i in "${workshopID[@]}" + do + ID=$(echo ${i} | cut -d: -f1) + if [[ ${X} = ${1} ]] + then + echo ${ID} + return + fi + X=$((X+1)) + done +} + +# Get mod name by ID or index +get_mod_name(){ + # Check for an ID + if [ -d "${workshopfolder}/${1}" ] + then + ID=${1} + else + ID=$(get_mod_id_by_index ${1}) + fi + if ! [ -d "${workshopfolder}/${ID}" ] + then + echo "Mod ID ${1} doesn't exist" >&2 + exit 1 + fi + NAME=$(grep name ${workshopfolder}/${ID}/meta.cpp | cut -d '"' -f2 | sed -r 's/\s+//g') + echo ${NAME} +} diff --git a/files/server.sh b/files/server.sh index bd23c4c..c4c168d 100755 --- a/files/server.sh +++ b/files/server.sh @@ -6,7 +6,7 @@ then echo "Creating .bashrc..." cat > .bashrc < .bashrc <&2 - read -s -n 1 a - a=$(echo ${a} | tr A-Z a-z) - echo - if [[ "${a}" = "y" ]] - then - return 0 - else - return 1 - fi -} - -check_install(){ - if [ ! -f "${SERVER_INSTALL_FILE}" ] - then - echo - echo -e "The DayZ server files are not installed. Run '${green}docker-compose run --rm main dayzserver install${default}'" - echo - exit 1 - fi -} - # Ensures all is installed and ready before allowing operations that depends on things being ready. # Installs the initial server config file from its template. # Handles the importing of changes to that template. @@ -245,61 +190,6 @@ force(){ kill -KILL $(pidof DayZServer) } -# Hanle the Steam login information. -login(){ - loadconfig - if [ -f "${STEAM_LOGIN}" ] - then - if prompt_yn "The steam login is already set. Reset it?" - then - rm -f "${STEAM_LOGIN}" - else - echo "Not reset." - exit 0 - fi - fi - if [ ! -f "${STEAM_LOGIN}" ] - then - echo "Setting up Steam credentials" - echo -n "Steam Username (anonymous): " - read steamlogin - if [[ "${steamlogin}" = "" ]] - then - echo "Steam login set to 'anonymous'" - steamlogin="anonymous" - fi - echo "steamlogin=${steamlogin}" > "${STEAM_LOGIN}" - ${STEAMCMD} +force_install_dir ${SERVER_FILES} +login "${steamlogin}" +quit - fi -} - -# "Perform" the Steam login. This just sources the file with the Steam login name. -dologin(){ - loadconfig - if [ -f "${STEAM_LOGIN}" ] - then - source "${STEAM_LOGIN}" - else - echo "No cached Steam credentials. Please configure this now: " - login - fi -} - -# Perform the installation of the server files. -install(){ - loadconfig - if [ ! -f "${SERVER_INSTALL_FILE}" ] || [[ ${1} = "force" ]] - then - mkdir -p "${SERVER_FILES}" - mkdir -p "${SERVER_PROFILE}" - printf "[ ${yellow}DayZ${default} ] Downloading DayZ Server-Files!\n" - dologin - ${STEAMCMD} +force_install_dir ${SERVER_FILES} +login "${steamlogin}" +app_update "${release_server_appid}" validate +quit - else - printf "[ ${lightblue}DayZ${default} ] The server is already installed.\n" - fi -} - # Handle any changes in the server config file by allowing them to be merged after viewing a diff. config(){ if ! diff -q "${SERVER_CFG_DST}" "${SERVER_CFG_SRC}" @@ -319,51 +209,6 @@ config(){ fi } -# Update the server files. -update(){ - dologin - appmanifestfile=${SERVER_FILES}/steamapps/appmanifest_"${release_server_appid}".acf - printf "[ ... ] Checking for update:" - # gets currentbuild - currentbuild=$(grep buildid "${appmanifestfile}" | tr '[:blank:]"' ' ' | tr -s ' ' | cut -d \ -f3) - # Removes appinfo.vdf as a fix for not always getting up to date version info from SteamCMD - if [ -f "${HOME}/Steam/appcache/appinfo.vdf" ] - then - rm -f "${HOME}/Steam/appcache/appinfo.vdf" - fi - # check for new build - availablebuild=$(${STEAMCMD} +login "${steamlogin}" +app_info_update 1 +app_info_print "${release_server_appid}" +quit | \ - sed -n '/branch/,$p' | grep -m 1 buildid | tr -cd '[:digit:]') - if [ -z "${availablebuild}" ] - then - printf "\r[ ${red}FAIL${default} ] Checking for update:\n" - printf "\r[ ${red}FAIL${default} ] Checking for update:: Not returning version info\n" - exit - else - printf "\r[ ${green}OK${default} ] Checking for update:" - fi - # compare builds - if [ "${currentbuild}" != "${availablebuild}" ] || [[ ${1} = "force" ]] - then - printf "\r[ ${green}OK${default} ] Checking for update:: Update available\n" - printf "Update available:\n" - printf "\tCurrent build: ${red}${currentbuild}${default}\n" - printf "\tAvailable build: ${green}${availablebuild}${default}\n" - printf "\thttps://steamdb.info/app/${release_server_appid}/\n" - printf "\nApplying update" - # run update - dologin - ${STEAMCMD} +force_install_dir ${SERVER_FILES} +login "${steamlogin}" +app_update "${release_server_appid}" validate +quit - modupdate - else - printf "\r[ ${green}OK${default} ] Checking for update:: No update available\n" - printf "\nNo update available:\n" - printf "\tCurrent version: ${green}${currentbuild}${default}\n" - printf "\tAvailable version: ${green}${availablebuild}${default}\n" - printf "\thttps://steamdb.info/app/${release_server_appid}/\n\n" - fi -} - # Assemble the workshop variables get_mods(){ mapfile -t workshopID < "${WORKSHOP_CFG}" @@ -414,87 +259,6 @@ get_mod_name(){ echo ${NAME} } -# Update mods -modupdate(){ - echo "Updating mods..." - dologin -# echo ${STEAMCMD} +force_install_dir ${SERVER_FILES} +login "${steamlogin}" ${workshoplist} +quit - ${STEAMCMD} +force_install_dir ${SERVER_FILES} +login "${steamlogin}" ${workshoplist} +quit - # Updated files come in with mixed cases. Fix that. - echo -ne "\nFixing file names..." - find "${workshopfolder}" -depth -exec rename -f 's/(.*)\/([^\/]*)/$1\/\L$2/' {} \; - echo "done" - echo -} - -# Add a mod -add(){ - if [ -d "${workshopfolder}/${1}" ] - then - echo -e "${yellow}Warning: The mod directory ${workshopfolder}/${1} already exists!${default}" - MODNAME=$(get_mod_name ${1}) - fi - if [ -L "${SERVER_FILES}/@${MODNAME}" ] - then - echo -e "${yellow}Warning: The mod symlink ${SERVER_FILES}/@${MODNAME} already exists!${default}" - fi - if grep -qP "\b${1}\b" "${WORKSHOP_CFG}" - then - echo "The mod with id ${1} is already in the workshop configuration." - return - fi - echo "Adding mod id ${1}" - echo "${1}:MODNAME:1" >> ${WORKSHOP_CFG} - dologin - ${STEAMCMD} +force_install_dir ${SERVER_FILES} +login "${steamlogin}" +workshop_download_item "${release_client_appid}" "${1}" +quit - # Make sure the install succeeded - if [ ! -d "${workshopfolder}/${1}" ] - then - echo -e "${red}Mod installation failed: The mod directory ${workshopfolder}/${1} was not created!${default}" - echo "Installation failed! See above (You probably need to use a real Steam login)" - # The mod is added temporarily into the workshop config. Since the installation failed, reemove it instead of updating it. - head -n-1 "${WORKSHOP_CFG}" > /tmp/workshop.cfg.tmp - mv /tmp/workshop.cfg.tmp "${WORKSHOP_CFG}" - return - fi - # Get the name of the newly added mod - MODNAME=$(get_mod_name ${1}) - symlink 1 ${1} "${MODNAME}" - # Lower case all the files in mod directories. - find "${workshopfolder}/${1}" -depth -exec rename -f 's/(.*)\/([^\/]*)/$1\/\L$2/' {} \; - # Copy the key files - copy_keys 1 ${1} - # Set the mod name in the workshop config file, as we don't know this at the start. - sed -i "${WORKSHOP_CFG}" -e "s/${1}:MODNAME/${1}:${MODNAME}/" - echo -e "Mod id ${1} - ${green}${MODNAME}${default} - added" - checkXML ${1} install - checkInstall ${1} install -} - -# Remove a mod -remove(){ - ID=$(get_mod_id_by_index ${1}) - MODNAME=$(get_mod_name ${1}) - checkXML ${ID} uninstall - checkInstall ${ID} uninstall - if [ -d "${workshopfolder}/${ID}" ] - then - echo "Removing directory ${workshopfolder}/${ID}" - rm -rf "${workshopfolder}/${ID}" - fi - if [ -L "${SERVER_FILES}/@${MODNAME}" ] - then - echo "Removing symlink ${SERVER_FILES}/@${MODNAME}" - rm -vf "${SERVER_FILES}/@${MODNAME}" - fi - if grep -q ${ID} "${WORKSHOP_CFG}" - then - echo "Removing workshop file entry" - sed -i "${WORKSHOP_CFG}" -e "/${ID}:/d" - fi - echo -e "Mod id ${ID} - ${red}${MODNAME}${default} - removed" -} - # Activate / Deactivate a mod activate(){ W=${1} @@ -513,9 +277,6 @@ activate(){ if [[ "${ACTIVE}" != "${W}" ]] then sed -i "${WORKSHOP_CFG}" -e "s/${ID}:${MODNAME}:[0-1]/${ID}:${MODNAME}:${W}/" - symlink ${W} ${ID} "${MODNAME}" - copy_keys ${W} ${ID} - checkInstall ${ID} ${UU}install echo -e "Mod id ${ID} - ${COLOR}${MODNAME}${default} ${WW}activated" else echo -e "Mod id ${ID} - ${COLOR}${MODNAME}${default} - is already ${WW}active" @@ -552,30 +313,6 @@ list(){ done } -# Copy mod keys -copy_keys(){ - if [[ ${1} = 1 ]] - then - echo "Copying key files..." - find "${workshopfolder}/${2}" -name "*.bikey" -exec cp "{}" "${SERVER_FILES}/keys/" \; - fi -} - -# Symlink mods -symlink(){ - W=${1} - ID=${2} - NAME=${3} - # Symlink it - if [ ! -L "${SERVER_FILES}/@${NAME}" ] && [[ ${W} = 1 ]] - then - ln -sv ${workshopfolder}/${ID} "${SERVER_FILES}/@${NAME}" - elif [[ "${W}" = "0" ]] - then - rm -vf "${SERVER_FILES}/@${NAME}" - fi -} - # Assemble the mod command line mod_cmd(){ mod_command_line="" @@ -632,22 +369,6 @@ checkXML(){ fi } -checkInstall(){ - # See if this mod id exists in files/mods, and offer to install other server side files if an install.sh is found - if [ -f /files/mods/${1}/${2}.sh ] - then - echo "An ${2}.sh was found for mod id ${1}. Running..." - /files/mods/${1}/${2}.sh - fi - # A generic map install script. Presumes a git repo as the source - if [ -f /files/mods/${1}/install.env ] - then - echo "An ${2}.env was found for mod id ${1}. Performing ${2}..." - source /files/mods/${1}/install.env - /files/mods/install.sh ${1} ${2} - fi - -} # Our internal RCON rcon(){ exec /usr/local/py3rcon/py3rcon.py --gui ~/py3rcon.config.json diff --git a/web/Dockerfile b/web/Dockerfile new file mode 100644 index 0000000..1c99517 --- /dev/null +++ b/web/Dockerfile @@ -0,0 +1,82 @@ +FROM debian:bullseye + +# Set debconf to run non-interactively and agree to the SteamCMD EULA +RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections \ + && echo steam steam/question select "I AGREE" | debconf-set-selections \ + && echo steam steam/license note '' | debconf-set-selections \ + && dpkg --add-architecture i386 + +# Add contrib and backports +RUN sed -i /etc/apt/sources.list -e 's/main/main contrib non-free/' + +RUN echo 'deb http://deb.debian.org/debian bullseye-backports main non-free' >> /etc/apt/sources.list + +# Install _only_ the necessary packages +RUN apt-get update && apt-get -y upgrade && apt-get -y install --no-install-recommends \ + curl \ + ca-certificates \ + gdb \ + git \ + gwenhywfar-tools \ + jq \ + lib32gcc-s1 \ + lib32stdc++6 \ + libcurl4:i386 \ + libsdl2-2.0-0:i386 \ + libsdl2-2.0-0 \ + libcap2 \ + libxml2-utils \ + locales \ + nano \ + procps \ + python3-pip \ + wget \ + rename \ + steamcmd + +RUN update-alternatives --install /usr/bin/python python /usr/bin/python3.9 1 +RUN update-alternatives --install /usr/bin/pip pip /usr/bin/pip3 1 + +# Set the locale +RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && locale-gen +ENV LANG en_US.UTF-8 +ENV LANGUAGE en_US:en +ENV LC_ALL en_US.UTF-8 + +# Steamcmd needs its path added, as it ends up in /usr/games. +# Our server script is bind mounted in /files in docker-compose. +ENV PATH /usr/games:/files:${PATH} + +# Install nodejs +RUN mkdir /usr/local/nvm +ENV NVM_DIR /usr/local/nvm +ENV NODE_VERSION 16.17.0 +RUN echo $NODE_VERSION + +# Install nvm with node and npm +RUN curl https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash \ + && . $NVM_DIR/nvm.sh \ + && nvm install $NODE_VERSION \ + && nvm alias default $NODE_VERSION \ + && nvm use default + +ENV NODE_PATH $NVM_DIR/versions/node/v$NODE_VERSION/lib/node_modules +ENV PATH $NVM_DIR/versions/node/v$NODE_VERSION/bin:$PATH:/work/bin + +# Add py3rcon +RUN cd /usr/local && git clone https://github.com/indepth666/py3rcon.git + +# Setup a non-privileged user +RUN groupadd user && \ + useradd -l -g user user && \ + mkdir -p /home/user /serverfiles/mpmissions /serverfiles/steamapps/workshop/content /web && \ + chown -R user:user /home/user /serverfiles /web + +# Use our non-privileged user +USER user + +# The dayzserver script expects a home directory to itself. +WORKDIR /home/user + +# Run the web server +CMD ["webserver.sh"] diff --git a/web/bin/dz b/web/bin/dz new file mode 100755 index 0000000..ced4a73 --- /dev/null +++ b/web/bin/dz @@ -0,0 +1,302 @@ +#!/usr/bin/env bash + +source /files/dz-common + +# Workshop. This file will store metadata about what mods are installed. +WORKSHOP_CFG="${SERVER_FILES}/workshop.cfg" +if [ ! -f "${WORKSHOP_CFG}" ] +then + touch "${WORKSHOP_CFG}" +fi + +# An array to store Workshop items. Each element contains the mod's ID, name, and state (active or not). +declare -a workshopID +workshopfolder="${SERVER_FILES}/steamapps/workshop/content/${release_client_appid}" + +# Functions + +# Usage +usage(){ + echo -e " +${red}Bad option or arguments! ${yellow}${*}${default} + +Usage: ${green}$(basename $0)${yellow} option [ arg1 [ arg2 ] ] + +Options and arguments: + + add id - Add a DayZ Workshop item by id. Added items become active by default + i|install - Install the DayZ server files + l|list - List Workshop items and their details + g|login - Login to Steam. + m|modupdate - Update the mod files + r|remove id - Remove all files and directories of a Workshop item by id + s|status - Shows the server's status: Running, uptime, mods, parameters, mod parameter, etc. + u|update - Update the server files +${default}" + exit 1 +} + +# Handle the Steam login information. +login(){ + loadconfig + if [ -f "${STEAM_LOGIN}" ] + then + if prompt_yn "The steam login is already set. Reset it?" + then + rm -f "${STEAM_LOGIN}" + else + echo "Not reset." + exit 0 + fi + fi + if [ ! -f "${STEAM_LOGIN}" ] + then + echo "Setting up Steam credentials" + echo -n "Steam Username (anonymous): " + read steamlogin + if [[ "${steamlogin}" = "" ]] + then + echo "Steam login set to 'anonymous'" + steamlogin="anonymous" + fi + echo "steamlogin=${steamlogin}" > "${STEAM_LOGIN}" + ${STEAMCMD} +force_install_dir ${SERVER_FILES} +login "${steamlogin}" +quit + fi +} + +# "Perform" the Steam login. This just sources the file with the Steam login name. +dologin(){ + loadconfig + if [ -f "${STEAM_LOGIN}" ] + then + source "${STEAM_LOGIN}" + else + echo "No cached Steam credentials. Please configure this now: " + login + fi +} + +# Perform the installation of the server files. +install(){ + loadconfig + if [ ! -f "${SERVER_INSTALL_FILE}" ] || [[ ${1} = "force" ]] + then + printf "[ ${yellow}DayZ${default} ] Downloading DayZ Server-Files!\n" + dologin + ${STEAMCMD} +force_install_dir ${SERVER_FILES} +login "${steamlogin}" +app_update "${release_server_appid}" validate +quit + else + printf "[ ${lightblue}DayZ${default} ] The server is already installed.\n" + fi +} + +# Make sure to clean up and report on exit, as these files remain in the container's volume +report() { + rm -f /tmp/mod_command_line /tmp/parameters + echo + echo -e "${yellow}========================================== error.log ==========================================" + find "${SERVER_PROFILE}" -name error.log -exec head {} \; -exec tail -n 30 {} \; -exec rm -f {} \; + echo + echo -e "========================================== script*.log ========================================" + find "${SERVER_PROFILE}" -name "script*.log" -exec head {} \; -exec tail -n 30 {} \; -exec rm -f {} \; + echo + echo -e "========================================== *.RPT ==============================================" + find "${SERVER_PROFILE}" -name "*.RPT" -exec ls -la {} \; -exec tail -n 30 {} \; -exec rm -f {} \; + echo + echo -e "========================================== End log ======================================${default}" +} + +# Update the server files. +update(){ + dologin + appmanifestfile=${SERVER_FILES}/steamapps/appmanifest_"${release_server_appid}".acf + printf "[ ... ] Checking for update:" + # gets currentbuild + currentbuild=$(grep buildid "${appmanifestfile}" | tr '[:blank:]"' ' ' | tr -s ' ' | cut -d \ -f3) + # Removes appinfo.vdf as a fix for not always getting up to date version info from SteamCMD + if [ -f "${HOME}/Steam/appcache/appinfo.vdf" ] + then + rm -f "${HOME}/Steam/appcache/appinfo.vdf" + fi + # check for new build + availablebuild=$(${STEAMCMD} +login "${steamlogin}" +app_info_update 1 +app_info_print "${release_server_appid}" +quit | \ + sed -n '/branch/,$p' | grep -m 1 buildid | tr -cd '[:digit:]') + if [ -z "${availablebuild}" ] + then + printf "\r[ ${red}FAIL${default} ] Checking for update:\n" + printf "\r[ ${red}FAIL${default} ] Checking for update:: Not returning version info\n" + exit + else + printf "\r[ ${green}OK${default} ] Checking for update:" + fi + # compare builds + if [ "${currentbuild}" != "${availablebuild}" ] || [[ ${1} = "force" ]] + then + printf "\r[ ${green}OK${default} ] Checking for update:: Update available\n" + printf "Update available:\n" + printf "\tCurrent build: ${red}${currentbuild}${default}\n" + printf "\tAvailable build: ${green}${availablebuild}${default}\n" + printf "\thttps://steamdb.info/app/${release_server_appid}/\n" + printf "\nApplying update" + # run update + dologin + ${STEAMCMD} +force_install_dir ${SERVER_FILES} +login "${steamlogin}" +app_update "${release_server_appid}" validate +quit + modupdate + else + printf "\r[ ${green}OK${default} ] Checking for update:: No update available\n" + printf "\nNo update available:\n" + printf "\tCurrent version: ${green}${currentbuild}${default}\n" + printf "\tAvailable version: ${green}${availablebuild}${default}\n" + printf "\thttps://steamdb.info/app/${release_server_appid}/\n\n" + fi +} + +# Update mods +modupdate(){ + echo "Updating mods..." + dologin +# echo ${STEAMCMD} +force_install_dir ${SERVER_FILES} +login "${steamlogin}" ${workshoplist} +quit + ${STEAMCMD} +force_install_dir ${SERVER_FILES} +login "${steamlogin}" ${workshoplist} +quit + # Updated files come in with mixed cases. Fix that. + echo -ne "\nFixing file names..." + find "${workshopfolder}" -depth -exec rename -f 's/(.*)\/([^\/]*)/$1\/\L$2/' {} \; + echo "done" + echo +} + +# List mods +list(){ + # The state may have changed since we started + get_mods + if [[ "${workshopID[@]}" = "" ]] + then + return + fi + X=1 + spaces=" " + echo -e "\n ID Name Active URL Size" + echo "------------------------------------------------------------------------------------------------------------------------" + for i in "${workshopID[@]}" + do + ID=$(echo ${i} | cut -d: -f1) + NAME=$(echo ${i} | cut -d: -f2) + ACTIVE=$(echo ${i} | cut -d: -f3) + SIZE=$(du -sh ${SERVER_FILES}/steamapps/workshop/content/221100/${ID} | awk '{print $1}') + if [[ ${ACTIVE} = "1" ]] + then + C="${green}" + else + C="${red}" + fi + printf "${C}%.3d %s %.23s %s %s https://steamcommunity.com/sharedfiles/filedetails/?id=%s %s${default}\n" ${X} ${ID} "${NAME}" "${spaces:${#NAME}+1}" ${ACTIVE} ${ID} ${SIZE} + X=$((X+1)) + done +} + +# Display the status of the provisioning container +status(){ + INSTALLED="${NO}" + LOGGED_IN="${NO}" + RUNNING="${NO}" + + # DayZ Server files installation + if [ -f "${SERVER_INSTALL_FILE}" ] + then + INSTALLED="${YES}" + fi + # Logged into Steam + if [ -f "${STEAM_LOGIN}" ] + then + LOGGED_IN="${YES}" + if grep -q anonymous "${STEAM_LOGIN}" + then + ANONYMOUS="${yellow}(as anonymous)${default}" + else + ANONYMOUS="${green}(not anonymous)${default}" + fi + fi + # Running or not + if pidof DayZServer > /dev/null + then + # Uptime + D=$(date +%s) + F=$(date +%s -r ${SERVER_PROFILE}/server_console.log) + DAYS=$(( (${D} - ${F}) / 86400 )) +# UPTIME=$(date --date="$(( ${D} - ${F} ))" +"${DAYS} days %H:%M:%S") + UPTIME="${DAYS} days "$(date -d@$(($(date +%s) - $(date +%s -r ${SERVER_PROFILE}/server_console.log))) -u +"%H hours %M minutes %S seconds") + + RUNNING="${YES}\nUptime: ${green}${UPTIME}${default}" + # Current parameters + RUNNING="${RUNNING}\nRunning Parameters: $(cat /tmp/parameters)\nRunning mod parameter: $(cat /tmp/mod_command_line)" + fi + mod_cmd + MAP="none" + # Map name + if [[ -f ${SERVER_CFG_DST} ]] + then + MAP=$(grep -E "template=" ${SERVER_CFG_DST} | grep -vE "^//") + fi + # Number of mods plus the list denoting on or off + echo -ne " +Logged in to Steam: ${LOGGED_IN} ${ANONYMOUS} +Server files installed: ${INSTALLED}" + if [[ "${INSTALLED}" = "${NO}" ]] + then + echo + echo + exit 0 + fi + echo -ne " +Mods: " + MODS=$(list) + if [[ ${MODS} == "" ]] + then + echo -n "none" + fi + echo -e "${MODS} +Server running: ${RUNNING} +Working parameters: ${parameters} +Working mod parameter: ${mod_command_line}" + if [[ "${INSTALLED}" = "${YES}" ]] + then + MAP=$(grep template ${SERVER_CFG_DST} | grep -v "^//" | cut -d= -f2 | cut -d\; -f1) + echo "Map: ${MAP}" + fi +} + +# Capture the first argument and shift it off so we can pass $@ to every function +C=${1} +shift || { + usage +} + +get_mods + +case "${C}" in + add) + add "${@}" + ;; + i|install) + install "${@}" + ;; + l|list) + list "${@}" + ;; + login) + login "${@}" + ;; + m|modupdate) + modupdate "${@}" + ;; + r|remove) + remove "${@}" + ;; + s|status) + status "${@}" + ;; + u|update) + update "${@}" + ;; + *) + usage "$*" + ;; +esac diff --git a/web/index.js b/web/index.js new file mode 100644 index 0000000..63820ce --- /dev/null +++ b/web/index.js @@ -0,0 +1,10 @@ +const express = require('express') +const path = require('path') +const app = express() +const port = 8000 + +app.use('/', express.static(path.join(__dirname, 'root'))) + +app.listen(port, () => { + console.log(`Listening on port ${port}`) +}) diff --git a/web/package-lock.json b/web/package-lock.json new file mode 100644 index 0000000..948f048 --- /dev/null +++ b/web/package-lock.json @@ -0,0 +1,1018 @@ +{ + "name": "web", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "web", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "express": "^4.18.2" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/get-intrinsic": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + } + }, + "dependencies": { + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + } + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + } + }, + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "requires": { + "safe-buffer": "5.2.1" + } + }, + "content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" + }, + "cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + }, + "destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" + }, + "express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "requires": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + } + }, + "finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + } + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "get-intrinsic": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" + }, + "object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==" + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "requires": { + "ee-first": "1.1.1" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + } + }, + "qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "requires": { + "side-channel": "^1.0.4" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "requires": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "dependencies": { + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + } + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" + } + } +} diff --git a/web/package.json b/web/package.json new file mode 100644 index 0000000..14398df --- /dev/null +++ b/web/package.json @@ -0,0 +1,15 @@ +{ + "name": "web", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "express": "^4.18.2" + } +} diff --git a/web/root/index.html b/web/root/index.html new file mode 100644 index 0000000..c0941c6 --- /dev/null +++ b/web/root/index.html @@ -0,0 +1,23 @@ + + + + + DayZ Docker Server + + + + + +
+
+

DayZ Docker Server

+
+
+ + +