diff --git a/README.md b/README.md index 2979a447..cd63f607 100644 --- a/README.md +++ b/README.md @@ -134,7 +134,7 @@ By default, the container will download the latest version of the "vanilla" [Min * [Running on RaspberryPi](#running-on-raspberrypi) * [Contributing](#contributing) - + @@ -846,30 +846,35 @@ values. > **NOTE** it is very important to set this with servers exposed to the internet where you want only limited players to join. -To whitelist players for your Minecraft server, pass the Minecraft usernames separated by commas via the `WHITELIST` environment variable, such as +To whitelist players for your Minecraft server, you can: +- Provide the url or path to a whitelist file via `WHITELIST_FILE` environment variable + `docker run -d -e WHITELIST_FILE=/extra/whitelist.json ...` +- Provide a list of usernames and/or UUIDs separated by commas via the `WHITELIST` environment variable + `docker run -d -e WHITELIST=user1,uuid2 ...` - docker run -d -e WHITELIST=user1,user2 ... +To enforce the whitelist and auto-kick players not included in whitelist configuration, set `ENFORCE_WHITELIST=TRUE`. **By default** any user can join your Minecraft server if it's publicly accessible, regardless of your whitelist configuration. -or +If whitelist configuration already exists, `WHITELIST_FILE` will not be retrieved and any usernames in `WHITELIST` are **added** to the whitelist configuration. You can enforce regeneration of the whitelist on each server startup by setting `OVERRIDE_WHITELIST` to "true". This will delete the whitelist file before processing whitelist configuration. - docker run -d -e WHITELIST=uuid1,uuid2 ... +> NOTE: You can provide both `WHITELIST_FILE` and `WHITELIST`, which are processed in that order. -If the `WHITELIST` environment variable is not used, any user can join your Minecraft server if it's publicly accessible. +> NOTE: UUIDs passed via `WHITELIST` need to be the dashed variant, otherwise it not be recognised and instead added as a username. -> NOTE: When using uuids in the whitelist, please make sure it is the dashed variant otherwise it will not parse correctly. +> If running Minecraft 1.7.5 or earlier, these variables will apply to `white-list.txt`, with 1.7.6 implementing support for `whitelist.json`. Make sure your `WHITELIST_FILE` is in the appropriate format. -> NOTE: When `WHITELIST` is used the server properties `white-list` and `whitelist` will automatically get set to `true`. +If either `WHITELIST_FILE` or `WHITELIST` is provided, the server property `white-list` is automatically set to `true`, enabline whitelist functionality. Alternatively you can set `ENABLE_WHITELIST=TRUE` to only set the server property `white-list` without modifying the whitelist file. In this case the whitelist can be managed using the `whitelist add` and `whitelist remove` commands. Remember you can set enforcement via the `ENFORCE_WHITELIST` variable. -> By default, the players in `WHITELIST` are **added** to the final `whitelist.json` file by the Minecraft server. If you set `OVERRIDE_WHITELIST` to "true" then the `whitelist.json` file will be recreated on each server startup. - -Alternatively, you can set `ENABLE_WHITELIST=true` to only set the server properties `white-list` and `whitelist` without modifying the whitelist file. In this case the whitelist is solely managed using the `whitelist add` and `whitelist remove` commands. ### Op/Administrator Players -To add more "op" (aka adminstrator) users to your Minecraft server, pass the Minecraft usernames separated by commas via the `OPS` environment variable, such as +Similar to the whitelist, to add users as operators (aka adminstrators) to your Minecraft server, you can: +- Provide te url or path to an ops file via `OPS_FILE` environment variable + `docker run -d -e OPS_FILE=https://config.example.com/extra/ops.json ...` +- Provide a list of usernames and/or UUIDs separated by commas via the `OPS` environment variable + `docker run -d -e OPS=user1,uuid2 ...` - docker run -d -e OPS=user1,user2 ... +If ops configuration already exists, `OPS_FILE` will not be retrieved and any usernames in `OPS` are **added** to the ops configuration. You can enforce regeneration of the ops configuration on each server startup by setting `OVERRIDE_OPS` to "true". This will delete the ops file before processing ops configuration. -> By default, the players in `OPS` are **added** to the final `ops.json` file by the Minecraft server. If you set `OVERRIDE_OPS` to "true" then the `ops.json` file will be recreated on each server startup. +> Similar to whitelists, you can provide both `OPS_FILE` and `OPS`, and Minecraft 1.7.5 or earlier will use `ops.txt` rather than `ops.json`. ### Server icon @@ -1327,6 +1332,8 @@ If you would like to `docker attach` to the Minecraft server console with color > This will bypass graceful server shutdown handling when using `docker stop`, so be sure the server console's `stop` command. > > Make to enable stdin and tty with `-it` when using `docker run` or `stdin_open: true` and `tty: true` when using docker compose. +> +> This feature is incompatible with Autopause and cannot be set when `ENABLE_AUTOPAUSE=true`. ### Server Shutdown Options @@ -1444,6 +1451,8 @@ Enable the Autopause functionality by setting: -e ENABLE_AUTOPAUSE=TRUE ``` +Autopause is not compatible with `EXEC_DIRECTLY=true` and the two cannot be set together. + The following environment variables define the behaviour of auto-pausing: * `AUTOPAUSE_TIMEOUT_EST`, default `3600` (seconds) describes the time between the last client disconnect and the pausing of the process (read as timeout established) diff --git a/docker-versions-create.sh b/docker-versions-create.sh index 5a2f8226..e82dc7bf 100755 --- a/docker-versions-create.sh +++ b/docker-versions-create.sh @@ -130,3 +130,28 @@ EOL fi done + +if [[ $tag ]]; then + if [ -f "$HOME/.github.env" ]; then + source "$HOME/.github.env" + if [[ $GITHUB_TOKEN ]] + then + auth=(-u ":$GITHUB_TOKEN") + base=https://api.github.com + : "${owner:=itzg}" + : "${repo:=docker-minecraft-server}" + read -r -d '' releaseBody << EOF + { + "tag_name": "$tag", + "name": "$tag", + "generate_release_notes": true + } +EOF + if ! echo curl "${auth[@]}" -H "Accept: application/vnd.github.v3+json" \ + "${base}/repos/${owner}/${repo}/releases" -d "$releaseBody"; then + echo "ERROR failed to create github release $tag" + exit 1 + fi + fi + fi +fi \ No newline at end of file diff --git a/scripts/start-configuration b/scripts/start-configuration index 2536207d..450bea0f 100755 --- a/scripts/start-configuration +++ b/scripts/start-configuration @@ -32,6 +32,10 @@ if [ ! -e /data/eula.txt ]; then writeEula fi +if isTrue "${ENABLE_AUTOPAUSE}" && isTrue "${EXEC_DIRECTLY:-false}"; then + log "EXEC_DIRECTLY=true is incompatible with ENABLE_AUTOPAUSE=true" + exit 1 +fi if [[ $PROXY ]]; then export http_proxy="$PROXY" diff --git a/scripts/start-deployAirplane b/scripts/start-deployAirplane index 1fde1263..45e06228 100755 --- a/scripts/start-deployAirplane +++ b/scripts/start-deployAirplane @@ -1,10 +1,11 @@ #!/bin/bash -set -euo pipefail -IFS=$'\n\t' . ${SCRIPTS:-/}start-utils +set -euo pipefail isDebugging && set -x +IFS=$'\n\t' + if [ "${VERSION}" != "LATEST" ] && [ "${VERSION}" != "1.16" ] && [ "${VERSION}" != "1.17" ] && [ "${VERSION}" != "PURPUR" ] && [ "${VERSION}" != "PURPUR-1.16" ] ; then log "ERROR: Airplane server type only supports VERSION=LATEST, VERSION=1.17, VERSION=1.16, VERSION=PURPUR or VERSION=PURPUR-1.16. Note that these are branches, not #.#.# versions." exit 1 @@ -35,6 +36,12 @@ log "Using Airplane-${AIRPLANE_BRANCH} branch" export SERVER=airplane-${AIRPLANE_BRANCH}-${AIRPLANE_BUILD}.jar +log "Removing old Airplane versions ..." +shopt -s nullglob +for f in airplane-*.jar; do + [[ $f != $SERVER ]] && rm $f +done + if [ ! -f "$SERVER" ] || isTrue "${FORCE_REDOWNLOAD:-false}"; then downloadUrl="https://ci.tivy.ca/job/Airplane-${AIRPLANE_BRANCH}/${AIRPLANE_BUILD}/artifact/launcher-${AIRPLANE_TYPE}.jar" log "Downloading Airplane from $downloadUrl ..." diff --git a/scripts/start-finalExec b/scripts/start-finalExec index 78603ebc..e34222c6 100755 --- a/scripts/start-finalExec +++ b/scripts/start-finalExec @@ -3,28 +3,93 @@ . ${SCRIPTS:-/}start-utils isDebugging && set -x -if [ -n "$OPS" ]; then - log "Updating ops" - rm -f /data/ops.txt.converted - echo $OPS | awk -v RS=, '{print}' > /data/ops.txt -fi -if isTrue "${OVERRIDE_OPS}"; then - log "Recreating ops.json file at server startup" - rm -f /data/ops.json +if versionLessThan 1.7.6; then + opsFile=ops.txt + whitelistFile=white-list.txt +else + opsFile=ops.json + whitelistFile=whitelist.json fi -if [ -n "$WHITELIST" ]; then - log "Updating whitelist" - rm -f /data/white-list.txt.converted - if [[ $WHITELIST == *"-"* ]]; then - echo $WHITELIST | awk -v RS=, '{print}' | xargs -l -i curl -s https://playerdb.co/api/player/minecraft/{} | jq -r '.["data"]["player"] | {"uuid": .id, "name": .username}' | jq -s . > "whitelist.json" +function process_user_file() { + local output=$1 + local source=$2 + + if isURL "$source"; then + log "Downloading $output from $source" + if ! get -o /data/$output "$source"; then + log "ERROR: failed to download from $source" + exit 2 + fi else - echo $WHITELIST | awk -v RS=, '{print}' > /data/white-list.txt + log "Copying $output from $source" + if ! cp "$source" /data/$output; then + log "ERROR: failed to copy from $source" + exit 1 + fi fi +} + +function process_user_csv() { + local output=$1 + local list=$2 + local playerDataList + + if [[ "$output" == *"ops"* ]]; then + # Extra data for ops.json + userData='{"uuid": .id, "name": .username, "level": 4}' + else + userData='{"uuid": .id, "name": .username}' + fi + + log "Updating ${output%.*}" + for i in ${list//,/ } + do + if [ -e "$output" ] && grep -q "$i" "$output"; then + log "$i already present in $output, skipping" + continue + fi + if ! playerData=$(get "https://playerdb.co/api/player/minecraft/$i" | jq -re ".data.player"); then + log "WARNING: Could not lookup user $i for ${output} addition" + else + playerDataList=$playerDataList$(echo $playerData | jq -r "$userData") + fi + done + local newUsers=$(echo $playerDataList | jq -s .) + if [[ $output =~ .*\.txt ]]; then + # username list for txt config (Minecraft <= 1.7.5) + echo $newUsers | jq -r '.[].name' >> /data/${output} + sort -u /data/${output} -o /data/${output} + elif [ -e /data/${output} ]; then + # Merge with existing json file + local currentUsers=$(cat /data/${output}) + jq --argjson current "$currentUsers" --argjson new "$newUsers" -n '$new + $current | unique_by(.uuid)' > /data/${output} + else + # New json file + echo $newUsers > /data/${output} + fi +} + +if isTrue "${OVERRIDE_OPS}"; then + log "Recreating ${opsFile} file at server startup" + rm -f /data/${opsFile} fi +if [ -n "${OPS_FILE}" ] && [ ! -e "/data/${opsFile}" ]; then + process_user_file ${opsFile} "$OPS_FILE" +fi +if [ -n "${OPS}" ]; then + process_user_csv ${opsFile} "$OPS" +fi + if isTrue "${OVERRIDE_WHITELIST}"; then - log "Recreating whitelist.json file at server startup" - rm -f /data/whitelist.json + log "Recreating ${whitelistFile} file at server startup" + rm -f /data/${whitelistFile} +fi +if [ -n "${WHITELIST_FILE}" ] && [ ! -e "/data/${whitelistFile}" ]; then + process_user_file ${whitelistFile} "$WHITELIST_FILE" +fi +if [ -n "${WHITELIST}" ]; then + process_user_csv ${whitelistFile} "$WHITELIST" fi if [ -n "$ICON" ]; then @@ -96,7 +161,10 @@ patchLog4jConfig() { } # Patch Log4j remote code execution vulnerability -if isFamily VANILLA && versionLessThan 1.12; then +# See https://www.minecraft.net/en-us/article/important-message--security-vulnerability-java-edition +if versionLessThan 1.7; then + : # No patch required here. +elif isFamily VANILLA && versionLessThan 1.12; then patchLog4jConfig log4j2_17-111.xml https://launcher.mojang.com/v1/objects/dd2b723346a8dcd48e7f4d245f6bf09e98db9696/log4j2_17-111.xml elif isFamily VANILLA && versionLessThan 1.17; then patchLog4jConfig log4j2_112-116.xml https://launcher.mojang.com/v1/objects/02937d122c86ce73319ef9975b58896fc1b491d1/log4j2_112-116.xml diff --git a/scripts/start-setupServerProperties b/scripts/start-setupServerProperties index 0855da5e..0febd096 100755 --- a/scripts/start-setupServerProperties +++ b/scripts/start-setupServerProperties @@ -33,15 +33,18 @@ function setServerProp { } function customizeServerProps { - if [ -n "$WHITELIST" ] || isTrue "${ENABLE_WHITELIST:-false}"; then - log "Creating whitelist" - setServerPropValue "whitelist" "true" + # Whitelist processing + if [ -n "$WHITELIST" ] || [ -n "$WHITELIST_FILE" ] || isTrue "${ENABLE_WHITELIST:-false}"; then + log "Enabling whitelist functionality" setServerPropValue "white-list" "true" else - log "Disabling whitelist" - setServerPropValue "whitelist" "false" + log "Disabling whitelist functionality" setServerPropValue "white-list" "false" fi + setServerProp "enforce-whitelist" ENFORCE_WHITELIST + if [[ $(grep "enforce-whitelist" $SERVER_PROPERTIES) != *true ]]; then + log "WARNING: whitelist enabled but not enforced. Set ENFORCE_WHITELIST=TRUE or update 'enforce-whitelist' in server.properties to enforce the whitelist." + fi # If not provided, generate a reasonable default message-of-the-day, # which shows up in the server listing in the client @@ -104,7 +107,6 @@ function customizeServerProps { setServerProp "op-permission-level" OP_PERMISSION_LEVEL setServerProp "prevent-proxy-connections" PREVENT_PROXY_CONNECTIONS setServerProp "use-native-transport" USE_NATIVE_TRANSPORT - setServerProp "enforce-whitelist" ENFORCE_WHITELIST setServerProp "simulation-distance" SIMULATION_DISTANCE setServerPropValue "motd" "$(echo "$MOTD" | mc-image-helper asciify)" [[ $LEVEL_TYPE ]] && setServerPropValue "level-type" "${LEVEL_TYPE^^}"