#!/usr/bin/env bash
# Run the 10-point breach check on a single user.
# Usage: user-breach-check.sh <tenant-id-or-domain> <upn>
# Writes raw JSON to /tmp/remediation-tool/{tenant-id}/user-breach/{user-slug}/
# Prints a summary table to stdout.
set -euo pipefail

SCRIPT_DIR="$(dirname "${BASH_SOURCE[0]}")"
__ROOT="${CLAUDETOOLS_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../../../.." && pwd)}"

TENANT_INPUT="${1:?usage: user-breach-check.sh <tenant-id|domain> <upn>}"
UPN="${2:?usage: user-breach-check.sh <tenant-id|domain> <upn>}"

TENANT_ID=$("$SCRIPT_DIR/resolve-tenant.sh" "$TENANT_INPUT")
GT=$("$SCRIPT_DIR/get-token.sh" "$TENANT_ID" investigator)
# Exchange REST (adminapi InvokeCommand) MUST use exchange-op: it holds Exchange.ManageAsApp
# + Exchange Administrator. investigator-exo 401s (Security Investigator app lacks ManageAsApp)
# — see references/gotchas.md "Exchange REST goes through exchange-op". (fixed 2026-07-16)
EXO=$("$SCRIPT_DIR/get-token.sh" "$TENANT_ID" exchange-op) || EXO=""

USER_SLUG=$(echo "$UPN" | tr '@.' '__')
OUT="/tmp/remediation-tool/$TENANT_ID/user-breach/$USER_SLUG"
mkdir -p "$OUT"

echo "[info] tenant=$TENANT_ID user=$UPN out=$OUT"

# --- 0. Resolve user object ID ---
curl -s -H "Authorization: Bearer $GT" \
  "https://graph.microsoft.com/v1.0/users/${UPN}?\$select=id,displayName,userPrincipalName,mail,accountEnabled,createdDateTime,lastPasswordChangeDateTime" \
  > "$OUT/00_user.json"
UID_=$(jq -r '.id // empty' "$OUT/00_user.json")
if [[ -z "$UID_" ]]; then
  echo "ERROR: user not found or Graph returned error" >&2
  cat "$OUT/00_user.json" >&2
  bash "$__ROOT/.claude/scripts/log-skill-error.sh" "remediation-tool" "user-breach-check: user not found or Graph returned error resolving user object" --context "tenant=$TENANT_ID upn=$UPN err=$(jq -r '.error.code // empty' "$OUT/00_user.json" 2>/dev/null)" >/dev/null 2>&1 || true
  exit 1
fi
echo "[info] object id: $UID_"

# --- 1. Inbox rules (Graph v1.0 — visible only) ---
curl -s -H "Authorization: Bearer $GT" \
  "https://graph.microsoft.com/v1.0/users/${UPN}/mailFolders/inbox/messageRules" \
  > "$OUT/01_inbox_rules_graph.json" &

# --- 2. Mailbox settings (forwarding flags) ---
curl -s -H "Authorization: Bearer $GT" \
  "https://graph.microsoft.com/v1.0/users/${UPN}/mailboxSettings" \
  > "$OUT/02_mailbox_settings.json" &

# --- 4. OAuth consents + app role assignments ---
curl -s -H "Authorization: Bearer $GT" \
  "https://graph.microsoft.com/v1.0/users/${UPN}/oauth2PermissionGrants" \
  > "$OUT/04a_oauth_grants.json" &
curl -s -H "Authorization: Bearer $GT" \
  "https://graph.microsoft.com/v1.0/users/${UPN}/appRoleAssignments" \
  > "$OUT/04b_app_role_assignments.json" &

# --- 5. Authentication methods ---
curl -s -H "Authorization: Bearer $GT" \
  "https://graph.microsoft.com/v1.0/users/${UPN}/authentication/methods" \
  > "$OUT/05_auth_methods.json" &

wait

# --- 6. Sign-ins 30d (v1.0 — interactive only) ---
FROM=$(date -u -d '30 days ago' +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u -v-30d +%Y-%m-%dT%H:%M:%SZ)
curl -s -H "Authorization: Bearer $GT" \
  "https://graph.microsoft.com/v1.0/auditLogs/signIns?\$filter=userId%20eq%20'${UID_}'%20and%20createdDateTime%20ge%20${FROM}&\$top=200" \
  > "$OUT/06_signins.json" &

# --- 7. Directory audits (targetResources = user) 30d ---
curl -s -H "Authorization: Bearer $GT" \
  "https://graph.microsoft.com/v1.0/auditLogs/directoryAudits?\$filter=activityDateTime%20ge%20${FROM}%20and%20targetResources/any(t:t/id%20eq%20'${UID_}')&\$top=200" \
  > "$OUT/07_dir_audits.json" &

# --- 8. Risky user + risk detections (403 if app lacks IdentityRiskyUser scope) ---
curl -s -H "Authorization: Bearer $GT" \
  "https://graph.microsoft.com/v1.0/identityProtection/riskyUsers/${UID_}" \
  > "$OUT/08a_risky_user.json" &
curl -s -H "Authorization: Bearer $GT" \
  "https://graph.microsoft.com/v1.0/identityProtection/riskDetections?\$filter=userId%20eq%20'${UID_}'&\$top=100" \
  > "$OUT/08b_risk_detections.json" &

# --- 9. Sent items (last 25) ---
curl -s -H "Authorization: Bearer $GT" \
  "https://graph.microsoft.com/v1.0/users/${UPN}/mailFolders/sentitems/messages?\$top=25&\$orderby=sentDateTime%20desc&\$select=subject,toRecipients,sentDateTime,from" \
  > "$OUT/09_sent.json" &

