feat(secubox-users): Add Gitea integration with password sync

- Add Gitea as a service option in SecuBox Users UI
- Add Gitea checkbox in Add User modal
- Add Gitea service badge in status display
- Implement password sync to Gitea via API on password change
- Fix Gitea API call to include login_name parameter
- Add gitea to check_service() and get_status()
- Sync passwords to all enabled services (email, jabber, nextcloud, gitea)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
CyberMind-FR 2026-02-25 13:42:41 +01:00
parent 33426e90e5
commit 4fee9e4c12
3 changed files with 120 additions and 3 deletions

View File

@ -3639,3 +3639,33 @@ git checkout HEAD -- index.html
- Added route to mitmproxy-in for WAF inspection
- **Files Modified:**
- `luci-app-streamlit/root/usr/libexec/rpcd/luci.streamlit`: upload_app, upload_and_deploy with KISS ZIP handling
36. **ALERTE.DEPOT Whistleblower Platform (2026-02-25)**
- **Anonymous Whistleblower Application (Loi Waserman compliant):**
- Pseudonymized submissions - no personal data required
- Token-based tracking (16-char alphanumeric tokens)
- Three modes: Submit / Track / Admin
- SecuBox Users authentication for investigators
- Gitea backend (private repo: gandalf/alertes-depot)
- QR code generation for attestations
- **Tracking Portal:**
- Token lookup searches Gitea issues
- Status display with visual badges
- Two-way communication with investigators
- Add supplementary information capability
- **Admin Dashboard:**
- SecuBox Users RPCD authentication
- Case management with status workflow
- Internal notes vs public responses
- Statistics overview
- **Security & Compliance:**
- Audit trail blockchain (/srv/secubox/mesh/alertes-chain.json)
- Deadline monitoring cron (7-day ack, 3-month response)
- Immutable hash chain for all actions
- **Dual-Channel Access:**
- HTTPS: alerte.gk2.secubox.in (production SSL cert)
- Tor: i7j46m67zvdksfhddbq273yydpuo5xvewsl2fjl5zlycjyo4qelysnid.onion
- **Files:**
- `/srv/streamlit/apps/alerte_depot/app.py`: Full whistleblower platform
- `/srv/secubox/mesh/alertes-chain.json`: Audit blockchain
- `/usr/sbin/alerte-depot-cron`: Deadline monitor

View File

@ -116,7 +116,8 @@ return view.extend({
E('label', { 'style': 'margin-left:10px;' }, [E('input', { 'type': 'checkbox', 'id': 'svc-peertube', 'checked': true }), ' PeerTube']),
E('label', { 'style': 'margin-left:10px;' }, [E('input', { 'type': 'checkbox', 'id': 'svc-jabber', 'checked': true }), ' Jabber']),
E('label', { 'style': 'margin-left:10px;' }, [E('input', { 'type': 'checkbox', 'id': 'svc-matrix', 'checked': true }), ' Matrix']),
E('label', { 'style': 'margin-left:10px;' }, [E('input', { 'type': 'checkbox', 'id': 'svc-email', 'checked': true }), ' Email'])
E('label', { 'style': 'margin-left:10px;' }, [E('input', { 'type': 'checkbox', 'id': 'svc-email', 'checked': true }), ' Email']),
E('label', { 'style': 'margin-left:10px;' }, [E('input', { 'type': 'checkbox', 'id': 'svc-gitea', 'checked': true }), ' Gitea'])
])
])
]),
@ -136,6 +137,7 @@ return view.extend({
if (document.getElementById('svc-jabber').checked) services.push('jabber');
if (document.getElementById('svc-matrix').checked) services.push('matrix');
if (document.getElementById('svc-email').checked) services.push('email');
if (document.getElementById('svc-gitea').checked) services.push('gitea');
if (!username) {
ui.addNotification(null, E('p', {}, _('Username required')), 'error');
@ -263,7 +265,8 @@ return view.extend({
this.renderServiceBadge('PeerTube', services.peertube),
this.renderServiceBadge('Matrix', services.matrix),
this.renderServiceBadge('Jabber', services.jabber),
this.renderServiceBadge('Email', services.email)
this.renderServiceBadge('Email', services.email),
this.renderServiceBadge('Gitea', services.gitea)
]),
E('p', { 'style': 'color:#666;' }, _('Domain: %s | Users: %d').format(status.domain, status.user_count))
]));

View File

