Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .gitignore

This file was deleted.

139 changes: 0 additions & 139 deletions SEGURIDAD.md

This file was deleted.

13 changes: 3 additions & 10 deletions admin-auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,7 @@
* Generala con tools/generar-hash.html (o cualquier herramienta SHA-256)
* y pega el resultado entre comillas.
*
* EN PRODUCCIÓN CON SUPABASE:
* - La autenticación real se hace contra Supabase Auth
* - Este hash es SOLO como fallback/backup si falla la conexión a Supabase
* - Configura usuarios en el dashboard de Supabase > Authentication > Users
* - El sistema intentará primero login con Supabase, si falla usará este hash local
* En localhost sin valor configurado el admin se abre con aviso (solo desarrollo).
* En github.io u otros dominios públicos hace falta el hash obligatoriamente.
*/
window.ELECTROSTORE_ADMIN_PASSWORD_SHA256 = ''; // DEJAR VACÍO - Usando Supabase Auth

// Configuración de Supabase Auth para admin
// IMPORTANTE: Poné aquí el email EXACTO que creaste en Supabase > Authentication > Users
window.SUPABASE_ADMIN_EMAIL = 'skynet871012@gmail.com'; // ← Email configurado
window.ELECTROSTORE_ADMIN_PASSWORD_SHA256 = '';
116 changes: 6 additions & 110 deletions admin-login.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
/**
* Acceso al panel: autenticación con Supabase Auth + sesión en sessionStorage.
*
* SEGURIDAD:
* - La autenticación se realiza contra Supabase Auth (servidor)
* - El hash local es solo como fallback para desarrollo
* - Rate limiting real implementado en Supabase Edge Functions
* Acceso al panel: sesión en sessionStorage, límite de intentos, SHA-256.
*/
(function () {
const SESSION_KEY = 'electrostore_admin_exp';
const SUPABASE_SESSION_KEY = 'supabase_admin_session';
const SESSION_MS = 8 * 60 * 60 * 1000;
const ATT_KEY = 'electrostore_login_att_v1';

Expand All @@ -19,7 +13,7 @@

function configuredHash() {
const h = window.ELECTROSTORE_ADMIN_PASSWORD_SHA256;
return typeof h === 'string' && /^[a-f0-9]{64}$/i.test(h.trim()) && h !== 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855';
return typeof h === 'string' && /^[a-f0-9]{64}$/i.test(h.trim());
}

function getHashHex() {
Expand All @@ -39,74 +33,13 @@

function clearSession() {
sessionStorage.removeItem(SESSION_KEY);
sessionStorage.removeItem(SUPABASE_SESSION_KEY);
}

async function sha256Hex(text) {
const buf = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(text));
return [...new Uint8Array(buf)].map((b) => b.toString(16).padStart(2, '0')).join('');
}

/**
* Autenticación con Supabase Auth
*/
async function signInWithSupabase(email, password) {
try {
if (!window.sbClient) {
throw new Error('Supabase no disponible');
}

const { data, error } = await window.sbClient.auth.signInWithPassword({
email: email,
password: password
});

if (error) throw error;

// Guardar token de sesión
if (data.user && data.session) {
sessionStorage.setItem(SUPABASE_SESSION_KEY, JSON.stringify({
access_token: data.session.access_token,
refresh_token: data.session.refresh_token,
user_id: data.user.id,
email: data.user.email,
expires_at: data.session.expires_at
}));
return { success: true, user: data.user };
}

throw new Error('No se recibió sesión válida');
} catch (error) {
console.error('Error en Supabase Auth:', error);
throw error;
}
}

/**
* Verificar si hay sesión activa en Supabase
*/
async function checkSupabaseSession() {
try {
if (!window.sbClient) return null;

const { data: { session }, error } = await window.sbClient.auth.getSession();

if (error || !session) return null;

// Verificar que el email coincida con el de admin configurado
const adminEmail = window.SUPABASE_ADMIN_EMAIL;
if (adminEmail && session.user.email !== adminEmail) {
console.warn('Email de usuario no coincide con admin configurado');
return null;
}

return session;
} catch (error) {
console.error('Error verificando sesión Supabase:', error);
return null;
}
}

function getAttemptsState() {
try {
return JSON.parse(sessionStorage.getItem(ATT_KEY) || '{}') || {};
Expand Down Expand Up @@ -152,11 +85,7 @@
const btn = document.getElementById('admin-logout');
if (btn && !btn.dataset.bound) {
btn.dataset.bound = '1';
btn.addEventListener('click', async () => {
// Cerrar sesión en Supabase si existe
if (window.sbClient) {
await window.sbClient.auth.signOut();
}
btn.addEventListener('click', () => {
clearSession();
location.reload();
});
Expand All @@ -179,35 +108,23 @@
if (htmlMessage) msgEl.innerHTML = htmlMessage;
}

async function init() {
function init() {
attachLogout();

// Primero verificar sesión de Supabase
const supabaseSession = await checkSupabaseSession();
if (supabaseSession) {
setSession();
showMain(false);
console.log('✅ Sesión de Supabase restaurada');
return;
}

// Fallback: verificar sesión local
if (isSessionValid()) {
showMain(false);
return;
}

const hashHex = getHashHex();
const adminEmail = window.SUPABASE_ADMIN_EMAIL;

if (!hashHex && !adminEmail) {
if (!hashHex) {
if (isLocalDev()) {
showMain(true);
setSession();
return;
}
showGate(
'<strong>Falta configurar credenciales de Supabase.</strong><br><br>1. Editá <code>admin-auth.js</code> y poné tu email en <code>SUPABASE_ADMIN_EMAIL</code>.<br>2. Asegurate de haber creado ese usuario en Supabase Dashboard > Authentication > Users.<br>3. Volvé a desplegar en GitHub Pages.<br><br>El sistema usará Supabase Auth para validar tu acceso de forma segura.'
'<strong>Falta configurar la contraseña.</strong><br><br>Editá <code>admin-auth.js</code> en el repositorio: generá el SHA-256 de tu contraseña con <code>tools/generar-hash.html</code> y pegá el valor en <code>ELECTROSTORE_ADMIN_PASSWORD_SHA256</code>. Volvé a desplegar en GitHub Pages.'
);
if (form) form.classList.add('hidden');
return;
Expand All @@ -230,34 +147,13 @@
msgEl.textContent = 'Ingresá la contraseña.';
return;
}

// Intentar primero con Supabase Auth
if (adminEmail && adminEmail !== 'admin@megaofertas.local' && adminEmail !== 'tu-email@dominio.com' && window.sbClient) {
try {
msgEl.textContent = 'Autenticando...';
const result = await signInWithSupabase(adminEmail, pass);
if (result.success) {
resetAttempts();
passInput.value = '';
setSession();
showMain(false);
console.log('✅ Login exitoso con Supabase Auth');
return;
}
} catch (supabaseError) {
console.warn('Supabase Auth falló, usando fallback local:', supabaseError.message);
}
}

// Fallback: autenticación local con hash (solo desarrollo o sin Supabase)
try {
const got = (await sha256Hex(pass)).toLowerCase();
if (got === hashHex) {
resetAttempts();
passInput.value = '';
setSession();
showMain(false);
console.log('✅ Login exitoso con hash local (modo fallback)');
} else {
recordFailedAttempt();
msgEl.textContent = 'Contraseña incorrecta.';
Expand Down
11 changes: 0 additions & 11 deletions admin.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,11 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<meta name="robots" content="noindex, nofollow">

<!-- Security Headers -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src https://fonts.gstatic.com; connect-src 'self' https://hkgdbealspivhkmvtqcv.supabase.co;">
<meta http-equiv="X-Content-Type-Options" content="nosniff">
<meta http-equiv="X-Frame-Options" content="DENY">
<meta http-equiv="X-XSS-Protection" content="1; mode=block">

<title>MegaOfertas — Administración</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,400;0,9..40,500;0,9..40,600;0,9..40,700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="styles.css">

<!-- Supabase JS Client -->
<script src="https://cdn.jsdelivr.net/npm/@supabase/supabase-js@2"></script>
</head>
<body class="admin-body">

Expand Down Expand Up @@ -131,7 +121,6 @@ <h2>Productos</h2>
</div>

<script src="site-config.js"></script>
<script src="supabase-config.js"></script>
<script src="admin-auth.js"></script>
<script src="store.js"></script>
<script src="admin-login.js"></script>
Expand Down
Loading