# --- 10. Deleted items (last 25) ---
curl -s -H "Authorization: Bearer $GT" \
  "https://graph.microsoft.com/v1.0/users/${UPN}/mailFolders/deleteditems/messages?\$top=25&\$orderby=receivedDateTime%20desc&\$select=subject,from,receivedDateTime" \
  > "$OUT/10_deleted.json" &

wait

# --- 3. Exchange REST (hidden rules + delegates + SendAs + Get-Mailbox) ---
if [[ -n "$EXO" ]]; then
  EX_URL="https://outlook.office365.com/adminapi/beta/${TENANT_ID}/InvokeCommand"

  curl -s -X POST -H "Authorization: Bearer $EXO" -H "Content-Type: application/json" "$EX_URL" \
    -d "{\"CmdletInput\":{\"CmdletName\":\"Get-InboxRule\",\"Parameters\":{\"Mailbox\":\"${UPN}\",\"IncludeHidden\":true}}}" \
    > "$OUT/03a_InboxRule_hidden.json" &

  curl -s -X POST -H "Authorization: Bearer $EXO" -H "Content-Type: application/json" "$EX_URL" \
    -d "{\"CmdletInput\":{\"CmdletName\":\"Get-MailboxPermission\",\"Parameters\":{\"Identity\":\"${UPN}\"}}}" \
    > "$OUT/03b_MailboxPermission.json" &

  curl -s -X POST -H "Authorization: Bearer $EXO" -H "Content-Type: application/json" "$EX_URL" \
    -d "{\"CmdletInput\":{\"CmdletName\":\"Get-RecipientPermission\",\"Parameters\":{\"Identity\":\"${UPN}\"}}}" \
    > "$OUT/03c_RecipientPermission.json" &

  curl -s -X POST -H "Authorization: Bearer $EXO" -H "Content-Type: application/json" "$EX_URL" \
    -d "{\"CmdletInput\":{\"CmdletName\":\"Get-Mailbox\",\"Parameters\":{\"Identity\":\"${UPN}\"}}}" \
    > "$OUT/03d_Mailbox.json" &

  wait
else
  echo "[warn] no Exchange token; skipping check 3 (hidden rules/delegates/SendAs/mailbox forwarding flags)"
fi

# --- Summary table ---
echo ""
echo "=== Summary: $UPN ==="
jq -r '"account_enabled: \(.accountEnabled)  lastPwChange: \(.lastPasswordChangeDateTime)  created: \(.createdDateTime)"' "$OUT/00_user.json"
echo "01 inbox_rules (Graph):    $(jq '.value | length // "error"' "$OUT/01_inbox_rules_graph.json")"
echo "02 forwarding:             fwdSmtp=$(jq -r '.automaticRepliesSetting.status // "n/a"' "$OUT/02_mailbox_settings.json" 2>/dev/null) (see mailbox Get-Mailbox for forwarding fields)"
echo "04a oauth_grants:          $(jq '.value | length // "error"' "$OUT/04a_oauth_grants.json")"
echo "04b app_role_assignments:  $(jq '.value | length // "error"' "$OUT/04b_app_role_assignments.json")"
echo "05 auth_methods:           $(jq '.value | length // "error"' "$OUT/05_auth_methods.json")"
echo "06 signins (30d, interactive): $(jq '.value | length // "error"' "$OUT/06_signins.json")  non-US: $(jq '[.value[]?|select(.location.countryOrRegion != "US" and .location.countryOrRegion != null)] | length' "$OUT/06_signins.json" 2>/dev/null)"
echo "07 dir_audits (30d):       $(jq '.value | length // "error"' "$OUT/07_dir_audits.json")"
echo "08 risky_user:             $(jq -r '.riskLevel // .error.code // "none"' "$OUT/08a_risky_user.json" 2>/dev/null)"
echo "08 risk_detections:        $(jq '.value | length // (.error.code // "error")' "$OUT/08b_risk_detections.json")"
echo "09 sent (recent 25):       $(jq '.value | length // "error"' "$OUT/09_sent.json")"
echo "10 deleted (recent 25):    $(jq '.value | length // "error"' "$OUT/10_deleted.json")"
if [[ -f "$OUT/03a_InboxRule_hidden.json" ]]; then
  HIDDEN=$(jq '.value | length // (.error.code // "?")' "$OUT/03a_InboxRule_hidden.json" 2>/dev/null || echo "?")
  echo "03a hidden_inbox_rules:    $HIDDEN"
  echo "03b mailbox_permissions:   $(jq '[.value[]? | select(.User != "NT AUTHORITY\\SELF")] | length // "?"' "$OUT/03b_MailboxPermission.json" 2>/dev/null) non-SELF"
  echo "03c send_as:               $(jq '[.value[]? | select(.Trustee != "NT AUTHORITY\\SELF")] | length // "?"' "$OUT/03c_RecipientPermission.json" 2>/dev/null) non-SELF"
  echo "03d mailbox_forwarding:    fwdAddr=$(jq -r '.value[0].ForwardingAddress // "null"' "$OUT/03d_Mailbox.json" 2>/dev/null)  fwdSmtp=$(jq -r '.value[0].ForwardingSmtpAddress // "null"' "$OUT/03d_Mailbox.json" 2>/dev/null)"
else
  echo "03 exchange_rest:          SKIPPED (no exchange token — tenant likely needs Exchange Admin role assigned)"
fi
echo ""
echo "[info] raw artifacts: $OUT"
