fix the fail2ban issues and other things
shellcheck / shellcheck (push) Successful in 11s

This commit is contained in:
2026-10-31 08:10:05 -06:00
parent 17c1ba10f7
commit 6770150b11
19 changed files with 580 additions and 51 deletions
+66 -2
View File
@@ -14,6 +14,7 @@ CORES_DIR="$HOME/.config/coredesktop/cores"
TAILSCALE_CONF="$HOME/.config/coredesktop/tailscale.conf"
BACKUP_CONF="$HOME/.config/coredesktop/backup.conf"
GOA_ACCOUNT="$COREDESKTOP/configure.d/lib/goa-account"
EMAIL_WATCH="$COREDESKTOP/system/email-watch"
source "$COREDESKTOP/configure.d/lib/nextcloud.sh"
[ -f "$CORE_CONF" ] && source "$CORE_CONF"
MAIN_DOMAIN="$CORE_DOMAIN"
@@ -40,6 +41,7 @@ core_names() {
SUPERPANEL_DESKTOP="$HOME/.local/share/applications/core-$CORE_DOMAIN-superpanel.desktop"
MATRIX="https://matrix.$CORE_DOMAIN"
ELEMENT_CONFIG="$HOME/.config/Element/config.json"
PLAUSIBLE="plausible.$CORE_DOMAIN"
}
superpanel_done() {
@@ -70,6 +72,26 @@ element_done() {
"$ELEMENT_CONFIG" &> /dev/null
}
# Tally for Plausible, a Flatpak, shows one Plausible Analytics. It follows the
# main Core, if that runs Plausible.
TALLY=com.cassidyjames.plausible
tally_installed() {
flatpak info "$TALLY" &> /dev/null
}
tally_setting() {
flatpak run --command=gsettings "$TALLY" "$@" 2> /dev/null
}
tally_done() {
[ "$(tally_setting get "$TALLY" domain)" = "'$PLAUSIBLE'" ]
}
plausible_on_core() {
curl -sf -o /dev/null --max-time 15 "https://$PLAUSIBLE/api/health"
}
# Element only follows the main Core
core_done() {
superpanel_done && nextcloud_done && email_done && files_done \
@@ -293,6 +315,13 @@ setup_element() {
echo "Element will use $MATRIX the next time it starts."
}
# Tally opens the page it showed last, so forget that one too
setup_tally() {
tally_setting set "$TALLY" domain "$PLAUSIBLE" || return 1
tally_setting set "$TALLY" current-url "" || return 1
echo "Tally for Plausible will show https://$PLAUSIBLE the next time it starts. Sign in there."
}
# Run a step unless it's done; a failed step doesn't stop the ones after it
step() {
local name="$1" title="$2"
@@ -359,7 +388,12 @@ setup_core() {
step files "Nextcloud files at $MOUNT"
[ "$CORE_DOMAIN" = "$MAIN_DOMAIN" ] && element_installed \
&& step element "Element with your Core's Matrix server"
[ "$CORE_DOMAIN" = "$MAIN_DOMAIN" ] && tally_installed && plausible_on_core \
&& step tally "Tally for Plausible with your Core's Plausible"
unset PASSWORD APP_PASSWORD
# Pauses email if the mail server stops taking its password (system/email-watch)
systemctl --user start coredesktop-email-watch.service 2> /dev/null
return $STATUS
}
@@ -399,10 +433,12 @@ change_password() {
echo
if email_done; then
local was_paused=""
"$GOA_ACCOUNT" paused imap_smtp "$CORE_EMAIL" 2> /dev/null && was_paused=", and isn't paused any more"
jq -n --arg password "$PASSWORD" '{"imap-password": $password, "smtp-password": $password}' \
| "$GOA_ACCOUNT" update imap_smtp "$CORE_EMAIL" 2> /dev/null
case $? in
0) echo " Email: has your new password" ;;
0) echo " Email: has your new password$was_paused" ;;
3) echo -e " \e[31mEmail: saved your new password, but the mail server didn't accept it.\e[0m"
STATUS=1 ;;
*) echo -e " \e[31mEmail: couldn't save your new password.\e[0m"; STATUS=1 ;;
@@ -462,6 +498,10 @@ main_changed() {
if element_installed && ! element_done && confirm_yes "Point Element at $MATRIX?"; then
setup_element
fi
if tally_installed && ! tally_done && plausible_on_core \
&& confirm_yes "Point Tally for Plausible at https://$PLAUSIBLE?"; then
setup_tally
fi
[ -f "$TAILSCALE_CONF" ] && echo "To move this computer to its Tailscale network: configure tailscale"
[ -f "$BACKUP_CONF" ] && echo "To back up to it instead: configure backup"
return 0
@@ -547,13 +587,26 @@ failed() {
# Test an Online Accounts account, and that none of what CoreDesktop set it up
# for is turned off in Settings:
# <title> <provider> <identity> <setup> <fix> <enable>
# One Online Accounts already found failing isn't signed in to again: each
# wrong password counts towards the mail server blocking this computer.
test_account() {
local error off works=1
if ! "$GOA_ACCOUNT" exists "$2" "$3" 2> /dev/null; then
failed "$1" "not set up" "$4"
return
fi
if ! error="$("$GOA_ACCOUNT" check "$2" "$3" 2>&1)"; then
if "$GOA_ACCOUNT" paused "$2" "$3" 2> /dev/null; then
failed "$1" "paused, as the server stopped taking its password" "$5" \
"So this computer doesn't keep trying it. Did your Core password change?"
works=0
elif "$GOA_ACCOUNT" attention "$2" "$3" 2> /dev/null; then
failed "$1" "the server doesn't take its password" "$5" "Did your Core password change?"
works=0
# Check email's password with Nextcloud first, not the mail server
elif [ "$2" = imap_smtp ] && { "$EMAIL_WATCH" --check-password "$3"; [ $? -eq 2 ]; }; then
failed "$1" "has an old password: Nextcloud doesn't take it" "$5" "Did your Core password change?"
works=0
elif ! error="$("$GOA_ACCOUNT" check "$2" "$3" 2>&1)"; then
failed "$1" "can't sign in" "$5" "$error"
works=0
fi
@@ -592,6 +645,16 @@ test_element() {
fi
}
test_tally() {
local title="Tally for Plausible with your Core's Plausible"
plausible_on_core || return 0
if tally_done; then
passed "$title"
else
failed "$title" "Tally shows another Plausible" setup_tally
fi
}
test_backups() {
local webdav
webdav="$(source "$BACKUP_CONF" && echo "$BACKUP_WEBDAV")"
@@ -631,6 +694,7 @@ test_core() {
test_account "Email in Online Accounts" imap_smtp "$CORE_EMAIL" setup_email fix_email enable_email
test_files
[ "$CORE_DOMAIN" = "$MAIN_DOMAIN" ] && element_installed && test_element
[ "$CORE_DOMAIN" = "$MAIN_DOMAIN" ] && tally_installed && test_tally
backup_on "$CORE_DOMAIN" && test_backups
return 0
}
+61
View File
@@ -15,6 +15,9 @@ Usage:
goa-account check <provider> <presentation-identity>
goa-account disabled <provider> <presentation-identity>
goa-account enable <provider> <presentation-identity>
goa-account attention <provider> <presentation-identity>
goa-account pause <provider> <presentation-identity>
goa-account paused <provider> <presentation-identity>
goa-account remove <provider> <presentation-identity>
account.json:
@@ -26,6 +29,18 @@ check signs in with what's saved, and fails if the server says no. update
exits with 3 if it saved the password but the server didn't accept it.
disabled prints the features CoreDesktop uses that are turned off in Settings,
e.g. "Calendar, Files", and enable turns them back on.
attention exits 0 if Online Accounts found that the server no longer takes
the saved password (it then shows the account as needing attention). It
doesn't sign in, so it doesn't add to the server's count of failed logins.
Online Accounts 3.58 only finds this for Nextcloud: a mail server refusing the
password is reported as a general failure (see system/email-watch).
pause empties the account's saved password, keeping its place in the keyring.
Online Accounts signs in again whenever the network changes, and Evolution
whenever it fetches mail; with no password neither tries, so a mail server
with fail2ban doesn't block this computer for repeated wrong passwords.
update puts a password back, which ends the pause. paused exits 0 if paused.
"""
import json
@@ -112,6 +127,45 @@ def store_credentials(provider, account_id, credentials):
secret, None)
# The account's saved credentials, e.g. {"imap-password": "..."}
def lookup_credentials(provider, account_id):
items = Secret.password_search_sync(
None, {"xdg:schema": "org.gnome.OnlineAccounts"},
Secret.SearchFlags.ALL | Secret.SearchFlags.UNLOCK | Secret.SearchFlags.LOAD_SECRETS, None)
for item in items:
identity = item.get_attributes().get("goa-identity", "")
if identity.startswith(f"{provider}:gen") and identity.endswith(f":{account_id}"):
return GLib.Variant.parse(None, item.get_secret().get_text(), None, None).unpack()
raise LookupError(f"there's no saved password for {account_id} in the keyring")
# The credential each kind of account signs in with
PASSWORD_KEYS = {"owncloud": "password", "imap_smtp": "imap-password"}
def attention(bus, provider, presentation_identity):
found = find_accounts(bus, provider, presentation_identity)
if not found:
raise LookupError(f"there's no {provider} account for {presentation_identity}")
return any(account.get("AttentionNeeded") for _, account in found)
def pause(bus, provider, presentation_identity):
found = find_accounts(bus, provider, presentation_identity)
if not found:
raise LookupError(f"there's no {provider} account for {presentation_identity}")
for _, account in found:
store_credentials(provider, account["Id"], {})
def paused(bus, provider, presentation_identity):
found = find_accounts(bus, provider, presentation_identity)
if not found:
raise LookupError(f"there's no {provider} account for {presentation_identity}")
return any(PASSWORD_KEYS[provider] not in lookup_credentials(provider, account["Id"])
for _, account in found)
def update(bus, provider, presentation_identity, credentials):
found = find_accounts(bus, provider, presentation_identity)
if not found:
@@ -180,6 +234,13 @@ def main():
if len(sys.argv) == 4 and sys.argv[1] == "enable":
enable(bus, sys.argv[2], sys.argv[3])
return 0
if len(sys.argv) == 4 and sys.argv[1] == "attention":
return 0 if attention(bus, sys.argv[2], sys.argv[3]) else 1
if len(sys.argv) == 4 and sys.argv[1] == "pause":
pause(bus, sys.argv[2], sys.argv[3])
return 0
if len(sys.argv) == 4 and sys.argv[1] == "paused":
return 0 if paused(bus, sys.argv[2], sys.argv[3]) else 1
if len(sys.argv) == 4 and sys.argv[1] == "remove":
remove(bus, sys.argv[2], sys.argv[3])
return 0