184 lines
6.9 KiB
HTML
184 lines
6.9 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<title>Facebook OAuth2 Callback</title>
|
|
<style>
|
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
body {
|
|
background: #18191a;
|
|
color: #e4e6eb;
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
height: 100vh;
|
|
text-align: center;
|
|
}
|
|
.card {
|
|
background: #242526;
|
|
border-radius: 12px;
|
|
padding: 36px 44px;
|
|
max-width: 440px;
|
|
width: 90%;
|
|
box-shadow: 0 8px 32px rgba(0,0,0,0.5);
|
|
}
|
|
.icon { font-size: 3.2rem; margin-bottom: 16px; }
|
|
h2 { font-size: 1.25rem; margin-bottom: 10px; font-weight: 600; }
|
|
p { font-size: 0.9rem; color: #aaa; line-height: 1.5; }
|
|
.error { color: #f44336; }
|
|
.success { color: #4caf50; }
|
|
.warn { color: #ff9800; }
|
|
.spinner {
|
|
width: 36px; height: 36px;
|
|
border: 3px solid rgba(45,136,255,0.2);
|
|
border-top-color: #2D88FF;
|
|
border-radius: 50%;
|
|
animation: spin 0.8s linear infinite;
|
|
margin: 0 auto 16px;
|
|
}
|
|
@keyframes spin { to { transform: rotate(360deg); } }
|
|
.debug {
|
|
margin-top: 16px;
|
|
background: #1a1a1a;
|
|
border-radius: 6px;
|
|
padding: 10px 14px;
|
|
font-size: 0.75rem;
|
|
color: #666;
|
|
text-align: left;
|
|
word-break: break-all;
|
|
white-space: pre-wrap;
|
|
display: none;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="card">
|
|
<div class="spinner" id="spinner"></div>
|
|
<div class="icon" id="icon" style="display:none"></div>
|
|
<h2 id="title">Procesando autorización…</h2>
|
|
<p id="msg">Por favor espera</p>
|
|
<div class="debug" id="debug"></div>
|
|
</div>
|
|
|
|
<script>
|
|
(function () {
|
|
'use strict';
|
|
|
|
var TARGET_ORIGIN = '*';
|
|
|
|
function show(icon, title, msg, cls) {
|
|
document.getElementById('spinner').style.display = 'none';
|
|
var iconEl = document.getElementById('icon');
|
|
iconEl.style.display = 'block';
|
|
iconEl.textContent = icon;
|
|
document.getElementById('title').textContent = title;
|
|
var msgEl = document.getElementById('msg');
|
|
msgEl.textContent = msg;
|
|
msgEl.className = cls || '';
|
|
}
|
|
|
|
function showDebug(text) {
|
|
var el = document.getElementById('debug');
|
|
el.style.display = 'block';
|
|
el.textContent = text;
|
|
}
|
|
|
|
function parseParams(str) {
|
|
var params = {};
|
|
if (!str) return params;
|
|
str.replace(/^[?#]/, '').split('&').forEach(function (part) {
|
|
var idx = part.indexOf('=');
|
|
if (idx > -1) {
|
|
params[decodeURIComponent(part.slice(0, idx))] =
|
|
decodeURIComponent(part.slice(idx + 1).replace(/\+/g, ' '));
|
|
}
|
|
});
|
|
return params;
|
|
}
|
|
|
|
var hashParams = parseParams(window.location.hash);
|
|
var queryParams = parseParams(window.location.search);
|
|
|
|
// ── ERROR de Facebook ─────────────────────────────────────────────────
|
|
var errorCode = hashParams.error || queryParams.error;
|
|
var errorDesc = hashParams.error_description || queryParams.error_description
|
|
|| hashParams.error_reason || queryParams.error_reason
|
|
|| 'Autorización cancelada o denegada';
|
|
|
|
if (errorCode) {
|
|
show('❌', 'Autorización fallida', errorCode + ': ' + errorDesc, 'error');
|
|
showDebug('error: ' + errorCode + '\ndescription: ' + errorDesc);
|
|
if (window.opener) {
|
|
window.opener.postMessage({ type: 'fb_oauth_result', error: errorCode + ': ' + errorDesc }, TARGET_ORIGIN);
|
|
}
|
|
setTimeout(function () { window.close(); }, 4000);
|
|
return;
|
|
}
|
|
|
|
// ── AUTH CODE (response_type=code) — flujo preferido con backend ──────
|
|
// El backend (server/index.js) intercambia: code → short-lived → long-lived (60 días)
|
|
var code = queryParams.code;
|
|
var state = queryParams.state || '';
|
|
|
|
if (code) {
|
|
show('🔄', 'Intercambiando código…',
|
|
'Obteniendo token de larga duración (60 días)…', 'success');
|
|
|
|
// redirect_uri debe coincidir EXACTAMENTE con la URL registrada en Facebook
|
|
// Usamos window.location.href sin query string para obtener la URL exacta
|
|
var thisUrl = window.location.origin + window.location.pathname;
|
|
|
|
// Enviar el code a la ventana principal; ella llamará al backend
|
|
if (window.opener) {
|
|
window.opener.postMessage(
|
|
{ type: 'fb_oauth_result', flow: 'code', code: code, state: state,
|
|
redirect_uri: thisUrl },
|
|
TARGET_ORIGIN
|
|
);
|
|
show('✅', '¡Código enviado!', 'Procesando token de larga duración…', 'success');
|
|
setTimeout(function () { window.close(); }, 2500);
|
|
} else {
|
|
show('⚠️', 'Ventana sin opener',
|
|
'Esta página debe abrirse como popup desde Restreamer.', 'warn');
|
|
showDebug('code recibido pero window.opener es null.\ncode: ' + code.slice(0, 20) + '…\nredirect_uri: ' + thisUrl);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// ── TOKEN IMPLÍCITO (response_type=token) — fallback 2h ──────────────
|
|
// Se usa cuando el App Secret no está configurado en el backend.
|
|
var accessToken = hashParams.access_token || queryParams.access_token;
|
|
var expiresIn = parseInt(hashParams.expires_in || queryParams.expires_in || '0', 10);
|
|
|
|
if (accessToken) {
|
|
show('✅', '¡Token recibido!', 'Enviando a Restreamer para upgrade…', 'success');
|
|
if (window.opener) {
|
|
window.opener.postMessage(
|
|
{ type: 'fb_oauth_result', flow: 'token',
|
|
access_token: accessToken, expires_in: expiresIn },
|
|
TARGET_ORIGIN
|
|
);
|
|
setTimeout(function () { window.close(); }, 1800);
|
|
} else {
|
|
show('⚠️', 'Ventana sin opener',
|
|
'Copia el token manualmente.', 'warn');
|
|
showDebug('access_token: ' + accessToken.slice(0, 30) + '…\nexpires_in: ' + expiresIn);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// ── Sin datos útiles ──────────────────────────────────────────────────
|
|
show('⚠️', 'Sin datos de autorización',
|
|
'No se recibió code ni token. Revisa la configuración de tu App de Facebook.', 'warn');
|
|
showDebug('hash: ' + window.location.hash + '\nsearch: ' + window.location.search);
|
|
if (window.opener) {
|
|
window.opener.postMessage({ type: 'fb_oauth_result', error: 'no_data_received' }, TARGET_ORIGIN);
|
|
}
|
|
setTimeout(function () { window.close(); }, 6000);
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html>
|