264 lines
8.1 KiB
Bash
264 lines
8.1 KiB
Bash
#!/usr/bin/env bash
|
||
set -euo pipefail
|
||
|
||
# Minimal KDE UI wrapper for Saikyo OS license install/status.
|
||
# Uses kdialog and pkexec.
|
||
|
||
if ! command -v kdialog >/dev/null 2>&1; then
|
||
echo "ERROR: kdialog not found" >&2
|
||
exit 1
|
||
fi
|
||
|
||
TITLE="SAIKYO OS — лицензия"
|
||
ICON="/usr/share/icons/hicolor/512x512/apps/saikyo-activation-logo.png"
|
||
|
||
human_duration() {
|
||
local s="${1:-0}"
|
||
if [[ -z "${s}" || ! "${s}" =~ ^[0-9]+$ ]]; then
|
||
printf '%s' "—"
|
||
return 0
|
||
fi
|
||
local d h m
|
||
d=$((s/86400))
|
||
h=$(((s%86400)/3600))
|
||
m=$(((s%3600)/60))
|
||
if [[ "$d" -gt 0 ]]; then
|
||
printf '%sd %sh %sm' "$d" "$h" "$m"
|
||
elif [[ "$h" -gt 0 ]]; then
|
||
printf '%sh %sm' "$h" "$m"
|
||
else
|
||
printf '%sm' "$m"
|
||
fi
|
||
}
|
||
|
||
parse_kv() {
|
||
# Reads key=value lines from stdin and exports them as shell vars.
|
||
local line k v
|
||
while IFS= read -r line; do
|
||
[[ -n "${line}" ]] || continue
|
||
case "${line}" in
|
||
*=*)
|
||
k=${line%%=*}
|
||
v=${line#*=}
|
||
k=${k//-/_}
|
||
case "${k}" in
|
||
status|trial_days|trial_remaining_seconds|valid_until|expired|org_id|org_name|tier|machine_id|signature)
|
||
printf -v "$k" '%s' "$v"
|
||
;;
|
||
esac
|
||
;;
|
||
esac
|
||
done
|
||
}
|
||
|
||
get_status_fields() {
|
||
status=""; trial_days=""; trial_remaining_seconds=""; valid_until=""; expired=""; org_id=""; org_name=""; tier=""; machine_id=""; signature=""
|
||
local out
|
||
out=$(/usr/sbin/saikyo-license status 2>/dev/null || true)
|
||
parse_kv <<<"${out}"
|
||
}
|
||
|
||
status_summary() {
|
||
get_status_fields
|
||
|
||
local state="UNKNOWN"
|
||
local rem="—"
|
||
|
||
if [[ "${status:-}" == "trial" ]]; then
|
||
state="TRIAL"
|
||
rem=$(human_duration "${trial_remaining_seconds:-0}")
|
||
elif [[ "${status:-}" == "missing" ]]; then
|
||
state="MISSING"
|
||
rem="—"
|
||
else
|
||
if [[ "${expired:-}" == "yes" ]]; then
|
||
state="EXPIRED"
|
||
else
|
||
# If we have a valid_until and not expired=yes, treat as active (even if signature says invalid we still show it).
|
||
if [[ -n "${valid_until:-}" ]]; then
|
||
state="ACTIVE"
|
||
else
|
||
state="UNKNOWN"
|
||
fi
|
||
fi
|
||
|
||
if [[ -n "${valid_until:-}" ]]; then
|
||
local now exp_s
|
||
now=$(date -u +%s 2>/dev/null || echo "")
|
||
exp_s=$(date -u -d "${valid_until}" +%s 2>/dev/null || echo "")
|
||
if [[ -n "${now}" && -n "${exp_s}" && "${exp_s}" =~ ^[0-9]+$ && "${now}" =~ ^[0-9]+$ && "${exp_s}" -gt "${now}" ]]; then
|
||
rem=$(human_duration $((exp_s - now)))
|
||
else
|
||
rem="—"
|
||
fi
|
||
fi
|
||
fi
|
||
|
||
local org="—"
|
||
[[ -n "${org_name:-}" ]] && org="${org_name}"
|
||
|
||
local tier_txt="—"
|
||
[[ -n "${tier:-}" ]] && tier_txt="${tier}"
|
||
|
||
local until_txt="—"
|
||
[[ -n "${valid_until:-}" ]] && until_txt="${valid_until}"
|
||
|
||
local sig_txt="—"
|
||
[[ -n "${signature:-}" ]] && sig_txt="${signature}"
|
||
|
||
printf '%s\n' \
|
||
"Статус: ${state}" \
|
||
"Осталось: ${rem}" \
|
||
"Организация: ${org}" \
|
||
"Тариф: ${tier_txt}" \
|
||
"Действует до: ${until_txt}" \
|
||
"Подпись: ${sig_txt}"
|
||
}
|
||
|
||
has_valid_license() {
|
||
# saikyo-license verify returns 0 only for a valid, installed license
|
||
/usr/sbin/saikyo-license verify >/dev/null 2>&1
|
||
}
|
||
|
||
show_status() {
|
||
kdialog --title "$TITLE" --icon "$ICON" --msgbox "$(status_summary)"
|
||
}
|
||
|
||
install_license() {
|
||
local json sig
|
||
|
||
json=$(kdialog --title "$TITLE" --getopenfilename "$HOME" "license.json|license.json (*.json)" 2>/dev/null || true)
|
||
[[ -n "${json}" ]] || return 0
|
||
|
||
sig=$(kdialog --title "$TITLE" --getopenfilename "$HOME" "license.sig|license.sig (*.sig)" 2>/dev/null || true)
|
||
[[ -n "${sig}" ]] || return 0
|
||
|
||
# Run privileged install
|
||
local cmd
|
||
cmd=(pkexec /usr/sbin/saikyo-license install "$json" "$sig")
|
||
|
||
local result
|
||
result=$(${cmd[@]} 2>&1) || {
|
||
kdialog --title "$TITLE" --icon "$ICON" --error "Ошибка установки лицензии:\n\n${result}"
|
||
return 1
|
||
}
|
||
|
||
kdialog --title "$TITLE" --icon "$ICON" --msgbox "Лицензия установлена.\n\n${result}"
|
||
show_status
|
||
}
|
||
|
||
install_response_code() {
|
||
local code
|
||
code=$(kdialog --title "$TITLE" --icon "$ICON" --inputbox "SAIKYO OS оффлайн активация\n\nВставьте response-код (SAI-RC / SAI-RESP2 / SAI-RESP)" "" 2>/dev/null || true)
|
||
[[ -n "${code}" ]] || return 0
|
||
|
||
local result
|
||
result=$(pkexec /usr/sbin/saikyo-license install-code "${code}" 2>&1) || {
|
||
kdialog --title "$TITLE" --icon "$ICON" --error "Ошибка оффлайн активации:\n\n${result}"
|
||
return 1
|
||
}
|
||
|
||
kdialog --title "$TITLE" --icon "$ICON" --msgbox "Лицензия установлена.\n\n${result}"
|
||
show_status
|
||
}
|
||
|
||
show_files_info() {
|
||
kdialog --title "$TITLE" --icon "$ICON" --msgbox "Файлы лицензии:\n\n/etc/saikyo/license/license.json\n/etc/saikyo/license/license.sig\n/etc/saikyo/license/trial_start (если trial)\n\nКлючи проверки:\n/usr/share/saikyo-os/license/saikyo-license-pub.pem\n/usr/share/saikyo-os/license/saikyo-license-ed25519-pub.pem" 2>/dev/null || true
|
||
}
|
||
|
||
show_diagnostics() {
|
||
local out
|
||
out=$( (/usr/sbin/saikyo-license status 2>&1 || true; echo; /usr/sbin/saikyo-license verify 2>&1 || true) | sed -n '1,200p' )
|
||
kdialog --title "$TITLE" --icon "$ICON" --msgbox "Диагностика (первые 200 строк):\n\n${out}" 2>/dev/null || true
|
||
}
|
||
|
||
show_machine_id() {
|
||
local mid
|
||
mid=$(cat /etc/machine-id 2>/dev/null || true)
|
||
if [[ -z "${mid}" ]]; then
|
||
kdialog --title "$TITLE" --icon "$ICON" --error "Не удалось прочитать /etc/machine-id"
|
||
return 1
|
||
fi
|
||
kdialog --title "$TITLE" --icon "$ICON" --msgbox "Идентификатор машины (machine-id):\n\n${mid}"
|
||
}
|
||
|
||
activate_online() {
|
||
local token
|
||
local server
|
||
server="https://saikyo-os.ru/license"
|
||
|
||
token=$(kdialog --title "$TITLE" --icon "$ICON" --inputbox "SAIKYO OS активация\n\nВведите токен активации" "" 2>/dev/null || true)
|
||
[[ -n "${token}" ]] || return 0
|
||
|
||
local result
|
||
result=$(pkexec /usr/sbin/saikyo-license activate --token "${token}" --server "${server}" 2>&1) || {
|
||
kdialog --title "$TITLE" --icon "$ICON" --error "Ошибка онлайн-активации:\n\n${result}"
|
||
return 1
|
||
}
|
||
|
||
kdialog --title "$TITLE" --icon "$ICON" --msgbox "Онлайн-активация выполнена.\n\n${result}"
|
||
show_status
|
||
}
|
||
|
||
open_portal() {
|
||
if command -v xdg-open >/dev/null 2>&1; then
|
||
xdg-open "https://saikyo-os.ru/license" >/dev/null 2>&1 || true
|
||
fi
|
||
}
|
||
|
||
force_activation() {
|
||
# Non-closable UX (as much as possible): closing/canceling just re-opens.
|
||
# The only exit is a successful activation (valid license).
|
||
if has_valid_license; then
|
||
exit 0
|
||
fi
|
||
|
||
while true; do
|
||
if has_valid_license; then
|
||
kdialog --title "$TITLE" --icon "$ICON" --msgbox "Лицензия активирована. Спасибо."
|
||
exit 0
|
||
fi
|
||
|
||
kdialog --title "$TITLE" --icon "$ICON" --msgbox "SAIKYO OS активация\n\nДля продолжения работы необходимо активировать лицензию.\n\nНажмите OK, чтобы ввести токен." 2>/dev/null || true
|
||
|
||
if activate_online; then
|
||
:
|
||
else
|
||
# Show error handled inside activate_online; loop.
|
||
:
|
||
fi
|
||
done
|
||
}
|
||
|
||
if [[ "${1:-}" == "--force-activate" ]]; then
|
||
shift || true
|
||
force_activation
|
||
fi
|
||
|
||
while true; do
|
||
header=$(status_summary)
|
||
action=$(kdialog --title "$TITLE" --icon "$ICON" --menu "${header}\n\nДействия:" \
|
||
status "Показать статус" \
|
||
activate "Онлайн-активация/продление (токен)" \
|
||
offline "Оффлайн активация (response-код)" \
|
||
install "Установить лицензию (license.json + license.sig)" \
|
||
portal "Открыть портал" \
|
||
files "Где лежат файлы/ключи" \
|
||
diag "Диагностика" \
|
||
machine-id "Показать machine-id" \
|
||
exit "Выход" \
|
||
2>/dev/null || true)
|
||
|
||
case "$action" in
|
||
status) show_status;;
|
||
activate) activate_online;;
|
||
offline) install_response_code;;
|
||
install) install_license;;
|
||
portal) open_portal;;
|
||
files) show_files_info;;
|
||
diag) show_diagnostics;;
|
||
machine-id) show_machine_id;;
|
||
exit|"") exit 0;;
|
||
esac
|
||
done
|