feat(gk2hub): Add authentication support for protected MetaBlogizer sites

- Add lock badge CSS for protected site cards
- Add login banner for unauthenticated users
- Detect auth_required flag from metablogizer UCI config
- Hide protected cards until sessionStorage token present
- Filter respects authentication state in search and category views

Works with secubox-core portal-auth system.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
CyberMind-FR 2026-02-23 09:40:53 +01:00
parent 5bf6d0d84c
commit c2de15f861

View File

@ -125,6 +125,13 @@ body{background:var(--bg);color:var(--text);font-family:'Segoe UI',system-ui,san
.card-cat.meta{background:linear-gradient(135deg,var(--accent),var(--accent2))}
.card-cat.streamlit{background:linear-gradient(135deg,var(--accent3),#059669)}
.card-cat.video{background:linear-gradient(135deg,var(--accent4),#ea580c)}
.lock-badge{position:absolute;top:8px;right:8px;background:rgba(0,0,0,0.7);padding:4px 8px;border-radius:4px;font-size:0.8rem}
.site-card[data-protected]{display:none}
.site-card[data-protected].unlocked{display:flex}
.login-banner{background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:12px 20px;margin-bottom:20px;display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:10px}
.login-banner.hidden{display:none}
.login-banner a{color:var(--accent);text-decoration:none;padding:6px 16px;border:1px solid var(--accent);border-radius:6px}
.login-banner a:hover{background:var(--accent);color:#000}
.footer{margin-top:40px;padding:20px 0;border-top:1px solid var(--border);text-align:center;color:var(--muted);font-size:0.8rem}
.footer a{color:var(--accent);text-decoration:none}
@media(max-width:768px){.header{flex-direction:column;align-items:flex-start}.view-list .site-card{flex-direction:column}.view-list .card-preview{width:100%}}
@ -153,6 +160,10 @@ cat >> "$TEMP" << EOF
<button class="view-btn" id="toggleCloud">☁ Tags</button>
</div>
</div>
<div class="login-banner" id="loginBanner">
<span>🔒 Certains contenus nécessitent une authentification</span>
<a href="/login.html">Se connecter</a>
</div>
EOF
# Collect all sites
@ -168,12 +179,16 @@ uci show metablogizer 2>/dev/null | grep "=site$" | sed "s/metablogizer\.\(.*\)=
name=$(uci -q get "metablogizer.$site.name")
domain=$(uci -q get "metablogizer.$site.domain")
enabled=$(uci -q get "metablogizer.$site.enabled")
auth_required=$(uci -q get "metablogizer.$site.auth_required")
[ "$enabled" != "1" ] && continue
[ -z "$domain" ] && continue
cat=$(categorize_site "$name")
emoji=$(get_emoji "$cat")
echo "$cat" >> "$CAT_FILE"
printf '%s\t%s\t%s\t%s\tmeta\t\t\n' "$domain" "$name" "$cat" "$emoji" >> "$SITES_FILE"
# 7th field: protected (1 if auth_required)
protected=""
[ "$auth_required" = "1" ] && protected="protected"
printf '%s\t%s\t%s\t%s\tmeta\t\t%s\n' "$domain" "$name" "$cat" "$emoji" "$protected" >> "$SITES_FILE"
done
# Streamlit instances
@ -290,9 +305,23 @@ echo '</div>' >> "$TEMP"
# Sites grid
echo '<div class="view-grid" id="viewContainer"><div class="sites-grid" id="sitesGrid">' >> "$TEMP"
while IFS=' ' read -r url name cat emoji type thumb duration; do
while IFS=' ' read -r url name cat emoji type thumb protected; do
[ -z "$url" ] && continue
# For videos, 'thumb' is thumbnail URL and 'protected' is duration
duration=""
if [ "$type" = "video" ]; then
duration="$protected"
protected=""
fi
protected_attr=""
protected_badge=""
if [ "$protected" = "protected" ]; then
protected_attr="data-protected=\"1\""
protected_badge="<span class=\"lock-badge\">🔒</span>"
fi
if [ "$type" = "streamlit" ]; then
card_class="site-card streamlit"
cat_class="card-cat streamlit"
@ -317,9 +346,10 @@ while IFS=' ' read -r url name cat emoji type thumb duration; do
fi
cat >> "$TEMP" << CARD
<a href="$link_url" class="$card_class" target="_blank" data-category="$cat" data-type="$type" data-search="$url $name $cat $type">
<a href="$link_url" class="$card_class" target="_blank" data-category="$cat" data-type="$type" data-search="$url $name $cat $type" $protected_attr>
<div class="card-preview">
$preview_html
$protected_badge
</div>
<div class="card-content">
<div class="card-title">$name</div>
@ -342,6 +372,20 @@ document.addEventListener('DOMContentLoaded',function(){
const cards=document.querySelectorAll('.site-card');
const search=document.getElementById('searchBox');
const cloud=document.getElementById('tagCloud');
const loginBanner=document.getElementById('loginBanner');
const protectedCards=document.querySelectorAll('.site-card[data-protected]');
// Check authentication
const isLoggedIn=sessionStorage.getItem('secubox_token')!==null;
if(isLoggedIn){
// Unlock protected cards
protectedCards.forEach(c=>c.classList.add('unlocked'));
loginBanner.classList.add('hidden');
}else if(protectedCards.length===0){
// No protected content, hide banner
loginBanner.classList.add('hidden');
}
document.querySelectorAll('.view-btn[data-view]').forEach(b=>b.onclick=function(){
document.querySelectorAll('.view-btn[data-view]').forEach(x=>x.classList.remove('active'));
@ -357,6 +401,7 @@ document.addEventListener('DOMContentLoaded',function(){
function filter(cat){
cards.forEach(c=>{
let show = cat==='all' || c.dataset.category===cat || c.dataset.type===cat;
if(c.dataset.protected && !isLoggedIn) show=false;
c.style.display = show ? '' : 'none';
});
}
@ -369,7 +414,11 @@ document.addEventListener('DOMContentLoaded',function(){
search.oninput=function(){
const q=this.value.toLowerCase();
cards.forEach(c=>c.style.display=c.dataset.search.toLowerCase().includes(q)?'':'none');
cards.forEach(c=>{
let show=c.dataset.search.toLowerCase().includes(q);
if(c.dataset.protected && !isLoggedIn) show=false;
c.style.display=show?'':'none';
});
};
});
</script>