#!/usr/bin/env bash

# Application permissions, as far as the desktop can actually enforce them.
#
# The rules:
#
#   1. The page never claims more than the portal can do. A native binary opens
#      /dev/video0 directly, and a settings page implying otherwise is worse
#      than one that says nothing -- so the limit is stated on the page, not
#      buried in a comment.
#   2. A device nothing has asked for is reported empty, not omitted. "No
#      application uses your microphone" and a page that quietly leaves the
#      microphone out look identical and mean very different things.
#   3. Absence is not failure. The store answers "No entry for microphone" for a
#      device nobody has requested; treating that as an error would make the
#      whole page fail because one device is unused.
#   4. Anything that is not an explicit "yes" is withheld. Guessing generously
#      about a camera is the wrong way to be wrong.
#   5. A refusal states its reason.
#
# The write path is exercised against an application id that does not exist, so
# no real application's camera access is changed. What is on this machine --
# OBS Studio and GNOME Snapshot -- is read, never written.

set -uo pipefail

repo_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
helper="$repo_dir/config/dot/quickshell/scripts/panama-permissions"
service="$repo_dir/config/dot/quickshell/services/Permissions.qml"
page="$repo_dir/config/dot/quickshell/modules/settings/PrivacyPage.qml"

probe="org.panama.ContractProbe"

fail() {
    printf 'permissions contract: %s\n' "$1" >&2
    exit 1
}

for path in "$helper" "$service" "$page"; do
    [[ -r "$path" ]] || fail "missing $path"
done
[[ -x "$helper" ]] || fail 'panama-permissions is not executable'

field() { python3 -c "import json,sys; print(json.load(sys.stdin)$1)"; }

state="$("$helper" snapshot)" || fail 'snapshot failed'

if [[ "$(printf '%s' "$state" | field "['available']")" != "True" ]]; then
    printf 'permissions contract: skipped (the portal permission store is not running)\n'
    exit 0
fi

# ── 1. The page states the limit ────────────────────────────────────────────

grep -q 'directly' "$page" \
    || fail 'the page does not say that programs outside the portal reach these devices anyway'

# ── 2 & 3. Unused devices are present and empty, not an error ───────────────

printf '%s' "$state" | python3 -c "
import json, sys
state = json.load(sys.stdin)
if state['error']:
    raise SystemExit(f\"snapshot reported an error: {state['error']}\")
names = [d['id'] for d in state['devices']]
for required in ('camera', 'microphone', 'speakers'):
    if required not in names:
        raise SystemExit(f'{required} is missing from the snapshot entirely')
" || fail 'a device with no recorded application was dropped or reported as an error'

# ── 4 & 5. The write path, on an application that does not exist ────────────

before="$(printf '%s' "$state" | field "['devices']")"

denied="$("$helper" set camera "$probe" deny)" || fail 'set deny failed'
reason="$(printf '%s' "$denied" | field "['error']")"
[[ -z "$reason" ]] || fail "denying refused a valid write: $reason"
printf '%s' "$denied" | python3 -c "
import json, sys
for device in json.load(sys.stdin)['devices']:
    for app in device['applications']:
        if app['app'] == '$probe':
            if app['allowed']:
                raise SystemExit('a denied application was reported as allowed')
            raise SystemExit(0)
raise SystemExit('the denied application was not written at all')
" || fail 'deny did not take effect -- the write path is not doing anything'

allowed="$("$helper" set camera "$probe" allow)" || fail 'set allow failed'
printf '%s' "$allowed" | python3 -c "
import json, sys
for device in json.load(sys.stdin)['devices']:
    for app in device['applications']:
        if app['app'] == '$probe' and app['allowed']:
            raise SystemExit(0)
raise SystemExit('allow did not take effect')
" || fail 'allow did not take effect'

# Refusals name their reason rather than merely failing.
reason="$(printf '%s' "$("$helper" set camera "$probe" maybe)" | field "['error']")"
[[ "$reason" == *"allow or deny"* ]] \
    || fail "an invalid decision was not refused with a reason (got: $reason)"

reason="$(printf '%s' "$("$helper" set nonsense "$probe" allow)" | field "['error']")"
[[ -n "$reason" ]] || fail 'an unknown device was accepted'

# ── Put it back ────────────────────────────────────────────────────────────

"$helper" forget camera "$probe" >/dev/null || fail 'forget failed'
after="$("$helper" snapshot | field "['devices']")"
[[ "$before" == "$after" ]] \
    || fail 'the contract changed recorded permissions and did not restore them'

printf 'permissions contract: ok\n'
