diff --git a/Dockerfile b/Dockerfile index a0eda3227..ff8c9e24b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -132,6 +132,10 @@ ENV DEBIAN_FRONTEND="noninteractive" # Ensure we run all scripts through 'bash' rather than 'sh' SHELL ["/bin/bash", "-c"] +# Set www-data to be RUNTIME_UID/RUNTIME_GID +RUN groupmod --gid ${RUNTIME_GID} www-data \ + && usermod --uid ${RUNTIME_UID} --gid ${RUNTIME_GID} www-data + RUN set -ex \ && mkdir -pv /var/www/ \ && chown -R ${RUNTIME_UID}:${RUNTIME_GID} /var/www diff --git a/app/Http/Controllers/FederationController.php b/app/Http/Controllers/FederationController.php index 9155e9aed..5738292f1 100644 --- a/app/Http/Controllers/FederationController.php +++ b/app/Http/Controllers/FederationController.php @@ -72,14 +72,14 @@ class FederationController extends Controller return response()->json($res, 200, [], JSON_UNESCAPED_SLASHES); } - if(str_starts_with($resource, 'https://')) { - if(str_starts_with($resource, 'https://' . $domain . '/users/')) { - $username = str_replace('https://' . $domain . '/users/', '', $resource); - if(strlen($username) > 15) { + if (str_starts_with($resource, 'https://')) { + if (str_starts_with($resource, 'https://'.$domain.'/users/')) { + $username = str_replace('https://'.$domain.'/users/', '', $resource); + if (strlen($username) > 15) { return response('', 400); } $stripped = str_replace(['_', '.', '-'], '', $username); - if(!ctype_alnum($stripped)) { + if (! ctype_alnum($stripped)) { return response('', 400); } $key = 'federation:webfinger:sha256:url-username:'.$username; @@ -92,6 +92,7 @@ class FederationController extends Controller } $webfinger = (new Webfinger($profile))->generate(); Cache::put($key, $webfinger, 1209600); + return response()->json($webfinger, 200, [], JSON_UNESCAPED_SLASHES) ->header('Access-Control-Allow-Origin', '*'); } else { diff --git a/app/Util/Lexer/RestrictedNames.php b/app/Util/Lexer/RestrictedNames.php index 4224ae96c..9d88b0da1 100644 --- a/app/Util/Lexer/RestrictedNames.php +++ b/app/Util/Lexer/RestrictedNames.php @@ -4,376 +4,378 @@ namespace App\Util\Lexer; class RestrictedNames { - public static $additional = [ - 'autoconfig', - 'blog', - 'broadcasthost', - 'copyright', - 'download', - 'domainadmin', - 'domainadministrator', - 'errors', - 'events', - 'example', - 'faq', - 'faqs', - 'features', - 'ftp', - 'guest', - 'guests', - 'hostmaster', - 'hostmaster', - 'imap', - 'info', - 'information', - 'is', - 'isatap', - 'it', - 'localdomain', - 'localhost', - 'mail', - 'mailer-daemon', - 'mailerdaemon', - 'marketing', - 'me', - 'mis', - 'mx', - 'no-reply', - 'nobody', - 'noc', - 'noreply', - 'ns0', - 'ns1', - 'ns2', - 'ns3', - 'ns4', - 'ns5', - 'ns6', - 'ns7', - 'ns8', - 'ns9', - 'owner', - 'pop', - 'pop3', - 'postmaster', - 'pricing', - 'root', - 'sales', - 'security', - 'signin', - 'signout', - 'smtp', - 'src', - 'ssladmin', - 'ssladministrator', - 'sslwebmaster', - 'sys', - 'sysadmin', - 'system', - 'tutorial', - 'tutorials', - 'usenet', - 'uucp', - 'webmaster', - 'wpad', - ]; + public static $additional = [ + 'autoconfig', + 'blog', + 'broadcasthost', + 'copyright', + 'download', + 'domainadmin', + 'domainadministrator', + 'errors', + 'events', + 'example', + 'faq', + 'faqs', + 'features', + 'ftp', + 'guest', + 'guests', + 'hostmaster', + 'hostmaster', + 'imap', + 'info', + 'information', + 'is', + 'isatap', + 'it', + 'localdomain', + 'localhost', + 'mail', + 'mailer-daemon', + 'mailerdaemon', + 'marketing', + 'me', + 'mis', + 'mx', + 'no-reply', + 'nobody', + 'noc', + 'noreply', + 'ns0', + 'ns1', + 'ns2', + 'ns3', + 'ns4', + 'ns5', + 'ns6', + 'ns7', + 'ns8', + 'ns9', + 'owner', + 'pop', + 'pop3', + 'postmaster', + 'pricing', + 'root', + 'sales', + 'security', + 'signin', + 'signout', + 'smtp', + 'src', + 'ssladmin', + 'ssladministrator', + 'sslwebmaster', + 'sys', + 'sysadmin', + 'system', + 'tutorial', + 'tutorials', + 'usenet', + 'uucp', + 'webmaster', + 'wpad', + ]; - public static $reserved = [ - // Reserved for instance admin - 'admin', - 'administrator', + public static $reserved = [ + // Reserved for instance admin + 'admin', + 'administrator', - // Static Assets - 'assets', - 'public', - 'storage', - 'htaccess', - '.htaccess', - 'favicon.ico', - 'embed.js', - 'index.php', - 'manifest.json', - 'mix-manifest.json', - 'robots.txt', + // Static Assets + 'assets', + 'public', + 'storage', + 'htaccess', + '.htaccess', + 'favicon.ico', + 'embed.js', + 'index.php', + 'manifest.json', + 'mix-manifest.json', + 'robots.txt', - // Laravel Horizon - 'horizon', + // Laravel Horizon + 'horizon', - // Reserved routes - 'a', - 'app', - 'about', - 'aboutus', - 'about-us', - 'abuse', - 'actor', - 'actors', - 'account', - 'admins', - 'api', - 'audio', - 'auth', - 'avatar', - 'avatars', - 'b', - 'bartender', - 'broadcast', - 'broadcaster', - 'booth', - 'bouncer', - 'browse', - 'c', - 'cdn', - 'circle', - 'circles', - 'checkpoint', - 'collection', - 'collections', - 'community', - 'communities', - 'contact', - 'contact-us', - 'contact_us', - 'costar', - 'costars', - 'css', - 'd', - 'dashboard', - 'delete', - 'deleted', - 'deleting', - 'dmca', - 'db', - 'deck', - 'dev', - 'developer', - 'developers', - 'discover', - 'discovers', - 'dj', - 'doc', - 'docs', - 'docs', - 'drive', - 'drives', - 'driver', - 'e', - 'embed', - 'email', - 'emails', - 'emoji', - 'emojis', - 'error', - 'explore', - 'export', - 'exports', - 'external', - 'f', - 'fedi', - 'fediverse', - 'feed', - 'featured', - 'font', - 'fonts', - 'follow', - 'follows', - 'followme', - 'follow-me', - 'follow_me', - 'g', - 'go', - 'gdpr', - 'graph', - 'ghost', - 'ghosts', - 'global', - 'group', - 'groups', - 'h', - 'header', - 'headers', - 'home', - 'help', - 'helpcenter', - 'help-center', - 'help_center', - 'help_center_', - 'help-center-', - 'help-center_', - 'help_center-', - 'i', - 'instance', - 'inbox', - 'img', - 'imgs', - 'image', - 'images', - 'invite', - 'invites', - 'import', - 'imports', - 'j', - 'join', - 'js', - 'k', - 'key', - 'l', - 'lang', - 'language', - '_lang', - '_language', - 'lab', - 'labs', - 'legal', - 'link', - 'live', - 'look', - 'look-back', - 'loop', - 'loops', - 'location', - 'locations', - 'login', - 'logout', - 'm', - 'media', - 'mini', - 'micro', - 'menu', - 'music', - 'my2020', - 'my2021', - 'my2022', - 'my2023', - 'my2024', - 'my2025', - 'my2026', - 'my2027', - 'my2028', - 'my2029', - 'my2030', - 'my', - 'n', - 'news', - 'new', - 'news', - 'news', - 'newsfeed', - 'newsroom', - 'newsrooms', - 'news-room', - 'news-rooms', - 'network', - 'networks', - 'o', - 'oauth', - 'official', - 'p', - 'page', - 'pages', - 'pin', - 'pins', - 'photo', - 'photos', - 'password', - 'portfolio', - 'portfolios', - 'pre', - 'post', - 'privacy', - 'private', - 'q', - 'quote', - 'query', - 'r', - 'redirect', - 'redirects', - 'register', - 'registers', - 'review', - 'reviews', - 'reset', - 'report', - 'results', - 'reports', - 'robot', - 'robots', - 's', - 'sc', - 'search', - 'sell', - 'send', - 'settings', - 'short', - 'shortcode', - 'status', - 'statuses', - 'site', - 'sites', - 'stage', - 'static', - 'story', - 'stories', - 'support', - 'svg', - 'svgs', - 't', - 'terms', - 'telescope', - 'timeline', - 'timelines', - 'tour', - 'tv', - 'u', - 'user', - 'users', - 'username', - 'usernames', - 'v', - 'valet', - 'video', - 'videos', - 'vendor', - 'w', - 'waiter', - 'wall', - 'whats-new', - 'whatsnew', - 'whatnew', - 'whats-news', - 'web', - 'ws', - 'wss', - 'www', - 'x', - 'y', - 'year', - 'year-in-review', - 'z', - '400', - '401', - '403', - '404', - '500', - '503', - '504', - ]; + // Reserved routes + 'a', + 'app', + 'about', + 'aboutus', + 'about-us', + 'abuse', + 'actor', + 'actors', + 'account', + 'admins', + 'api', + 'audio', + 'auth', + 'avatar', + 'avatars', + 'b', + 'bartender', + 'broadcast', + 'broadcaster', + 'booth', + 'bouncer', + 'browse', + 'c', + 'cdn', + 'circle', + 'circles', + 'checkpoint', + 'collection', + 'collections', + 'community', + 'communities', + 'contact', + 'contact-us', + 'contact_us', + 'costar', + 'costars', + 'css', + 'd', + 'dashboard', + 'delete', + 'deleted', + 'deleting', + 'dmca', + 'db', + 'deck', + 'dev', + 'developer', + 'developers', + 'discover', + 'discovers', + 'dj', + 'doc', + 'docs', + 'docs', + 'drive', + 'drives', + 'driver', + 'e', + 'embed', + 'email', + 'emails', + 'emoji', + 'emojis', + 'error', + 'explore', + 'export', + 'exports', + 'external', + 'f', + 'fedi', + 'fediverse', + 'feed', + 'featured', + 'font', + 'fonts', + 'follow', + 'follows', + 'followme', + 'follow-me', + 'follow_me', + 'g', + 'go', + 'gdpr', + 'graph', + 'ghost', + 'ghosts', + 'global', + 'group', + 'groups', + 'h', + 'header', + 'headers', + 'home', + 'help', + 'help.center', + 'helpcenter', + 'help-center', + 'help_center', + 'help_center_', + 'help-center-', + 'help-center_', + 'help_center-', + 'i', + 'instance', + 'inbox', + 'img', + 'imgs', + 'image', + 'images', + 'invite', + 'invites', + 'import', + 'imports', + 'intent', + 'j', + 'join', + 'js', + 'k', + 'key', + 'l', + 'lang', + 'language', + '_lang', + '_language', + 'lab', + 'labs', + 'legal', + 'link', + 'live', + 'look', + 'look-back', + 'loop', + 'loops', + 'location', + 'locations', + 'login', + 'logout', + 'm', + 'media', + 'mini', + 'micro', + 'menu', + 'music', + 'my2020', + 'my2021', + 'my2022', + 'my2023', + 'my2024', + 'my2025', + 'my2026', + 'my2027', + 'my2028', + 'my2029', + 'my2030', + 'my', + 'n', + 'news', + 'new', + 'news', + 'news', + 'newsfeed', + 'newsroom', + 'newsrooms', + 'news-room', + 'news-rooms', + 'network', + 'networks', + 'o', + 'oauth', + 'official', + 'p', + 'page', + 'pages', + 'pin', + 'pins', + 'photo', + 'photos', + 'password', + 'portfolio', + 'portfolios', + 'pre', + 'post', + 'privacy', + 'private', + 'q', + 'quote', + 'query', + 'r', + 'redirect', + 'redirects', + 'register', + 'registers', + 'review', + 'reviews', + 'reset', + 'report', + 'results', + 'reports', + 'robot', + 'robots', + 's', + 'sc', + 'search', + 'sell', + 'send', + 'settings', + 'short', + 'shortcode', + 'status', + 'statuses', + 'site', + 'sites', + 'stage', + 'static', + 'story', + 'stories', + 'support', + 'svg', + 'svgs', + 't', + 'terms', + 'telescope', + 'timeline', + 'timelines', + 'tour', + 'tv', + 'u', + 'user', + 'users', + 'username', + 'usernames', + 'v', + 'valet', + 'video', + 'videos', + 'vendor', + 'w', + 'waiter', + 'wall', + 'whats-new', + 'whatsnew', + 'whatnew', + 'whats-news', + 'web', + 'ws', + 'wss', + 'www', + 'x', + 'y', + 'year', + 'year-in-review', + 'z', + '400', + '401', + '403', + '404', + '500', + '503', + '504', + ]; - public static function get() - { - $banned = []; + public static function get() + { + $banned = []; - if(config('instance.username.banned')) { - $banned = array_map('trim', explode(',', config('instance.username.banned'))); - } + if (config('instance.username.banned')) { + $banned = array_map('trim', explode(',', config('instance.username.banned'))); + } - $additional = self::$additional; - $reserved = self::$reserved; + $additional = self::$additional; + $reserved = self::$reserved; - $res = array_merge($additional, $reserved, $banned); - $res = array_unique($res); - sort($res); - - return $res; - } + $res = array_merge($additional, $reserved, $banned); + $res = array_unique($res); + sort($res); + + return $res; + } } diff --git a/docker/shared/root/docker/entrypoint.d/01-permissions.sh b/docker/shared/root/docker/entrypoint.d/01-permissions.sh index efff58110..dc9dc7591 100755 --- a/docker/shared/root/docker/entrypoint.d/01-permissions.sh +++ b/docker/shared/root/docker/entrypoint.d/01-permissions.sh @@ -17,7 +17,7 @@ run-as-current-user chown --verbose --recursive "${RUNTIME_UID}:${RUNTIME_GID}" : "${DOCKER_APP_ENSURE_OWNERSHIP_PATHS:=""}" declare -a ensure_ownership_paths=() -IFS=' ' read -ar ensure_ownership_paths <<<"${DOCKER_APP_ENSURE_OWNERSHIP_PATHS}" +IFS=' ' read -r -a ensure_ownership_paths <<<"${DOCKER_APP_ENSURE_OWNERSHIP_PATHS}" if [[ ${#ensure_ownership_paths[@]} == 0 ]]; then log-info "No paths has been configured for ownership fixes via [\$DOCKER_APP_ENSURE_OWNERSHIP_PATHS]." diff --git a/docker/shared/root/docker/entrypoint.d/05-templating.sh b/docker/shared/root/docker/entrypoint.d/05-templating.sh index 4d229b11c..e699778cf 100755 --- a/docker/shared/root/docker/entrypoint.d/05-templating.sh +++ b/docker/shared/root/docker/entrypoint.d/05-templating.sh @@ -16,12 +16,8 @@ entrypoint-set-script-name "$0" declare template_file relative_template_file_path output_file_dir # load all dot-env config files -load-config-files +load-and-export-config-files -# export all dot-env variables so they are available in templating -# -# shellcheck disable=SC2068 -export ${seen_dot_env_variables[@]} find "${ENTRYPOINT_TEMPLATE_DIR}" -follow -type f -print | while read -r template_file; do # Example: template_file=/docker/templates/usr/local/etc/php/php.ini diff --git a/docker/shared/root/docker/entrypoint.sh b/docker/shared/root/docker/entrypoint.sh index 73f6a4f3e..055cf25d7 100755 --- a/docker/shared/root/docker/entrypoint.sh +++ b/docker/shared/root/docker/entrypoint.sh @@ -28,7 +28,7 @@ entrypoint-set-script-name "entrypoint.sh" # Convert ENTRYPOINT_SKIP_SCRIPTS into a native bash array for easier lookup declare -a skip_scripts # shellcheck disable=SC2034 -IFS=' ' read -ar skip_scripts <<< "$ENTRYPOINT_SKIP_SCRIPTS" +IFS=' ' read -r -a skip_scripts <<< "$ENTRYPOINT_SKIP_SCRIPTS" # Ensure the entrypoint root folder exists mkdir -p "${ENTRYPOINT_D_ROOT}" diff --git a/docker/shared/root/docker/helpers.sh b/docker/shared/root/docker/helpers.sh index 8ca2880fd..631b0ef0e 100644 --- a/docker/shared/root/docker/helpers.sh +++ b/docker/shared/root/docker/helpers.sh @@ -27,9 +27,6 @@ declare -a dot_env_files=( /var/www/.env ) -# environment keys seen when source dot files (so we can [export] them) -declare -ga seen_dot_env_variables=() - declare -g docker_state_path docker_state_path="$(readlink -f ./storage/docker)" @@ -250,13 +247,23 @@ function log-info-stderr() fi } -# @description Loads the dot-env files used by Docker and track the keys present in the configuration. -# @sets seen_dot_env_variables array List of config keys discovered during loading -function load-config-files() -{ - # Associative array (aka map/dictionary) holding the unique keys found in dot-env files - local -A _tmp_dot_env_keys +# @description Loads the dot-env files used by Docker +function load-config-files() { + local export_vars=0 + load-config-files-impl "$export_vars" +} +# @description Loads the dot-env files used by Docker and exports the variables to subshells +function load-and-export-config-files() { + local export_vars=1 + load-config-files-impl "$export_vars" +} + +# @description Implementation of the [load-config-files] and [load-and-export-config-files] functions. Loads th +# @arg $1 int Whether to export the variables or just have them available in the current shell +function load-config-files-impl() +{ + local export_vars=${1:-0} for file in "${dot_env_files[@]}"; do if ! file-exists "${file}"; then log-warning "Could not source file [${file}]: does not exists" @@ -264,19 +271,11 @@ function load-config-files() fi log-info "Sourcing ${file}" + if ((export_vars)); then set -o allexport; fi # shellcheck disable=SC1090 source "${file}" - - # find all keys in the dot-env file and store them in our temp associative array - for k in $(grep -v '^#' "${file}" | cut -d"=" -f1 | xargs); do - _tmp_dot_env_keys[$k]=1 - done + if ((export_vars)); then set +o allexport; fi done - - # Used in other scripts (like templating) for [export]-ing the values - # - # shellcheck disable=SC2034 - seen_dot_env_variables=("${!_tmp_dot_env_keys[@]}") } # @description Checks if $needle exists in $haystack