@ -16,6 +16,7 @@ check_service() {
matrix) [ -x /usr/sbin/matrixctl ] && lxc-info -n matrix 2>/dev/null | grep -q "RUNNING" && echo "1" || echo "0" ;;
jabber) [ -x /usr/sbin/jabberctl ] && lxc-info -n jabber 2>/dev/null | grep -q "RUNNING" && echo "1" || echo "0" ;;
email) [ -x /usr/sbin/mailserverctl ] && lxc-info -n mailserver 2>/dev/null | grep -q "RUNNING" && echo "1" || echo "0" ;;
gitea) [ -x /usr/sbin/giteactl ] && lxc-info -n gitea 2>/dev/null | grep -q "RUNNING" && echo "1" || echo "0" ;;
*) echo "0" ;;
esac
}
@ -30,6 +31,7 @@ get_status() {
local mx_running=$(check_service matrix)
local jb_running=$(check_service jabber)
local em_running=$(check_service email)
local gt_running=$(check_service gitea)
cat <<EOFJ
{
@ -41,7 +43,8 @@ get_status() {
"peertube": $pt_running,
"matrix": $mx_running,
"jabber": $jb_running,
"email": $em_running
"email": $em_running,
"gitea": $gt_running
}
}
EOFJ
@ -156,9 +159,71 @@ update_password() {
fi
if echo "$output" | grep -q "Password updated"; then
# Sync to all enabled services
local services=$(uci -q get ${CONFIG}.${username}.services 2>/dev/null | tr ' ' '\n' | sort -u)
local synced=""
local failed=""
for svc in $services; do
case "$svc" in
gitea)
local gitea_url=$(uci -q get gitea.main.url 2>/dev/null || echo "http://192.168.255.1:3001")
local gitea_token=$(uci -q get gitea.main.token 2>/dev/null)
if [ -n "$gitea_token" ]; then
local result=$(curl -s -X PATCH \
-H "Authorization: token $gitea_token" \
-H "Content-Type: application/json" \
-d "{\"login_name\":\"$username\",\"password\":\"$password\"}" \
"${gitea_url}/api/v1/admin/users/${username}" 2>/dev/null)
if echo "$result" | grep -q "\"username\""; then
synced="$synced gitea"
else
failed="$failed gitea"
fi
fi
;;
email)
if [ -x /usr/sbin/mailserverctl ]; then
local domain=$(uci -q get ${CONFIG}.main.domain || echo "secubox.in")
local email="${username}@${domain}"
. /usr/lib/mailserver/users.sh 2>/dev/null
if user_passwd "$email" "$password" >/dev/null 2>&1; then
synced="$synced email"
else
failed="$failed email"
fi
fi
;;
jabber)
if [ -x /usr/sbin/jabberctl ]; then
local domain=$(uci -q get ${CONFIG}.main.domain || echo "secubox.in")
if jabberctl user passwd "${username}@${domain}" "$password" >/dev/null 2>&1; then
synced="$synced jabber"
else
failed="$failed jabber"
fi
fi
;;
nextcloud)
if [ -x /usr/sbin/nextcloudctl ]; then
export OC_PASS="$password"
if nextcloudctl occ user:resetpassword "$username" --password-from-env >/dev/null 2>&1; then
synced="$synced nextcloud"
else
failed="$failed nextcloud"
fi
fi
;;
esac
done
logger -t secubox-users "Password updated for $username (synced:$synced failed:$failed)"
json_init
json_add_boolean "success" 1
json_add_string "password" "$password"
json_add_string "synced" "$synced"
json_add_string "failed" "$failed"
json_dump
else
json_init
@ -367,6 +432,25 @@ change_password() {
fi
fi
;;
gitea)
# Sync password to Gitea via API
local gitea_url=$(uci -q get gitea.main.url 2>/dev/null || echo "http://192.168.255.1:3001")
local gitea_token=$(uci -q get gitea.main.token 2>/dev/null)
if [ -n "$gitea_token" ]; then
local result=$(curl -s -X PATCH \
-H "Authorization: token $gitea_token" \
-H "Content-Type: application/json" \
-d "{\"login_name\":\"$username\",\"password\":\"$new_password\"}" \
"${gitea_url}/api/v1/admin/users/${username}" 2>/dev/null)
if echo "$result" | grep -q "\"username\""; then
synced="$synced gitea"
else
failed="$failed gitea"
fi
else
failed="$failed gitea(no-token)"
fi
;;
nextcloud)
if [ -x /usr/sbin/nextcloudctl ]; then
export OC_PASS="$new_password"