improvements to configure
This commit is contained in:
@@ -216,9 +216,9 @@ configure
|
||||
|
||||
It covers:
|
||||
|
||||
- **Your Federated Computer Core.** Give it your Superpanel's address (e.g. https://superpanel.example.com), your Core email, name and password, and it adds Superpanel to your applications, adds your Nextcloud (calendar, contacts and files) and email to GNOME's Online Accounts, and mounts your Nextcloud files at /mnt/example.com ("example.com" in the Files sidebar), and points Element at your Core's Matrix server. For Nextcloud and the files it creates a Nextcloud app password, which you can revoke in Nextcloud under Settings > Security.
|
||||
- **Your Core's Tailscale network.** Joins this computer to it through headscale.example.com, so you can reach your other machines on it. Set up your Core first. You sign in through a link it shows you; if this computer is on another Tailscale network, it moves it to your Core's.
|
||||
- **Daily backups of your home folder** to your Nextcloud files, in a .backup-{machine name} folder, with restic. Set up your Core first. The backup is encrypted with a passphrase that `configure` shows you once: save it somewhere other than this computer, such as Bitwarden. It keeps 7 daily, 4 weekly and 6 monthly backups, and leaves out caches and things that can be reinstalled. To leave out more, list paths in ~/.config/coredesktop/backup-exclude, one per line. restic reaches Nextcloud directly through rclone with its own Nextcloud app password, so the backup doesn't depend on the /mnt mount. See "Restoring from a backup" below.
|
||||
- **Your Federated Computer Core.** Give it your Superpanel's address (e.g. https://superpanel.example.com), your Core email, name and password, and it adds Superpanel to your applications, adds your Nextcloud (calendar, contacts and files) and email to GNOME's Online Accounts, and mounts your Nextcloud files at /mnt/example.com ("example.com" in the Files sidebar), and points Element at your Core's Matrix server. For Nextcloud and the files it creates a Nextcloud app password, which you can revoke in Nextcloud under Settings > Security. You can add more Cores: run `configure core` again and choose "Add a Core". Each gets its own Superpanel, Nextcloud, email and files; Element, Tailscale and backups use your main Core (the first one, unless you choose another). "Remove a Core" takes it off this computer and revokes its app password, and leaves everything on the Core itself as it is.
|
||||
- **Your Core's Tailscale network.** Joins this computer to it through headscale.example.com, so you can reach your other machines on it. Set up your Core first. You sign in through a link it shows you; if this computer is on another Tailscale network, it moves it to your Core's. To leave your Core's network, run `configure tailscale` again.
|
||||
- **Daily backups of your home folder** to your Nextcloud files, in a .backup-{machine name} folder, with restic. Set up your Core first. The backup is encrypted with a passphrase that `configure` shows you once: save it somewhere other than this computer, such as Bitwarden. It keeps 7 daily, 4 weekly and 6 monthly backups, and leaves out caches and things that can be reinstalled. To leave out more, list paths in ~/.config/coredesktop/backup-exclude, one per line. restic reaches Nextcloud directly through rclone with its own Nextcloud app password, so the backup doesn't depend on the /mnt mount. See "Restoring from a backup" below. To turn backups off, run `configure backup` again; it also offers to delete the backups from your Nextcloud files (they go to Nextcloud's trash bin).
|
||||
- Signing in to Claude Code, opencode and Hermes Agent and choosing their model providers.
|
||||
|
||||
To set up one thing, name it, e.g. `configure hermes`; `configure --list` shows the names.
|
||||
|
||||
+196
-9
@@ -3,11 +3,30 @@
|
||||
TITLE="Federated Computer Core"
|
||||
DESCRIPTION="Superpanel, Nextcloud, email, files and Element"
|
||||
|
||||
# What you entered last time, so running this again only does what's missing
|
||||
# Each Core is in cores/<domain>.conf, with what you entered last time, so
|
||||
# running this again only does what's missing. core.conf is a copy of the main
|
||||
# Core's: Element, Tailscale and Backup use that one.
|
||||
CORE_CONF="$HOME/.config/coredesktop/core.conf"
|
||||
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"
|
||||
source "$COREDESKTOP/configure.d/lib/nextcloud.sh"
|
||||
[ -f "$CORE_CONF" ] && source "$CORE_CONF"
|
||||
MAIN_DOMAIN="$CORE_DOMAIN"
|
||||
|
||||
core_domains() {
|
||||
local file
|
||||
for file in "$CORES_DIR"/*.conf; do
|
||||
[ -f "$file" ] && basename "$file" .conf
|
||||
done
|
||||
}
|
||||
|
||||
load_core() {
|
||||
CORE_DOMAIN="" CORE_EMAIL="" CORE_NAME=""
|
||||
[ -n "$1" ] && source "$CORES_DIR/$1.conf"
|
||||
core_names
|
||||
}
|
||||
|
||||
# CORE_DOMAIN, CORE_EMAIL and CORE_NAME come from core.conf; the rest follow
|
||||
core_names() {
|
||||
@@ -48,19 +67,37 @@ element_done() {
|
||||
"$ELEMENT_CONFIG" &> /dev/null
|
||||
}
|
||||
|
||||
is_configured() {
|
||||
[ -n "$CORE_DOMAIN" ] || return 1
|
||||
core_names
|
||||
superpanel_done && nextcloud_done && email_done && files_done && element_done
|
||||
# Element only follows the main Core
|
||||
core_done() {
|
||||
superpanel_done && nextcloud_done && email_done && files_done \
|
||||
&& { [ "$CORE_DOMAIN" != "$MAIN_DOMAIN" ] || element_done; }
|
||||
}
|
||||
|
||||
# Done when every Core is
|
||||
is_configured() {
|
||||
local domain domains
|
||||
domains="$(core_domains)"
|
||||
[ -n "$domains" ] || return 1
|
||||
for domain in $domains; do
|
||||
(load_core "$domain" && core_done) || return 1
|
||||
done
|
||||
}
|
||||
|
||||
# The first Core you set up is the main one
|
||||
save_conf() {
|
||||
mkdir -p "$(dirname "$CORE_CONF")"
|
||||
mkdir -p "$CORES_DIR"
|
||||
{
|
||||
printf 'CORE_DOMAIN=%q\n' "$CORE_DOMAIN"
|
||||
printf 'CORE_EMAIL=%q\n' "$CORE_EMAIL"
|
||||
printf 'CORE_NAME=%q\n' "$CORE_NAME"
|
||||
} > "$CORE_CONF"
|
||||
} > "$CORES_DIR/$CORE_DOMAIN.conf"
|
||||
if [ -z "$MAIN_DOMAIN" ] || [ "$MAIN_DOMAIN" = "$CORE_DOMAIN" ]; then
|
||||
make_main "$CORE_DOMAIN"
|
||||
fi
|
||||
}
|
||||
|
||||
make_main() {
|
||||
cp "$CORES_DIR/$1.conf" "$CORE_CONF" && MAIN_DOMAIN="$1"
|
||||
}
|
||||
|
||||
desktop_entry() {
|
||||
@@ -263,7 +300,8 @@ step() {
|
||||
"setup_$name" || { echo -e "\e[31m$title was not set up.\e[0m"; STATUS=1; }
|
||||
}
|
||||
|
||||
run_configure() {
|
||||
# Set up the Core loaded with load_core, or a new one
|
||||
setup_core() {
|
||||
local url
|
||||
STATUS=0
|
||||
|
||||
@@ -304,7 +342,156 @@ run_configure() {
|
||||
step nextcloud "Nextcloud in Online Accounts"
|
||||
step email "Email in Online Accounts"
|
||||
step files "Nextcloud files at $MOUNT"
|
||||
element_installed && step element "Element with your Core's Matrix server"
|
||||
[ "$CORE_DOMAIN" = "$MAIN_DOMAIN" ] && element_installed \
|
||||
&& step element "Element with your Core's Matrix server"
|
||||
unset PASSWORD APP_PASSWORD
|
||||
return $STATUS
|
||||
}
|
||||
|
||||
# Tailscale and Backup point at one Core, which can't be removed while they do
|
||||
tailscale_on() {
|
||||
[ "$(source "$TAILSCALE_CONF" 2> /dev/null && echo "$TAILSCALE_DOMAIN")" = "$1" ] \
|
||||
&& tailscale status --json 2> /dev/null | jq -e '.BackendState == "Running"' > /dev/null
|
||||
}
|
||||
|
||||
backup_on() {
|
||||
[[ "$(source "$BACKUP_CONF" 2> /dev/null && echo "$BACKUP_WEBDAV")" == "https://nextcloud.$1/"* ]] \
|
||||
&& systemctl --user is-enabled -q coredesktop-backup.timer 2> /dev/null
|
||||
}
|
||||
|
||||
# Choose one of DOMAINS, other than $2 if given; sets PICKED
|
||||
pick_core() {
|
||||
local choices=() domain choice i
|
||||
for domain in "${DOMAINS[@]}"; do
|
||||
[ "$domain" != "$2" ] && choices+=("$domain")
|
||||
done
|
||||
if [ ${#choices[@]} -eq 1 ]; then
|
||||
PICKED="${choices[0]}"
|
||||
return 0
|
||||
fi
|
||||
for i in "${!choices[@]}"; do
|
||||
printf ' %d) %s\n' $((i + 1)) "${choices[$i]}"
|
||||
done
|
||||
read -rp "$1 " choice
|
||||
[[ "$choice" =~ ^[0-9]+$ ]] && (( choice >= 1 && choice <= ${#choices[@]} )) || return 1
|
||||
PICKED="${choices[$((choice - 1))]}"
|
||||
}
|
||||
|
||||
# Point Element at the main Core, and say what else follows it
|
||||
main_changed() {
|
||||
load_core "$MAIN_DOMAIN"
|
||||
echo "$MAIN_DOMAIN is now your main Core."
|
||||
if element_installed && ! element_done && confirm_yes "Point Element at $MATRIX?"; then
|
||||
setup_element
|
||||
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
|
||||
}
|
||||
|
||||
# The app password this computer uses for the Core, from davfs2's secrets
|
||||
files_app_password() {
|
||||
grep -s "^$MOUNT " "$HOME/.davfs2/secrets" \
|
||||
| python3 -I -c 'import shlex, sys; print(shlex.split(sys.stdin.read())[2])' 2> /dev/null
|
||||
}
|
||||
|
||||
# Undo what setup_core did. Nothing on the Core itself changes.
|
||||
remove_core() {
|
||||
local domain="$1" new_main="" app_password mount_re
|
||||
if tailscale_on "$domain"; then
|
||||
echo "This computer is on $domain's Tailscale network. Leave it first: configure tailscale"
|
||||
return 1
|
||||
fi
|
||||
if backup_on "$domain"; then
|
||||
echo "Your backups go to $domain. Turn them off first: configure backup"
|
||||
return 1
|
||||
fi
|
||||
if [ "$domain" = "$MAIN_DOMAIN" ] && [ ${#DOMAINS[@]} -gt 1 ]; then
|
||||
echo "$domain is your main Core. Which Core should be the main one instead?"
|
||||
pick_core "Choose:" "$domain" || { echo "Choose a number from the list."; return 1; }
|
||||
new_main="$PICKED"
|
||||
fi
|
||||
echo "This removes $domain's Superpanel, Nextcloud, email and files from this computer."
|
||||
echo "Your files, email and everything else stay on the Core."
|
||||
confirm "Remove $domain?" || return 0
|
||||
|
||||
load_core "$domain"
|
||||
app_password="$(files_app_password)"
|
||||
[ -n "$app_password" ] && nextcloud_revoke_app_password "$app_password"
|
||||
|
||||
mountpoint -q "$MOUNT" && { umount "$MOUNT" 2> /dev/null || sudo umount "$MOUNT"; }
|
||||
mount_re="${MOUNT//./\\.}"
|
||||
if grep -qs " $MOUNT davfs " /etc/fstab; then
|
||||
sudo sed -i "\\# $mount_re davfs #d" /etc/fstab && sudo systemctl daemon-reload
|
||||
fi
|
||||
[ -d "$MOUNT" ] && sudo rmdir "$MOUNT" 2> /dev/null
|
||||
sed -i "\\#^$mount_re #d" "$HOME/.davfs2/secrets" 2> /dev/null
|
||||
sed -i "\\#^file://$mount_re #d" "$HOME/.config/gtk-3.0/bookmarks" 2> /dev/null
|
||||
rm -f "$HOME/.config/autostart/core-$CORE_DOMAIN-files.desktop"
|
||||
|
||||
"$GOA_ACCOUNT" remove owncloud "$CORE_USER@nextcloud.$CORE_DOMAIN"
|
||||
"$GOA_ACCOUNT" remove imap_smtp "$CORE_EMAIL"
|
||||
rm -f "$SUPERPANEL_DESKTOP" "$HOME/.local/share/icons/core-$CORE_DOMAIN-superpanel.png"
|
||||
|
||||
# Element keeps its default server, unless that was this Core
|
||||
if [ "$domain" = "$MAIN_DOMAIN" ] && [ -z "$new_main" ] && [ -f "$ELEMENT_CONFIG" ] \
|
||||
&& jq -e --arg name "matrix.$domain" '.default_server_config["m.homeserver"].server_name == $name' \
|
||||
"$ELEMENT_CONFIG" &> /dev/null; then
|
||||
jq 'del(.default_server_config)' "$ELEMENT_CONFIG" > "$ELEMENT_CONFIG.tmp" \
|
||||
&& mv -f "$ELEMENT_CONFIG.tmp" "$ELEMENT_CONFIG"
|
||||
fi
|
||||
|
||||
rm -f "$CORES_DIR/$domain.conf"
|
||||
echo "Removed $domain from this computer."
|
||||
if [ -n "$new_main" ]; then
|
||||
make_main "$new_main" && main_changed
|
||||
elif [ "$domain" = "$MAIN_DOMAIN" ]; then
|
||||
rm -f "$CORE_CONF"
|
||||
fi
|
||||
}
|
||||
|
||||
run_configure() {
|
||||
local choice i state
|
||||
mapfile -t DOMAINS < <(core_domains)
|
||||
if [ ${#DOMAINS[@]} -eq 0 ]; then
|
||||
load_core ""
|
||||
setup_core
|
||||
return
|
||||
fi
|
||||
|
||||
echo "Your Cores:"
|
||||
for i in "${!DOMAINS[@]}"; do
|
||||
if (load_core "${DOMAINS[$i]}" && core_done); then
|
||||
state="\e[32mdone\e[0m "
|
||||
else
|
||||
state="\e[33mto do\e[0m"
|
||||
fi
|
||||
printf " %d) $state %s%s\n" $((i + 1)) "${DOMAINS[$i]}" \
|
||||
"$([ "${DOMAINS[$i]}" = "$MAIN_DOMAIN" ] && echo " (main)")"
|
||||
done
|
||||
echo
|
||||
echo " Choose a number to finish or change its setup, or:"
|
||||
echo " a) Add a Core"
|
||||
[ ${#DOMAINS[@]} -gt 1 ] && echo " m) Make another Core the main one"
|
||||
echo " r) Remove a Core"
|
||||
echo " q) Leave it as it is"
|
||||
echo
|
||||
read -rp "Choose: " choice
|
||||
case "$choice" in
|
||||
a|A)
|
||||
load_core ""
|
||||
setup_core ;;
|
||||
m|M)
|
||||
[ ${#DOMAINS[@]} -gt 1 ] || return 0
|
||||
pick_core "Which should be the main one?" "$MAIN_DOMAIN" || { echo "Choose a number from the list."; return 1; }
|
||||
make_main "$PICKED" && main_changed ;;
|
||||
r|R)
|
||||
pick_core "Which Core should be removed?" || { echo "Choose a number from the list."; return 1; }
|
||||
remove_core "$PICKED" ;;
|
||||
*)
|
||||
if [[ "$choice" =~ ^[0-9]+$ ]] && (( choice >= 1 && choice <= ${#DOMAINS[@]} )); then
|
||||
load_core "${DOMAINS[$((choice - 1))]}"
|
||||
setup_core
|
||||
fi ;;
|
||||
esac
|
||||
}
|
||||
|
||||
@@ -14,12 +14,45 @@ is_installed() {
|
||||
|
||||
# Tailscale has no status field naming its login server, so tailscale.conf
|
||||
# records which Core it was set up for
|
||||
is_configured() {
|
||||
[ -n "$CORE_DOMAIN" ] && [ "$TAILSCALE_DOMAIN" = "$CORE_DOMAIN" ] \
|
||||
joined() {
|
||||
[ -n "$TAILSCALE_DOMAIN" ] \
|
||||
&& tailscale status --json 2> /dev/null | jq -e '.BackendState == "Running"' > /dev/null
|
||||
}
|
||||
|
||||
# Done when on the main Core's network
|
||||
is_configured() {
|
||||
[ -n "$CORE_DOMAIN" ] && [ "$TAILSCALE_DOMAIN" = "$CORE_DOMAIN" ] && joined
|
||||
}
|
||||
|
||||
# Log out rather than only go down, so this computer's key is expired on
|
||||
# headscale and it's off the network until it joins again
|
||||
leave_network() {
|
||||
sudo tailscale logout || return 1
|
||||
rm -f "$TAILSCALE_CONF"
|
||||
echo "This computer has left your Core's Tailscale network. To join again: configure tailscale"
|
||||
}
|
||||
|
||||
run_configure() {
|
||||
local choice
|
||||
if joined &> /dev/null; then
|
||||
echo "This computer is on $TAILSCALE_DOMAIN's Tailscale network (headscale.$TAILSCALE_DOMAIN)."
|
||||
echo
|
||||
if [ "$TAILSCALE_DOMAIN" = "$CORE_DOMAIN" ]; then
|
||||
echo " 1) Join it again"
|
||||
else
|
||||
echo " 1) Join your main Core's network instead (headscale.$CORE_DOMAIN)"
|
||||
fi
|
||||
echo " 2) Leave the network"
|
||||
echo " q) Leave it as it is"
|
||||
echo
|
||||
read -rp "Choose: " choice
|
||||
case "$choice" in
|
||||
1) ;;
|
||||
2) leave_network; return ;;
|
||||
*) return 0 ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if [ -z "$CORE_DOMAIN" ]; then
|
||||
echo "This joins your Core's Tailscale network, so set up your Core first: configure core"
|
||||
return 1
|
||||
|
||||
@@ -13,11 +13,16 @@ is_installed() {
|
||||
command -v restic > /dev/null && command -v rclone > /dev/null && command -v secret-tool > /dev/null
|
||||
}
|
||||
|
||||
is_configured() {
|
||||
backups_on() {
|
||||
source "$COREDESKTOP/system/backup-env.sh" > /dev/null || return 1
|
||||
[ -n "$RESTIC_PASSWORD_COMMAND" ] && systemctl --user is-enabled -q coredesktop-backup.timer
|
||||
}
|
||||
|
||||
# Done when backing up to the main Core
|
||||
is_configured() {
|
||||
backups_on && [ "$BACKUP_WEBDAV" = "https://nextcloud.$CORE_DOMAIN/remote.php/dav/files/${CORE_EMAIL%@*}" ]
|
||||
}
|
||||
|
||||
save_secret() {
|
||||
printf '%s' "$3" | secret-tool store --label "CoreDesktop backup $1 ($2)" \
|
||||
coredesktop backup item "$1" url "$2"
|
||||
@@ -59,8 +64,78 @@ new_passphrase() {
|
||||
save_secret passphrase "$WEBDAV/$BACKUP_DIR" "$pass"
|
||||
}
|
||||
|
||||
# Stop the daily backup and any running now, and remove its units
|
||||
stop_backups() {
|
||||
systemctl --user disable --now coredesktop-backup.timer 2> /dev/null
|
||||
systemctl --user stop coredesktop-backup.service 2> /dev/null
|
||||
rm -f "$UNITS"/coredesktop-backup.{service,timer}
|
||||
systemctl --user daemon-reload
|
||||
}
|
||||
|
||||
# Delete the backup from Nextcloud, then what's on this computer for it:
|
||||
# without the backup, the passphrase and app password are no use
|
||||
delete_backups() {
|
||||
local app_password
|
||||
nextcloud_login || { echo "Couldn't sign in to Nextcloud."; return 1; }
|
||||
echo "Deleting $BACKUP_DIR from your Nextcloud files..."
|
||||
rclone purge ":webdav:$BACKUP_DIR" \
|
||||
|| { echo "rclone couldn't delete $BACKUP_DIR."; return 1; }
|
||||
echo "Deleted. Nextcloud keeps it in its trash bin, where it still uses space, until you empty it."
|
||||
|
||||
app_password="$(backup_secret nextcloud "$WEBDAV")"
|
||||
[ -n "$app_password" ] && nextcloud_revoke_app_password "$app_password"
|
||||
secret-tool clear coredesktop backup item nextcloud url "$WEBDAV"
|
||||
secret-tool clear coredesktop backup item passphrase url "$WEBDAV/$BACKUP_DIR"
|
||||
rm -f "$BACKUP_CONF"
|
||||
}
|
||||
|
||||
turn_off() {
|
||||
local answer
|
||||
WEBDAV="$BACKUP_WEBDAV"
|
||||
CORE_USER="$BACKUP_USER"
|
||||
NEXTCLOUD="${BACKUP_WEBDAV%%/remote.php/*}"
|
||||
|
||||
stop_backups
|
||||
echo "Backups are off."
|
||||
|
||||
echo
|
||||
echo "The backups made so far are still in $BACKUP_DIR in your Nextcloud files."
|
||||
if ! confirm "Delete them? They can't be restored from after that."; then
|
||||
echo "Kept them. To turn backups back on: configure backup"
|
||||
return 0
|
||||
fi
|
||||
read -rp "To delete them, type the folder name ($BACKUP_DIR): " answer
|
||||
if [ "$answer" != "$BACKUP_DIR" ]; then
|
||||
echo "That's not the folder name, so the backups were kept."
|
||||
return 0
|
||||
fi
|
||||
delete_backups
|
||||
}
|
||||
|
||||
run_configure() {
|
||||
local pass
|
||||
local pass choice
|
||||
if backups_on &> /dev/null; then
|
||||
if is_configured &> /dev/null; then
|
||||
echo "Your home folder is backed up daily to $BACKUP_DIR in your Nextcloud files."
|
||||
echo
|
||||
echo " 1) Set it up again"
|
||||
else
|
||||
echo "Your home folder is backed up daily to $BACKUP_DIR on ${BACKUP_WEBDAV%%/remote.php/*},"
|
||||
echo "which isn't your main Core."
|
||||
echo
|
||||
echo " 1) Back up to your main Core ($CORE_DOMAIN) instead; the backups so far stay where they are"
|
||||
fi
|
||||
echo " 2) Turn backups off"
|
||||
echo " q) Leave it as it is"
|
||||
echo
|
||||
read -rp "Choose: " choice
|
||||
case "$choice" in
|
||||
1) ;;
|
||||
2) turn_off; return ;;
|
||||
*) return 0 ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if [ -z "$CORE_DOMAIN" ] || [ -z "$CORE_EMAIL" ]; then
|
||||
echo "Backups go to your Nextcloud files, so set up your Core first: configure core"
|
||||
return 1
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Add an account to GNOME Online Accounts, the way Settings does.
|
||||
"""Add or remove an account in GNOME Online Accounts, the way Settings does.
|
||||
|
||||
Settings adds accounts by calling AddAccount on the Online Accounts service,
|
||||
which saves the account and keeps its password in the GNOME keyring. This
|
||||
@@ -9,6 +9,7 @@ so its password doesn't show up in the process list.
|
||||
Usage:
|
||||
goa-account exists <provider> <presentation-identity>
|
||||
goa-account add < account.json
|
||||
goa-account remove <provider> <presentation-identity>
|
||||
|
||||
account.json:
|
||||
{"provider": "owncloud", "identity": "...", "presentation_identity": "...",
|
||||
@@ -36,16 +37,20 @@ def accounts(bus):
|
||||
(objects,) = call(bus, "/org/gnome/OnlineAccounts",
|
||||
"org.freedesktop.DBus.ObjectManager", "GetManagedObjects",
|
||||
None, "(a{oa{sa{sv}}})")
|
||||
for interfaces in objects.values():
|
||||
for path, interfaces in objects.items():
|
||||
account = interfaces.get("org.gnome.OnlineAccounts.Account")
|
||||
if account:
|
||||
yield account
|
||||
yield path, account
|
||||
|
||||
|
||||
def find(bus, provider, presentation_identity):
|
||||
return [path for path, account in accounts(bus)
|
||||
if account.get("ProviderType") == provider
|
||||
and account.get("PresentationIdentity") == presentation_identity]
|
||||
|
||||
|
||||
def exists(bus, provider, presentation_identity):
|
||||
return any(account.get("ProviderType") == provider
|
||||
and account.get("PresentationIdentity") == presentation_identity
|
||||
for account in accounts(bus))
|
||||
return bool(find(bus, provider, presentation_identity))
|
||||
|
||||
|
||||
def add(bus, account):
|
||||
@@ -58,6 +63,11 @@ def add(bus, account):
|
||||
"org.gnome.OnlineAccounts.Manager", "AddAccount", parameters, "(o)")
|
||||
|
||||
|
||||
def remove(bus, provider, presentation_identity):
|
||||
for path in find(bus, provider, presentation_identity):
|
||||
call(bus, path, "org.gnome.OnlineAccounts.Account", "Remove", None, "()")
|
||||
|
||||
|
||||
def main():
|
||||
bus = Gio.bus_get_sync(Gio.BusType.SESSION, None)
|
||||
if len(sys.argv) == 4 and sys.argv[1] == "exists":
|
||||
@@ -68,6 +78,9 @@ def main():
|
||||
return 0
|
||||
add(bus, account)
|
||||
return 0
|
||||
if len(sys.argv) == 4 and sys.argv[1] == "remove":
|
||||
remove(bus, sys.argv[2], sys.argv[3])
|
||||
return 0
|
||||
print(__doc__.strip().split("\n\n")[2], file=sys.stderr)
|
||||
return 2
|
||||
|
||||
|
||||
@@ -25,3 +25,9 @@ nextcloud_app_password() {
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Revoke an app password, signing in with it. Uses CORE_USER and NEXTCLOUD.
|
||||
nextcloud_revoke_app_password() {
|
||||
auth_header "$CORE_USER" "$1" | curl -sf -o /dev/null -X DELETE -H @- \
|
||||
-H 'OCS-APIRequest: true' "$NEXTCLOUD/ocs/v2.php/core/apppassword"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
# configure can set up more than one Core, each in cores/<domain>.conf;
|
||||
# core.conf stays as the main Core's
|
||||
CORE_CONF="$HOME/.config/coredesktop/core.conf"
|
||||
CORES_DIR="$HOME/.config/coredesktop/cores"
|
||||
|
||||
[ -f "$CORE_CONF" ] || exit 0
|
||||
CORE_DOMAIN="$(source "$CORE_CONF" && echo "$CORE_DOMAIN")"
|
||||
[ -n "$CORE_DOMAIN" ] || exit 0
|
||||
mkdir -p "$CORES_DIR" || exit 1
|
||||
[ -f "$CORES_DIR/$CORE_DOMAIN.conf" ] || cp "$CORE_CONF" "$CORES_DIR/$CORE_DOMAIN.conf"
|
||||
Reference in New Issue
Block a user