- Add shared kiss-theme.js module for consistent dark theme across views
- Add eye toggle button (👁️) to switch between KISS and LuCI modes
- Add git repo status methods to luci.gitea RPCD:
- get_repo_status: branch, ahead/behind, staged/modified files
- get_commit_history: recent commits with stats
- get_commit_stats: daily commit counts for graphs
- Update InterceptoR overview with KISS styling and responsive grid
- Fix quick links paths (network-tweaks → admin/network/)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1028 lines
28 KiB
Bash
Executable File
1028 lines
28 KiB
Bash
Executable File
#!/bin/sh
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
# LuCI RPC backend for Gitea Platform
|
|
# Copyright (C) 2025 CyberMind.fr
|
|
|
|
. /lib/functions.sh
|
|
. /usr/share/libubox/jshn.sh
|
|
|
|
CONFIG="gitea"
|
|
LXC_NAME="gitea"
|
|
LXC_PATH="/srv/lxc"
|
|
DATA_PATH="/srv/gitea"
|
|
GITEA_VERSION="1.22.6"
|
|
|
|
# JSON helpers
|
|
json_init_obj() { json_init; json_add_object "result"; }
|
|
json_close_obj() { json_close_object; json_dump; }
|
|
|
|
json_error() {
|
|
json_init
|
|
json_add_object "error"
|
|
json_add_string "message" "$1"
|
|
json_close_object
|
|
json_dump
|
|
}
|
|
|
|
json_success() {
|
|
json_init_obj
|
|
json_add_boolean "success" 1
|
|
[ -n "$1" ] && json_add_string "message" "$1"
|
|
json_close_obj
|
|
}
|
|
|
|
# Check if container is running
|
|
lxc_running() {
|
|
lxc-info -n "$LXC_NAME" -s 2>/dev/null | grep -q "RUNNING"
|
|
}
|
|
|
|
# Check if container exists
|
|
lxc_exists() {
|
|
[ -f "$LXC_PATH/$LXC_NAME/config" ] && [ -d "$LXC_PATH/$LXC_NAME/rootfs" ]
|
|
}
|
|
|
|
# Get service status
|
|
get_status() {
|
|
local enabled running installed uptime
|
|
local http_port ssh_port data_path memory_limit app_name domain
|
|
|
|
config_load "$CONFIG"
|
|
config_get enabled main enabled "0"
|
|
config_get http_port main http_port "3000"
|
|
config_get ssh_port main ssh_port "2222"
|
|
config_get data_path main data_path "/srv/gitea"
|
|
config_get memory_limit main memory_limit "512M"
|
|
config_get app_name main app_name "SecuBox Git"
|
|
config_get domain main domain "git.local"
|
|
|
|
running="false"
|
|
installed="false"
|
|
uptime=""
|
|
|
|
if lxc_exists; then
|
|
installed="true"
|
|
fi
|
|
|
|
if lxc_running; then
|
|
running="true"
|
|
uptime=$(lxc-info -n "$LXC_NAME" 2>/dev/null | grep -i "cpu use" | head -1 | awk '{print $3}')
|
|
fi
|
|
|
|
# Count repositories
|
|
local repo_count=0
|
|
DATA_PATH="$data_path"
|
|
if [ -d "$DATA_PATH/git/repositories" ]; then
|
|
repo_count=$(find "$DATA_PATH/git/repositories" -name "*.git" -type d 2>/dev/null | wc -l)
|
|
fi
|
|
|
|
# Get disk usage
|
|
local disk_usage="0"
|
|
if [ -d "$DATA_PATH" ]; then
|
|
disk_usage=$(du -sh "$DATA_PATH" 2>/dev/null | awk '{print $1}' || echo "0")
|
|
fi
|
|
|
|
# Get LAN IP for URL
|
|
local lan_ip
|
|
lan_ip=$(uci -q get network.lan.ipaddr || echo "192.168.1.1")
|
|
|
|
json_init_obj
|
|
json_add_boolean "enabled" "$( [ "$enabled" = "1" ] && echo 1 || echo 0 )"
|
|
json_add_boolean "running" "$( [ "$running" = "true" ] && echo 1 || echo 0 )"
|
|
json_add_boolean "installed" "$( [ "$installed" = "true" ] && echo 1 || echo 0 )"
|
|
json_add_string "uptime" "$uptime"
|
|
json_add_int "http_port" "$http_port"
|
|
json_add_int "ssh_port" "$ssh_port"
|
|
json_add_string "data_path" "$data_path"
|
|
json_add_string "memory_limit" "$memory_limit"
|
|
json_add_string "app_name" "$app_name"
|
|
json_add_string "domain" "$domain"
|
|
json_add_int "repo_count" "$repo_count"
|
|
json_add_string "disk_usage" "$disk_usage"
|
|
json_add_string "http_url" "http://${lan_ip}:${http_port}"
|
|
json_add_string "ssh_url" "ssh://git@${lan_ip}:${ssh_port}"
|
|
json_add_string "container_name" "$LXC_NAME"
|
|
json_add_string "version" "$GITEA_VERSION"
|
|
json_close_obj
|
|
}
|
|
|
|
# Get statistics
|
|
get_stats() {
|
|
local data_path
|
|
config_load "$CONFIG"
|
|
config_get data_path main data_path "/srv/gitea"
|
|
|
|
local repo_count=0
|
|
local user_count=0
|
|
local disk_usage="0"
|
|
|
|
# Count repositories
|
|
if [ -d "$data_path/git/repositories" ]; then
|
|
repo_count=$(find "$data_path/git/repositories" -name "*.git" -type d 2>/dev/null | wc -l)
|
|
fi
|
|
|
|
# Get disk usage
|
|
if [ -d "$data_path" ]; then
|
|
disk_usage=$(du -sh "$data_path" 2>/dev/null | awk '{print $1}' || echo "0")
|
|
fi
|
|
|
|
# Count users (if we can query the database)
|
|
if [ -f "$data_path/gitea.db" ] && command -v sqlite3 >/dev/null 2>&1; then
|
|
user_count=$(sqlite3 "$data_path/gitea.db" "SELECT COUNT(*) FROM user" 2>/dev/null || echo "0")
|
|
fi
|
|
|
|
json_init_obj
|
|
json_add_int "repo_count" "$repo_count"
|
|
json_add_int "user_count" "$user_count"
|
|
json_add_string "disk_usage" "$disk_usage"
|
|
json_close_obj
|
|
}
|
|
|
|
# Get configuration
|
|
get_config() {
|
|
local http_port ssh_port http_host data_path memory_limit enabled app_name domain
|
|
local protocol disable_registration require_signin landing_page
|
|
|
|
config_load "$CONFIG"
|
|
|
|
# Main settings
|
|
config_get http_port main http_port "3000"
|
|
config_get ssh_port main ssh_port "2222"
|
|
config_get http_host main http_host "0.0.0.0"
|
|
config_get data_path main data_path "/srv/gitea"
|
|
config_get memory_limit main memory_limit "512M"
|
|
config_get enabled main enabled "0"
|
|
config_get app_name main app_name "SecuBox Git"
|
|
config_get domain main domain "git.local"
|
|
|
|
# Server settings
|
|
config_get protocol server protocol "http"
|
|
config_get disable_registration server disable_registration "false"
|
|
config_get require_signin server require_signin "false"
|
|
config_get landing_page server landing_page "explore"
|
|
|
|
json_init_obj
|
|
json_add_object "main"
|
|
json_add_boolean "enabled" "$( [ "$enabled" = "1" ] && echo 1 || echo 0 )"
|
|
json_add_int "http_port" "$http_port"
|
|
json_add_int "ssh_port" "$ssh_port"
|
|
json_add_string "http_host" "$http_host"
|
|
json_add_string "data_path" "$data_path"
|
|
json_add_string "memory_limit" "$memory_limit"
|
|
json_add_string "app_name" "$app_name"
|
|
json_add_string "domain" "$domain"
|
|
json_close_object
|
|
|
|
json_add_object "server"
|
|
json_add_string "protocol" "$protocol"
|
|
json_add_boolean "disable_registration" "$( [ "$disable_registration" = "true" ] && echo 1 || echo 0 )"
|
|
json_add_boolean "require_signin" "$( [ "$require_signin" = "true" ] && echo 1 || echo 0 )"
|
|
json_add_string "landing_page" "$landing_page"
|
|
json_close_object
|
|
|
|
json_close_obj
|
|
}
|
|
|
|
# Save configuration
|
|
save_config() {
|
|
read -r input
|
|
|
|
local http_port ssh_port http_host data_path memory_limit enabled app_name domain
|
|
local protocol disable_registration require_signin landing_page
|
|
|
|
http_port=$(echo "$input" | jsonfilter -e '@.http_port' 2>/dev/null)
|
|
ssh_port=$(echo "$input" | jsonfilter -e '@.ssh_port' 2>/dev/null)
|
|
http_host=$(echo "$input" | jsonfilter -e '@.http_host' 2>/dev/null)
|
|
data_path=$(echo "$input" | jsonfilter -e '@.data_path' 2>/dev/null)
|
|
memory_limit=$(echo "$input" | jsonfilter -e '@.memory_limit' 2>/dev/null)
|
|
enabled=$(echo "$input" | jsonfilter -e '@.enabled' 2>/dev/null)
|
|
app_name=$(echo "$input" | jsonfilter -e '@.app_name' 2>/dev/null)
|
|
domain=$(echo "$input" | jsonfilter -e '@.domain' 2>/dev/null)
|
|
protocol=$(echo "$input" | jsonfilter -e '@.protocol' 2>/dev/null)
|
|
disable_registration=$(echo "$input" | jsonfilter -e '@.disable_registration' 2>/dev/null)
|
|
require_signin=$(echo "$input" | jsonfilter -e '@.require_signin' 2>/dev/null)
|
|
landing_page=$(echo "$input" | jsonfilter -e '@.landing_page' 2>/dev/null)
|
|
|
|
[ -n "$http_port" ] && uci set "${CONFIG}.main.http_port=$http_port"
|
|
[ -n "$ssh_port" ] && uci set "${CONFIG}.main.ssh_port=$ssh_port"
|
|
[ -n "$http_host" ] && uci set "${CONFIG}.main.http_host=$http_host"
|
|
[ -n "$data_path" ] && uci set "${CONFIG}.main.data_path=$data_path"
|
|
[ -n "$memory_limit" ] && uci set "${CONFIG}.main.memory_limit=$memory_limit"
|
|
[ -n "$enabled" ] && uci set "${CONFIG}.main.enabled=$enabled"
|
|
[ -n "$app_name" ] && uci set "${CONFIG}.main.app_name=$app_name"
|
|
[ -n "$domain" ] && uci set "${CONFIG}.main.domain=$domain"
|
|
[ -n "$protocol" ] && uci set "${CONFIG}.server.protocol=$protocol"
|
|
[ -n "$disable_registration" ] && uci set "${CONFIG}.server.disable_registration=$disable_registration"
|
|
[ -n "$require_signin" ] && uci set "${CONFIG}.server.require_signin=$require_signin"
|
|
[ -n "$landing_page" ] && uci set "${CONFIG}.server.landing_page=$landing_page"
|
|
|
|
uci commit "$CONFIG"
|
|
|
|
json_success "Configuration saved"
|
|
}
|
|
|
|
# Start service
|
|
start_service() {
|
|
if lxc_running; then
|
|
json_error "Service is already running"
|
|
return
|
|
fi
|
|
|
|
if ! lxc_exists; then
|
|
json_error "Container not installed. Run install first."
|
|
return
|
|
fi
|
|
|
|
/etc/init.d/gitea start >/dev/null 2>&1 &
|
|
|
|
sleep 3
|
|
if lxc_running; then
|
|
json_success "Service started"
|
|
else
|
|
json_error "Failed to start service"
|
|
fi
|
|
}
|
|
|
|
# Stop service
|
|
stop_service() {
|
|
if ! lxc_running; then
|
|
json_error "Service is not running"
|
|
return
|
|
fi
|
|
|
|
/etc/init.d/gitea stop >/dev/null 2>&1
|
|
|
|
sleep 2
|
|
if ! lxc_running; then
|
|
json_success "Service stopped"
|
|
else
|
|
json_error "Failed to stop service"
|
|
fi
|
|
}
|
|
|
|
# Restart service
|
|
restart_service() {
|
|
/etc/init.d/gitea restart >/dev/null 2>&1 &
|
|
|
|
sleep 4
|
|
if lxc_running; then
|
|
json_success "Service restarted"
|
|
else
|
|
json_error "Service restart failed"
|
|
fi
|
|
}
|
|
|
|
# Install Gitea
|
|
install() {
|
|
if lxc_exists; then
|
|
json_error "Already installed. Use update to refresh."
|
|
return
|
|
fi
|
|
|
|
# Run install in background
|
|
/usr/sbin/giteactl install >/var/log/gitea-install.log 2>&1 &
|
|
|
|
json_init_obj
|
|
json_add_boolean "started" 1
|
|
json_add_string "message" "Installation started in background"
|
|
json_add_string "log_file" "/var/log/gitea-install.log"
|
|
json_close_obj
|
|
}
|
|
|
|
# Uninstall Gitea
|
|
uninstall() {
|
|
/usr/sbin/giteactl uninstall >/dev/null 2>&1
|
|
|
|
if ! lxc_exists; then
|
|
json_success "Uninstalled successfully"
|
|
else
|
|
json_error "Uninstall failed"
|
|
fi
|
|
}
|
|
|
|
# Update Gitea
|
|
update() {
|
|
if ! lxc_exists; then
|
|
json_error "Not installed. Run install first."
|
|
return
|
|
fi
|
|
|
|
# Run update in background
|
|
/usr/sbin/giteactl update >/var/log/gitea-update.log 2>&1 &
|
|
|
|
json_init_obj
|
|
json_add_boolean "started" 1
|
|
json_add_string "message" "Update started in background"
|
|
json_add_string "log_file" "/var/log/gitea-update.log"
|
|
json_close_obj
|
|
}
|
|
|
|
# Get logs
|
|
get_logs() {
|
|
read -r input
|
|
local lines
|
|
lines=$(echo "$input" | jsonfilter -e '@.lines' 2>/dev/null)
|
|
[ -z "$lines" ] && lines=100
|
|
|
|
json_init_obj
|
|
json_add_array "logs"
|
|
|
|
# Get container logs if running
|
|
if lxc_running; then
|
|
local data_path
|
|
config_load "$CONFIG"
|
|
config_get data_path main data_path "/srv/gitea"
|
|
|
|
if [ -f "$data_path/log/gitea.log" ]; then
|
|
tail -n "$lines" "$data_path/log/gitea.log" 2>/dev/null | while IFS= read -r line; do
|
|
json_add_string "" "$line"
|
|
done
|
|
fi
|
|
fi
|
|
|
|
# Also check install/update logs
|
|
for logfile in /var/log/gitea-install.log /var/log/gitea-update.log; do
|
|
[ -f "$logfile" ] || continue
|
|
tail -n 50 "$logfile" 2>/dev/null | while IFS= read -r line; do
|
|
json_add_string "" "$line"
|
|
done
|
|
done
|
|
|
|
json_close_array
|
|
json_close_obj
|
|
}
|
|
|
|
# List repositories
|
|
list_repos() {
|
|
local data_path
|
|
config_load "$CONFIG"
|
|
config_get data_path main data_path "/srv/gitea"
|
|
|
|
json_init_obj
|
|
json_add_array "repos"
|
|
|
|
local repo_root="$data_path/git/repositories"
|
|
if [ -d "$repo_root" ]; then
|
|
# Use temp file to avoid subshell issue with piped while loop
|
|
local tmpfile="/tmp/gitea-repos.$$"
|
|
find "$repo_root" -name "*.git" -type d 2>/dev/null > "$tmpfile"
|
|
|
|
while read -r repo; do
|
|
[ -z "$repo" ] && continue
|
|
local rel_path="${repo#$repo_root/}"
|
|
local name=$(basename "$repo" .git)
|
|
local owner=$(dirname "$rel_path")
|
|
local size=$(du -sh "$repo" 2>/dev/null | awk '{print $1}' || echo "0")
|
|
|
|
# Get last commit time if possible
|
|
local mtime=""
|
|
if [ -f "$repo/refs/heads/master" ]; then
|
|
mtime=$(stat -c %Y "$repo/refs/heads/master" 2>/dev/null || echo "")
|
|
elif [ -f "$repo/refs/heads/main" ]; then
|
|
mtime=$(stat -c %Y "$repo/refs/heads/main" 2>/dev/null || echo "")
|
|
fi
|
|
|
|
json_add_object ""
|
|
json_add_string "name" "$name"
|
|
json_add_string "owner" "$owner"
|
|
json_add_string "path" "$repo"
|
|
json_add_string "size" "$size"
|
|
[ -n "$mtime" ] && json_add_int "mtime" "$mtime"
|
|
json_close_object
|
|
done < "$tmpfile"
|
|
|
|
rm -f "$tmpfile"
|
|
fi
|
|
|
|
json_close_array
|
|
json_add_string "repo_root" "$repo_root"
|
|
json_close_obj
|
|
}
|
|
|
|
# Get repository details
|
|
get_repo() {
|
|
read -r input
|
|
local name owner
|
|
name=$(echo "$input" | jsonfilter -e '@.name' 2>/dev/null)
|
|
owner=$(echo "$input" | jsonfilter -e '@.owner' 2>/dev/null)
|
|
|
|
if [ -z "$name" ]; then
|
|
json_error "Missing repository name"
|
|
return
|
|
fi
|
|
|
|
local data_path
|
|
config_load "$CONFIG"
|
|
config_get data_path main data_path "/srv/gitea"
|
|
|
|
local repo_path="$data_path/git/repositories"
|
|
[ -n "$owner" ] && repo_path="$repo_path/$owner"
|
|
repo_path="$repo_path/${name}.git"
|
|
|
|
if [ ! -d "$repo_path" ]; then
|
|
json_error "Repository not found"
|
|
return
|
|
fi
|
|
|
|
local size=$(du -sh "$repo_path" 2>/dev/null | awk '{print $1}' || echo "0")
|
|
local branches=$(ls -1 "$repo_path/refs/heads" 2>/dev/null | wc -l)
|
|
|
|
# Get LAN IP
|
|
local lan_ip
|
|
local http_port ssh_port
|
|
config_get http_port main http_port "3000"
|
|
config_get ssh_port main ssh_port "2222"
|
|
lan_ip=$(uci -q get network.lan.ipaddr || echo "192.168.1.1")
|
|
|
|
local clone_url="http://${lan_ip}:${http_port}/${owner}/${name}.git"
|
|
local ssh_clone="git@${lan_ip}:${ssh_port}/${owner}/${name}.git"
|
|
|
|
json_init_obj
|
|
json_add_string "name" "$name"
|
|
json_add_string "owner" "$owner"
|
|
json_add_string "path" "$repo_path"
|
|
json_add_string "size" "$size"
|
|
json_add_int "branches" "$branches"
|
|
json_add_string "clone_url" "$clone_url"
|
|
json_add_string "ssh_clone" "$ssh_clone"
|
|
json_close_obj
|
|
}
|
|
|
|
# List users (from SQLite if available)
|
|
list_users() {
|
|
local data_path
|
|
config_load "$CONFIG"
|
|
config_get data_path main data_path "/srv/gitea"
|
|
|
|
json_init_obj
|
|
json_add_array "users"
|
|
|
|
local db_file="$data_path/gitea.db"
|
|
if [ -f "$db_file" ] && command -v sqlite3 >/dev/null 2>&1; then
|
|
sqlite3 -separator '|' "$db_file" \
|
|
"SELECT id, name, lower_name, email, is_admin, created_unix FROM user" 2>/dev/null | \
|
|
while IFS='|' read -r id name lower_name email is_admin created; do
|
|
json_add_object ""
|
|
json_add_int "id" "$id"
|
|
json_add_string "name" "$name"
|
|
json_add_string "email" "$email"
|
|
json_add_boolean "is_admin" "$is_admin"
|
|
[ -n "$created" ] && json_add_int "created" "$created"
|
|
json_close_object
|
|
done
|
|
fi
|
|
|
|
json_close_array
|
|
json_close_obj
|
|
}
|
|
|
|
# Create admin user
|
|
create_admin() {
|
|
read -r input
|
|
local username password email
|
|
username=$(echo "$input" | jsonfilter -e '@.username' 2>/dev/null)
|
|
password=$(echo "$input" | jsonfilter -e '@.password' 2>/dev/null)
|
|
email=$(echo "$input" | jsonfilter -e '@.email' 2>/dev/null)
|
|
|
|
if [ -z "$username" ] || [ -z "$password" ] || [ -z "$email" ]; then
|
|
json_error "Missing username, password, or email"
|
|
return
|
|
fi
|
|
|
|
if ! lxc_running; then
|
|
json_error "Service must be running to create users"
|
|
return
|
|
fi
|
|
|
|
lxc-attach -n "$LXC_NAME" -- su-exec git /usr/local/bin/gitea admin user create \
|
|
--username "$username" \
|
|
--password "$password" \
|
|
--email "$email" \
|
|
--admin \
|
|
--config /data/custom/conf/app.ini >/dev/null 2>&1
|
|
|
|
if [ $? -eq 0 ]; then
|
|
json_success "Admin user created: $username"
|
|
else
|
|
json_error "Failed to create admin user"
|
|
fi
|
|
}
|
|
|
|
# Create regular user
|
|
create_user() {
|
|
read -r input
|
|
local username password email
|
|
username=$(echo "$input" | jsonfilter -e '@.username' 2>/dev/null)
|
|
password=$(echo "$input" | jsonfilter -e '@.password' 2>/dev/null)
|
|
email=$(echo "$input" | jsonfilter -e '@.email' 2>/dev/null)
|
|
|
|
if [ -z "$username" ] || [ -z "$password" ] || [ -z "$email" ]; then
|
|
json_error "Missing username, password, or email"
|
|
return
|
|
fi
|
|
|
|
if ! lxc_running; then
|
|
json_error "Service must be running to create users"
|
|
return
|
|
fi
|
|
|
|
lxc-attach -n "$LXC_NAME" -- su-exec git /usr/local/bin/gitea admin user create \
|
|
--username "$username" \
|
|
--password "$password" \
|
|
--email "$email" \
|
|
--config /data/custom/conf/app.ini >/dev/null 2>&1
|
|
|
|
if [ $? -eq 0 ]; then
|
|
json_success "User created: $username"
|
|
else
|
|
json_error "Failed to create user (may already exist)"
|
|
fi
|
|
}
|
|
|
|
# Generate access token for user
|
|
generate_token() {
|
|
read -r input
|
|
local username token_name scopes
|
|
username=$(echo "$input" | jsonfilter -e '@.username' 2>/dev/null)
|
|
token_name=$(echo "$input" | jsonfilter -e '@.token_name' 2>/dev/null || echo "secubox-p2p")
|
|
scopes=$(echo "$input" | jsonfilter -e '@.scopes' 2>/dev/null || echo "write:repository,write:user,read:user")
|
|
|
|
if [ -z "$username" ]; then
|
|
json_error "Username required"
|
|
return
|
|
fi
|
|
|
|
if ! lxc_running; then
|
|
json_error "Service must be running to generate tokens"
|
|
return
|
|
fi
|
|
|
|
# Generate token via gitea CLI
|
|
local result
|
|
result=$(lxc-attach -n "$LXC_NAME" -- su-exec git /usr/local/bin/gitea admin user generate-access-token \
|
|
--username "$username" \
|
|
--token-name "$token_name" \
|
|
--scopes "$scopes" \
|
|
--config /data/custom/conf/app.ini 2>&1)
|
|
|
|
if echo "$result" | grep -q "Access token was successfully created"; then
|
|
local token=$(echo "$result" | grep -o '[a-f0-9]\{40\}')
|
|
json_init_obj
|
|
json_add_boolean "success" 1
|
|
json_add_string "token" "$token"
|
|
json_add_string "token_name" "$token_name"
|
|
json_add_string "username" "$username"
|
|
json_close_obj
|
|
else
|
|
json_error "Failed to generate token: $result"
|
|
fi
|
|
}
|
|
|
|
# Create repository for user
|
|
create_repo() {
|
|
read -r input
|
|
local owner repo_name description is_private
|
|
owner=$(echo "$input" | jsonfilter -e '@.owner' 2>/dev/null)
|
|
repo_name=$(echo "$input" | jsonfilter -e '@.name' 2>/dev/null)
|
|
description=$(echo "$input" | jsonfilter -e '@.description' 2>/dev/null || echo "")
|
|
is_private=$(echo "$input" | jsonfilter -e '@.private' 2>/dev/null || echo "true")
|
|
|
|
if [ -z "$owner" ] || [ -z "$repo_name" ]; then
|
|
json_error "Owner and repository name required"
|
|
return
|
|
fi
|
|
|
|
if ! lxc_running; then
|
|
json_error "Service must be running to create repositories"
|
|
return
|
|
fi
|
|
|
|
# Get HTTP port from config
|
|
local http_port
|
|
config_load "$CONFIG"
|
|
config_get http_port main http_port "3000"
|
|
|
|
# Use internal API with admin token from config
|
|
local admin_token
|
|
config_get admin_token main api_token ""
|
|
|
|
if [ -z "$admin_token" ]; then
|
|
json_error "Admin API token not configured"
|
|
return
|
|
fi
|
|
|
|
# Create repo via API
|
|
local response
|
|
response=$(curl -s -X POST "http://localhost:${http_port}/api/v1/admin/users/${owner}/repos" \
|
|
-H "Authorization: token $admin_token" \
|
|
-H "Content-Type: application/json" \
|
|
-d "{\"name\":\"$repo_name\",\"description\":\"$description\",\"private\":$is_private,\"auto_init\":true}" \
|
|
2>/dev/null)
|
|
|
|
if echo "$response" | jsonfilter -e '@.id' >/dev/null 2>&1; then
|
|
local clone_url=$(echo "$response" | jsonfilter -e '@.clone_url' 2>/dev/null)
|
|
local html_url=$(echo "$response" | jsonfilter -e '@.html_url' 2>/dev/null)
|
|
json_init_obj
|
|
json_add_boolean "success" 1
|
|
json_add_string "repo_name" "$repo_name"
|
|
json_add_string "owner" "$owner"
|
|
json_add_string "clone_url" "$clone_url"
|
|
json_add_string "html_url" "$html_url"
|
|
json_close_obj
|
|
else
|
|
local err_msg=$(echo "$response" | jsonfilter -e '@.message' 2>/dev/null || echo "Unknown error")
|
|
json_error "Failed to create repository: $err_msg"
|
|
fi
|
|
}
|
|
|
|
# Get git repo status (for local development tracking)
|
|
get_repo_status() {
|
|
read -r input
|
|
local repo_path
|
|
repo_path=$(echo "$input" | jsonfilter -e '@.path' 2>/dev/null)
|
|
|
|
# Default to secubox-openwrt if no path specified
|
|
[ -z "$repo_path" ] && repo_path="/root/secubox-openwrt"
|
|
|
|
if [ ! -d "$repo_path/.git" ]; then
|
|
json_error "Not a git repository: $repo_path"
|
|
return
|
|
fi
|
|
|
|
cd "$repo_path" || { json_error "Cannot access $repo_path"; return; }
|
|
|
|
local branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown")
|
|
local remote_branch=$(git rev-parse --abbrev-ref --symbolic-full-name @{u} 2>/dev/null || echo "")
|
|
local commit_hash=$(git rev-parse --short HEAD 2>/dev/null || echo "")
|
|
local commit_msg=$(git log -1 --pretty=%s 2>/dev/null || echo "")
|
|
local commit_date=$(git log -1 --pretty=%ci 2>/dev/null || echo "")
|
|
|
|
# Commits ahead/behind
|
|
local ahead=0 behind=0
|
|
if [ -n "$remote_branch" ]; then
|
|
ahead=$(git rev-list --count HEAD ^${remote_branch} 2>/dev/null || echo "0")
|
|
behind=$(git rev-list --count ${remote_branch} ^HEAD 2>/dev/null || echo "0")
|
|
fi
|
|
|
|
# Diff stats
|
|
local staged=$(git diff --cached --numstat 2>/dev/null | wc -l)
|
|
local modified=$(git diff --numstat 2>/dev/null | wc -l)
|
|
local untracked=$(git ls-files --others --exclude-standard 2>/dev/null | wc -l)
|
|
|
|
# Lines changed
|
|
local lines_added=$(git diff --numstat 2>/dev/null | awk '{sum+=$1} END {print sum+0}')
|
|
local lines_deleted=$(git diff --numstat 2>/dev/null | awk '{sum+=$2} END {print sum+0}')
|
|
|
|
json_init
|
|
json_add_boolean "success" 1
|
|
json_add_string "repo_path" "$repo_path"
|
|
json_add_string "branch" "$branch"
|
|
json_add_string "remote_branch" "$remote_branch"
|
|
json_add_string "commit_hash" "$commit_hash"
|
|
json_add_string "commit_msg" "$commit_msg"
|
|
json_add_string "commit_date" "$commit_date"
|
|
json_add_int "ahead" "${ahead:-0}"
|
|
json_add_int "behind" "${behind:-0}"
|
|
json_add_int "staged" "${staged:-0}"
|
|
json_add_int "modified" "${modified:-0}"
|
|
json_add_int "untracked" "${untracked:-0}"
|
|
json_add_int "lines_added" "${lines_added:-0}"
|
|
json_add_int "lines_deleted" "${lines_deleted:-0}"
|
|
json_dump
|
|
}
|
|
|
|
# Get recent commits for evolution graph
|
|
get_commit_history() {
|
|
read -r input
|
|
local repo_path limit
|
|
repo_path=$(echo "$input" | jsonfilter -e '@.path' 2>/dev/null)
|
|
limit=$(echo "$input" | jsonfilter -e '@.limit' 2>/dev/null)
|
|
|
|
[ -z "$repo_path" ] && repo_path="/root/secubox-openwrt"
|
|
[ -z "$limit" ] && limit=20
|
|
|
|
if [ ! -d "$repo_path/.git" ]; then
|
|
json_error "Not a git repository: $repo_path"
|
|
return
|
|
fi
|
|
|
|
cd "$repo_path" || { json_error "Cannot access $repo_path"; return; }
|
|
|
|
json_init
|
|
json_add_boolean "success" 1
|
|
json_add_array "commits"
|
|
|
|
git log --pretty=format:'%H|%h|%s|%an|%ae|%ci|%cr' -n "$limit" 2>/dev/null | while IFS='|' read -r hash short_hash msg author email date relative; do
|
|
# Get stats for this commit
|
|
local stats=$(git show --stat --format='' "$hash" 2>/dev/null | tail -1)
|
|
local files_changed=$(echo "$stats" | grep -oP '\d+(?= files? changed)' || echo "0")
|
|
local insertions=$(echo "$stats" | grep -oP '\d+(?= insertions?)' || echo "0")
|
|
local deletions=$(echo "$stats" | grep -oP '\d+(?= deletions?)' || echo "0")
|
|
|
|
json_add_object ""
|
|
json_add_string "hash" "$hash"
|
|
json_add_string "short_hash" "$short_hash"
|
|
json_add_string "message" "$msg"
|
|
json_add_string "author" "$author"
|
|
json_add_string "date" "$date"
|
|
json_add_string "relative" "$relative"
|
|
json_add_int "files_changed" "${files_changed:-0}"
|
|
json_add_int "insertions" "${insertions:-0}"
|
|
json_add_int "deletions" "${deletions:-0}"
|
|
json_close_object
|
|
done
|
|
|
|
json_close_array
|
|
json_dump
|
|
}
|
|
|
|
# Get daily commit stats for graph
|
|
get_commit_stats() {
|
|
read -r input
|
|
local repo_path days
|
|
repo_path=$(echo "$input" | jsonfilter -e '@.path' 2>/dev/null)
|
|
days=$(echo "$input" | jsonfilter -e '@.days' 2>/dev/null)
|
|
|
|
[ -z "$repo_path" ] && repo_path="/root/secubox-openwrt"
|
|
[ -z "$days" ] && days=30
|
|
|
|
if [ ! -d "$repo_path/.git" ]; then
|
|
json_error "Not a git repository: $repo_path"
|
|
return
|
|
fi
|
|
|
|
cd "$repo_path" || { json_error "Cannot access $repo_path"; return; }
|
|
|
|
json_init
|
|
json_add_boolean "success" 1
|
|
json_add_array "daily_stats"
|
|
|
|
# Get commits per day for last N days
|
|
for i in $(seq 0 $((days - 1))); do
|
|
local date_str=$(date -d "-${i} days" +%Y-%m-%d 2>/dev/null || date -v-${i}d +%Y-%m-%d 2>/dev/null)
|
|
[ -z "$date_str" ] && continue
|
|
|
|
local count=$(git log --after="${date_str} 00:00" --before="${date_str} 23:59" --oneline 2>/dev/null | wc -l)
|
|
|
|
json_add_object ""
|
|
json_add_string "date" "$date_str"
|
|
json_add_int "commits" "${count:-0}"
|
|
json_close_object
|
|
done
|
|
|
|
json_close_array
|
|
|
|
# Total stats
|
|
local total_commits=$(git rev-list --count HEAD 2>/dev/null || echo "0")
|
|
local total_authors=$(git log --format='%ae' | sort -u | wc -l)
|
|
|
|
json_add_int "total_commits" "$total_commits"
|
|
json_add_int "total_authors" "$total_authors"
|
|
json_dump
|
|
}
|
|
|
|
# Create backup
|
|
create_backup() {
|
|
local result
|
|
result=$(/usr/sbin/giteactl backup 2>&1)
|
|
|
|
if echo "$result" | grep -q "Backup created"; then
|
|
local backup_file=$(echo "$result" | grep -o '/srv/gitea/backups/[^ ]*')
|
|
json_init_obj
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "Backup created"
|
|
json_add_string "file" "$backup_file"
|
|
json_close_obj
|
|
else
|
|
json_error "Backup failed"
|
|
fi
|
|
}
|
|
|
|
# List backups
|
|
list_backups() {
|
|
local data_path
|
|
config_load "$CONFIG"
|
|
config_get data_path main data_path "/srv/gitea"
|
|
|
|
json_init_obj
|
|
json_add_array "backups"
|
|
|
|
local backup_dir="$data_path/backups"
|
|
if [ -d "$backup_dir" ]; then
|
|
for backup in "$backup_dir"/*.tar.gz; do
|
|
[ -f "$backup" ] || continue
|
|
local name=$(basename "$backup")
|
|
local size=$(ls -lh "$backup" 2>/dev/null | awk '{print $5}')
|
|
local mtime=$(stat -c %Y "$backup" 2>/dev/null || echo "0")
|
|
|
|
json_add_object ""
|
|
json_add_string "name" "$name"
|
|
json_add_string "path" "$backup"
|
|
json_add_string "size" "$size"
|
|
json_add_int "mtime" "$mtime"
|
|
json_close_object
|
|
done
|
|
fi
|
|
|
|
json_close_array
|
|
json_close_obj
|
|
}
|
|
|
|
# Restore backup
|
|
restore_backup() {
|
|
read -r input
|
|
local file
|
|
file=$(echo "$input" | jsonfilter -e '@.file' 2>/dev/null)
|
|
|
|
if [ -z "$file" ] || [ ! -f "$file" ]; then
|
|
json_error "Missing or invalid backup file"
|
|
return
|
|
fi
|
|
|
|
/usr/sbin/giteactl restore "$file" >/dev/null 2>&1
|
|
|
|
if [ $? -eq 0 ]; then
|
|
json_success "Restore completed"
|
|
else
|
|
json_error "Restore failed"
|
|
fi
|
|
}
|
|
|
|
# Check install progress
|
|
get_install_progress() {
|
|
local log_file="/var/log/gitea-install.log"
|
|
local status="unknown"
|
|
local progress=0
|
|
local message=""
|
|
|
|
if [ -f "$log_file" ]; then
|
|
# Check for completion markers
|
|
if grep -q "Installation complete" "$log_file" 2>/dev/null; then
|
|
status="completed"
|
|
progress=100
|
|
message="Installation completed successfully"
|
|
elif grep -q "ERROR" "$log_file" 2>/dev/null; then
|
|
status="error"
|
|
message=$(grep "ERROR" "$log_file" | tail -1)
|
|
else
|
|
status="running"
|
|
# Estimate progress based on log content
|
|
if grep -q "LXC config created" "$log_file" 2>/dev/null; then
|
|
progress=90
|
|
message="Finalizing setup..."
|
|
elif grep -q "Gitea binary installed" "$log_file" 2>/dev/null; then
|
|
progress=70
|
|
message="Configuring container..."
|
|
elif grep -q "Downloading Gitea" "$log_file" 2>/dev/null; then
|
|
progress=50
|
|
message="Downloading Gitea binary..."
|
|
elif grep -q "Rootfs created" "$log_file" 2>/dev/null; then
|
|
progress=40
|
|
message="Setting up container..."
|
|
elif grep -q "Extracting rootfs" "$log_file" 2>/dev/null; then
|
|
progress=30
|
|
message="Extracting container rootfs..."
|
|
elif grep -q "Downloading Alpine" "$log_file" 2>/dev/null; then
|
|
progress=20
|
|
message="Downloading Alpine rootfs..."
|
|
elif grep -q "Installing Gitea" "$log_file" 2>/dev/null; then
|
|
progress=10
|
|
message="Starting installation..."
|
|
else
|
|
progress=5
|
|
message="Initializing..."
|
|
fi
|
|
fi
|
|
else
|
|
status="not_started"
|
|
message="Installation has not been started"
|
|
fi
|
|
|
|
# Check if process is still running
|
|
if pgrep -f "giteactl install" >/dev/null 2>&1; then
|
|
status="running"
|
|
fi
|
|
|
|
json_init_obj
|
|
json_add_string "status" "$status"
|
|
json_add_int "progress" "$progress"
|
|
json_add_string "message" "$message"
|
|
json_close_obj
|
|
}
|
|
|
|
# Main RPC handler
|
|
case "$1" in
|
|
list)
|
|
cat <<-EOF
|
|
{
|
|
"get_status": {},
|
|
"get_stats": {},
|
|
"get_config": {},
|
|
"save_config": {"http_port": 3000, "ssh_port": 2222, "http_host": "str", "data_path": "str", "memory_limit": "str", "enabled": "str", "app_name": "str", "domain": "str", "protocol": "str", "disable_registration": "str", "require_signin": "str", "landing_page": "str"},
|
|
"start": {},
|
|
"stop": {},
|
|
"restart": {},
|
|
"install": {},
|
|
"uninstall": {},
|
|
"update": {},
|
|
"get_logs": {"lines": 100},
|
|
"list_repos": {},
|
|
"get_repo": {"name": "str", "owner": "str"},
|
|
"list_users": {},
|
|
"create_admin": {"username": "str", "password": "str", "email": "str"},
|
|
"create_user": {"username": "str", "password": "str", "email": "str"},
|
|
"generate_token": {"username": "str", "token_name": "str", "scopes": "str"},
|
|
"create_repo": {"owner": "str", "name": "str", "description": "str", "private": true},
|
|
"create_backup": {},
|
|
"list_backups": {},
|
|
"restore_backup": {"file": "str"},
|
|
"get_install_progress": {},
|
|
"get_repo_status": {"path": "str"},
|
|
"get_commit_history": {"path": "str", "limit": 20},
|
|
"get_commit_stats": {"path": "str", "days": 30}
|
|
}
|
|
EOF
|
|
;;
|
|
call)
|
|
case "$2" in
|
|
get_status)
|
|
get_status
|
|
;;
|
|
get_stats)
|
|
get_stats
|
|
;;
|
|
get_config)
|
|
get_config
|
|
;;
|
|
save_config)
|
|
save_config
|
|
;;
|
|
start)
|
|
start_service
|
|
;;
|
|
stop)
|
|
stop_service
|
|
;;
|
|
restart)
|
|
restart_service
|
|
;;
|
|
install)
|
|
install
|
|
;;
|
|
uninstall)
|
|
uninstall
|
|
;;
|
|
update)
|
|
update
|
|
;;
|
|
get_logs)
|
|
get_logs
|
|
;;
|
|
list_repos)
|
|
list_repos
|
|
;;
|
|
get_repo)
|
|
get_repo
|
|
;;
|
|
list_users)
|
|
list_users
|
|
;;
|
|
create_admin)
|
|
create_admin
|
|
;;
|
|
create_user)
|
|
create_user
|
|
;;
|
|
generate_token)
|
|
generate_token
|
|
;;
|
|
create_repo)
|
|
create_repo
|
|
;;
|
|
create_backup)
|
|
create_backup
|
|
;;
|
|
list_backups)
|
|
list_backups
|
|
;;
|
|
restore_backup)
|
|
restore_backup
|
|
;;
|
|
get_install_progress)
|
|
get_install_progress
|
|
;;
|
|
get_repo_status)
|
|
get_repo_status
|
|
;;
|
|
get_commit_history)
|
|
get_commit_history
|
|
;;
|
|
get_commit_stats)
|
|
get_commit_stats
|
|
;;
|
|
*)
|
|
json_error "Unknown method: $2"
|
|
;;
|
|
esac
|
|
;;
|
|
esac
|