#!/usr/bin/env bash # # envs.net - generate sysinfo.json and sysinfo.php # - this script is called by /etc/cron.d/envs_sysinfo # WWW_PATH='/var/www/envs.net' DOMAIN='envs.net' [ "$(id -u)" -ne 0 ] && printf 'Please run as root!\n' && exit 1 ### # define packages by category for sysinfo.php Page services=(0x0 bbj cryptpad getwtxt gitea gophernicus halcyon jetforce jitsi-meet mariadb-server matrix nginx openssh-server pleroma privatebin riot-web searx termbin tt-rss thelounge znc) readarray -t sorted_services < <(printf '%s\n' "${services[@]}" | sort) shells=(bash csh dash elvish fish ksh mksh sash tcsh xonsh yash zsh) readarray -t sorted_shells < <(printf '%s\n' "${shells[@]}" | sort) editors=(ed emacs micro nano neovim vim) readarray -t sorted_editors < <(printf '%s\n' "${editors[@]}" | sort) inet_clients=(alpine av98 bombadillo curl irssi lynx neomutt meli mutt mosh openssh-client pb toot weechat wget vf1) readarray -t sorted_inet_clients < <(printf '%s\n' "${inet_clients[@]}" | sort) coding_pkg=(cargo clang clisp clojure crystal default-jdk default-jre elixir erlang flex g++ gcc gcl gdc gforth ghc go golang guile-2.2 inform lua5.1 lua5.2 lua5.3 mono-complete nasm nim nodejs octave perl php picolisp ponyc python python2.7 python3 racket ruby rustc scala tcl yasm vlang) readarray -t sorted_coding_pkg < <(printf '%s\n' "${coding_pkg[@]}" | sort) coding_tools=(ack bison build-essential cl-launch cvs devscripts ecl gawk git gron initscripts jq latex-mk latexmk make mawk mercurial rake ripgrep sbcl shellcheck subversion texlive-full virtualenv yarn) readarray -t sorted_coding_tools < <(printf '%s\n' "${coding_tools[@]}" | sort) misc=(aria2 bc busybox burrow byobu clinte dict gfu goaccess hugo jekyll mariadb-client mandoc mathomatic mathtex mkdocs pandoc pelican sagemath screen sqlite3 tmux todotxt-cli twtxt txtnish zola) readarray -t sorted_misc < <(printf '%s\n' "${misc[@]}" | sort) # # do not add services! service_pkgs=(mariadb-server nginx openssh-server) FULL_PKG_LIST=("${service_pkgs[@]}" "${shells[@]}" "${editors[@]}" "${inet_clients[@]}" "${coding_pkg[@]}" "${coding_tools[@]}" "${misc[@]}") custom_pkg_desc() { local pkg="$1" case "$pkg" in # packages crystal) pkg_desc='Compiler for the Crystal language';; # custom packages av98) pkg_desc='Command line gemini client. High speed, low drag';; bombadillo) pkg_desc='Bombadillo is a non-web browser for the terminal';; burrow) pkg_desc='a helper for building and managing a gopher hole';; clinte) pkg_desc='a community notices system';; gfu) pkg_desc='A utility for formatting gophermaps';; go) pkg_desc='tool for managing Go source code';; goaccess) pkg_desc='fast web log analyzer and interactive viewer';; micro) pkg_desc='a new modern terminal-based text editor';; pb) pkg_desc='a helper utility for using 0x0 pastebin services';; twtxt) pkg_desc='Decentralised, minimalist microblogging service for hackers';; txtnish) pkg_desc='A twtxt client with minimal dependencies';; vf1) pkg_desc='Command line gopher client. High speed, low drag.';; vlang) pkg_desc='Simple, fast, safe, compiled programming language';; zola) pkg_desc='single-binary static site generator written in rust';; *) _no_custom_pkg='1' ;; esac } # # SYSINFO.JSON # JSON_FILE="$WWW_PATH/sysinfo.json" TMP_JSON='/tmp/sysinfo.json_tmp' print_pkg_version() { local pkg_version #for pkg in $(dpkg-query -f '${binary:Package}\n' -W); do for pkg in "${FULL_PKG_LIST[@]}"; do _no_custom_pkg='0' ; custom_pkg_desc "$pkg" if [ "$_no_custom_pkg" -eq '1' ] || [ "$pkg" = 'crystal' ]; then pkg_version="$(dpkg-query -f '${Version}\n' -W "$pkg")" printf ' "%s": "%s",\n' "$pkg" "$pkg_version" fi done } cat< "$TMP_JSON" { "timestamp": "$(date +'%s')", "data": { "info": { "name": "envs", "description": "envs.net is a minimalist, non-commercial shared linux system and will always be free to use.", "located": "germany", "maintainer": "Sven Kinne (~creme) - creme@envs.net", "website": "https://$DOMAIN", "signup_url": "https://$DOMAIN/signup/", "gopher": "gopher://envs.net/", "email": "hostmaster@$DOMAIN", "admin_email": "sudoers@$DOMAIN", "user_count": $(find /home -mindepth 1 -maxdepth 1 | wc -l) }, "SSHFP": { "RSA": "SHA256:7dB470mfzlyhhtqmjnXciIxp+jWLACiYKC3EE/Z0lFg", "ECDSA": "SHA256:U0C6SKGXUflve16m2l4KWBdLLARW6O8TiGWZsXAU2i4", "ED25519": "SHA256:V+mXTsRJ+jfJMxxPlD/28dpWouuns3Wuqwppv6ykVC8" }, "system": { "os": "$(lsb_release -sd)", "uptime": "$(cat /proc/uptime)", "uname": "$(uname -a)", "board": "$(hostnamectl status | awk '/Chassis/ {print $2}')", "cpuinfo": "$(awk '/system type|model name/{gsub(/^.*:[ ]*/,"");print $0;exit}' /proc/cpuinfo)", "cpucount": "$(grep -c ^processor /proc/cpuinfo)" }, "services": { "0x0": { "desc": "the null pointer - file hosting and url shortener", "version": "-", "url": "https://envs.sh/" }, "bbj": { "desc": "bulletin butter & jelly: an http bulletin board server for small communities", "version": "-", "url": "https://bbj.envs.net/" }, "cryptpad": { "desc": "collaborative real time editing", "version": "$(curl -fs https://pad."$DOMAIN"/api/config | awk -F= '/ver=/ {print $2}' | sed '$ s/"$//')", "url": "https://pad.envs.net/" }, "getwtxt": { "desc": "a twtxt registry service - microblogging for hackers", "version": "$(curl -fs https://twtxt."$DOMAIN"/api/plain/version | awk -Fv '{print $2}')", "url": "https://twtxt.envs.net/" }, "gitea": { "desc": "a painless self-hosted git service written in go", "version": "$(lxc-attach -n gitea -- bash -c "gitea --version | awk '{print \$3}'")", "url": "https://git.envs.net/" }, "gophernicus": { "desc": "a modern full-featured (and hopefully) secure gopher daemon", "version": "$(/usr/sbin/gophernicus -v | sed 's/Gophernicus\///' | awk '{print $1}')", "url": "gopher://envs.net/" }, "halcyon": { "desc": "a webclient for mastodon and pleroma which looks like twitter", "version": "$(cat /var/lib/lxc/pleroma/rootfs/var/www/halcyon/version.txt)", "url": "https://halcyon.envs.net/" }, "ipinfo": { "desc": "ip address info", "version": "", "url": "https://ip.envs.net/" }, "jetforce": { "desc": "an tcp server for the gemini protocol", "version": "$(/usr/local/bin/jetforce -V | awk '{printf $2}')", "url": "gemini://envs.net/" }, "jitsi-meet": { "desc": "secure, simple and scalable video conferences that you use as a standalone app or embed in your web application.", "version": "$(lxc-attach -n jitsi -- bash -c "dpkg-query -f '\${Version}\n' -W jitsi-meet")", "url": "https://jitsi.envs.net/" }, "matrix": { "desc": "an open network for secure, decentralized communication", "version": "$(curl -fs https://matrix."$DOMAIN"/_matrix/federation/v1/version | jq -Mr .server.version)", "url": "https://matrix.envs.net/" }, "pleroma": { "desc": "federated social network - microblogging", "version": "$(curl -fs https://pleroma."$DOMAIN"/api/v1/instance | jq -Mr .version | awk '{print $4}' | sed '$ s/)//')", "url": "https://pleroma.envs.net/" }, "privatebin": { "desc": "a graphical pastebin", "version": "$(lxc-attach -n pb -- bash -c "awk '/Current version:/ {print \$3}' /var/www/PrivateBin/README.md | sed '$ s/*$//'")", "url": "https://pb.envs.net/" }, "riot-web": { "desc": "a universal secure chat app for matrix (web-client)", "version": "$(lxc-attach -n matrix -- bash -c "dpkg-query -f '\${Version}\n' -W riot-web")", "url": "https://matrix.envs.net/" }, "searx": { "desc": "a privacy-respecting metasearch engine", "version": "$(curl -fs https://searx."$DOMAIN"/config | jq -Mr .version)", "url": "https://searx.envs.net/" }, "termbin": { "desc": "netcat-based command line pastebin", "version": "-", "url": "https://tb.envs.net/" }, "thelounge": { "desc": "a self-hosted web irc client", "version": "$(sudo -u thelounge /srv/thelounge/.yarn/bin/thelounge -v | awk -Fv '{print $2}')", "url": "https://webirc.envs.net/" }, "tt-rss": { "desc": "tiny tiny rss - web-based news feed (rss/atom) aggregator", "version": "$(lxc-attach -n rss -- bash -c "dpkg -s tt-rss | awk '/Version:/ {print \$2}' | head -n1")", "url": "https://rss.envs.net/" }, "znc": { "desc": "advanced modular irc bouncer", "version": "$(dpkg -s znc | awk '/Version:/ {print $2}' | head -n1)", "url": "https://znc.envs.net/" } }, "packages": { "av98": "$(/usr/local/bin/av98 --version | awk '{print $2}')", "bombadillo": "$(/usr/local/bin/bombadillo -v | awk '/Bombadillo/ {print $2}')", "burrow": "$(/usr/local/bin/burrow -v | awk -Fv '{print $2}')", "clinte": "$(/usr/local/bin/clinte -V | awk '/clinte/ {print $2}')", "gfu": "$(/usr/local/bin/gfu -v | sed '/version/s/.*version \([^ ][^ ]*\)[ ]*.*/\1/')", "go": "$(awk -Fgo '{print $2}' /usr/local/go/VERSION)", "goaccess": "$(/usr/bin/goaccess -V | awk '/GoAccess/ {print $3}')", "micro": "$(/usr/local/bin/micro -version | awk '/Version/ {print $2}')", "pb": "$(/usr/local/bin/pb -v)", "twtxt": "$(/usr/local/bin/twtxt --version | awk '/version/ {printf $3}')", "txtnish": "$(/usr/local/bin/txtnish -V)", "vf1": "$(/usr/local/bin/vf1 --version | awk '/VF-1/ {print $2}')", "vlang": "$(/usr/local/bin/v --version | awk '/V/ {print $2}')", "zola": "$(/usr/local/bin/zola -V | awk '/zola/ {print $2}')", $(print_pkg_version) EOM # remove trailing ',' on last line sed -i '$ s/,$//' "$TMP_JSON" cat<> "$TMP_JSON" } } } EOM mv "$TMP_JSON" "$JSON_FILE" chown root:www-data "$JSON_FILE" # # SYSINFO.PHP # print_pkg_info() { local pkg="$1" local pkg_version pkg_version="$(jq -Mr '.data.packages."'"$pkg"'"|select (.!=null)' "$JSON_FILE")" [ -z "$pkg_version" ] && pkg_version='n.a.' local pkg_desc custom_pkg_desc "$pkg" [ -z "$pkg_desc" ] && pkg_desc="$(apt-cache show "$pkg" | awk '/Description-en/ {print substr($0, index($0,$2))}' | head -1)" [ -z "$pkg_desc" ] && pkg_desc="$(apt-cache search ^"$pkg"$ | awk '{print substr($0, index($0,$3))}')" [ -z "$pkg_desc" ] && pkg_desc='n.a.' # remove description-en string pkg_desc="${pkg_desc//Description-en: /}" # replace double qoutes with single qoute pkg_desc="${pkg_desc//\"/\'}" # string to lowercase pkg_desc="${pkg_desc,,}" printf '\t\t %s %s %s \n' "$pkg" "$pkg_version" "$pkg_desc" } print_pkg_info_services() { local pkg="$1" local pkg_desc pkg_desc="$(jq -Mr '.data.services."'"$pkg"'".desc|select (.!=null)' "$JSON_FILE")" local pkg_version pkg_version="$(jq -Mr '.data.services."'"$pkg"'".version|select (.!=null)' "$JSON_FILE")" local s_url s_url="$(jq -Mr '.data.services."'"$pkg"'".url|select (.!=null)' "$JSON_FILE")" printf '\t\t %s %s %s \n' "$s_url" "$pkg" "$pkg_version" "$pkg_desc" } print_category() { local category="$1" shift local arr=("$@") if [ "$category" = 'services' ]; then printf '
# %s\n' "$category" "${category//_/ }" else printf '
# %s\n' "$category" "${category//_/ }" fi printf '\t\n' printf '\t\t\n' if [ "$category" = 'services' ]; then for pkg in "${arr[@]}"; do # check service in sysinfo.json s_in_j="$(jq -Mr '.data.services."'"$pkg"'"|select (.!=null)' "$JSON_FILE")" if [ -n "$s_in_j" ]; then print_pkg_info_services "$pkg" else print_pkg_info "$pkg" fi done else for pkg in "${arr[@]}"; do print_pkg_info "$pkg"; done fi printf '\t
Package Version Description
\n
\n

\n' } cat< /tmp/sysinfo.php_tmp

sysinfo

full data source: https://$DOMAIN/sysinfo.json
webserver stats: https://$DOMAIN/stats/

server admin: ~creme

this is a static list of the package informations. it updates once per day.

# can i get [package] installed?
probably! send an email with your suggestion to sudoers@$DOMAIN.

$(print_category 'services' "${sorted_services[@]}") $(print_category 'shells' "${sorted_shells[@]}") $(print_category 'editors' "${sorted_editors[@]}") $(print_category 'online_browser_and_clients' "${sorted_inet_clients[@]}") $(print_category 'coding_packages' "${sorted_coding_pkg[@]}") $(print_category 'coding_tools' "${sorted_coding_tools[@]}") $(print_category 'misc' "${sorted_misc[@]}")
EOM mv /tmp/sysinfo.php_tmp "$WWW_PATH"/sysinfo.php chown root:www-data "$WWW_PATH"/sysinfo.php # exit 0