3 Commits
4 changed files with 53 additions and 23 deletions
+2 -2
View File
@@ -2,7 +2,7 @@
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![PeerTube Engine](https://img.shields.io/badge/PeerTube-%3E%3D5.0.0-orange.svg)](https://joinpeertube.org) [![PeerTube Engine](https://img.shields.io/badge/PeerTube-%3E%3D5.0.0-orange.svg)](https://joinpeertube.org)
[![YakNet](https://img.shields.io/badge/YakNet-Federated%20Identity-blue.svg)](https://auth.yakhub.com.tr) [![YakNet](https://img.shields.io/badge/YakNet-Federated%20Identity-blue.svg)](https://developer-console.yakhub.com.tr)
**English** | [Türkçe](#türkçe) **English** | [Türkçe](#türkçe)
@@ -43,7 +43,7 @@ In your PeerTube admin panel (**Administration > Plugins / Themes > Settings** f
- **Client ID:** Your registered YakNet OAuth2 Application Client ID. - **Client ID:** Your registered YakNet OAuth2 Application Client ID.
- **Client Secret:** Your YakNet OAuth2 Client Secret. - **Client Secret:** Your YakNet OAuth2 Client Secret.
- **Auth Base URL:** Default is `https://auth.yakhub.com.tr`. - **Auth Base URL:** Default is `https://developer-console.yakhub.com.tr`.
- **Auto-Redirect on Login:** Automatically bypass the standard login form and redirect users directly to YakNet SSO (also synchronizes `redirect_on_single_external_auth` in PeerTube configuration). - **Auto-Redirect on Login:** Automatically bypass the standard login form and redirect users directly to YakNet SSO (also synchronizes `redirect_on_single_external_auth` in PeerTube configuration).
--- ---
+3 -4
View File
@@ -1,4 +1,4 @@
function registerClient({ registerHook, peertubeHelpers }) { async function register({ registerHook, peertubeHelpers }) {
try { try {
fetch('/plugins/auth-yaknet/router/status') fetch('/plugins/auth-yaknet/router/status')
.then(function (r) { .then(function (r) {
@@ -53,6 +53,5 @@ function registerClient({ registerHook, peertubeHelpers }) {
} }
} }
if (typeof module !== 'undefined' && module.exports) { export { register, register as registerClient };
module.exports = { registerClient: registerClient }; export default register;
}
+47 -16
View File
@@ -4,11 +4,22 @@ const http = require('http');
let clientId = ''; let clientId = '';
let clientSecret = ''; let clientSecret = '';
let authBaseUrl = 'https://auth.yakhub.com.tr'; let authBaseUrl = 'https://developer-console.yakhub.com.tr';
function postRequest(urlStr, data) { function normalizeAuthUrl(urlStr) {
if (typeof urlStr === 'string' && urlStr.includes('auth.yakhub.com.tr')) {
return urlStr.replace('auth.yakhub.com.tr', 'developer-console.yakhub.com.tr');
}
return urlStr;
}
function postRequest(urlStr, data, maxRedirects = 5) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const url = new URL(urlStr); if (maxRedirects <= 0) {
return reject(new Error('Too many redirects while calling YakNet auth server'));
}
const safeUrlStr = normalizeAuthUrl(urlStr);
const url = new URL(safeUrlStr);
const postData = typeof data === 'string' ? data : new URLSearchParams(data).toString(); const postData = typeof data === 'string' ? data : new URLSearchParams(data).toString();
const lib = url.protocol === 'https:' ? https : http; const lib = url.protocol === 'https:' ? https : http;
@@ -26,6 +37,12 @@ function postRequest(urlStr, data) {
} }
}, },
res => { res => {
// Follow 301, 302, 307, 308 redirects automatically
if ([301, 302, 307, 308].includes(res.statusCode) && res.headers.location) {
const nextUrl = new URL(res.headers.location, safeUrlStr).toString();
return resolve(postRequest(nextUrl, data, maxRedirects - 1));
}
let body = ''; let body = '';
res.on('data', chunk => (body += chunk)); res.on('data', chunk => (body += chunk));
res.on('end', () => { res.on('end', () => {
@@ -44,9 +61,13 @@ function postRequest(urlStr, data) {
}); });
} }
function getRequest(urlStr, token) { function getRequest(urlStr, token, maxRedirects = 5) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const url = new URL(urlStr); if (maxRedirects <= 0) {
return reject(new Error('Too many redirects while calling YakNet auth server'));
}
const safeUrlStr = normalizeAuthUrl(urlStr);
const url = new URL(safeUrlStr);
const lib = url.protocol === 'https:' ? https : http; const lib = url.protocol === 'https:' ? https : http;
const req = lib.request( const req = lib.request(
@@ -62,6 +83,12 @@ function getRequest(urlStr, token) {
} }
}, },
res => { res => {
// Follow 301, 302, 307, 308 redirects automatically
if ([301, 302, 307, 308].includes(res.statusCode) && res.headers.location) {
const nextUrl = new URL(res.headers.location, safeUrlStr).toString();
return resolve(getRequest(nextUrl, token, maxRedirects - 1));
}
let body = ''; let body = '';
res.on('data', chunk => (body += chunk)); res.on('data', chunk => (body += chunk));
res.on('end', () => { res.on('end', () => {
@@ -104,16 +131,17 @@ async function register({ registerExternalAuth, registerSetting, settingsManager
name: 'auth-base-url', name: 'auth-base-url',
label: 'YakNet Auth URL', label: 'YakNet Auth URL',
type: 'input', type: 'input',
description: 'YakNet SSO Server URL (Default: https://auth.yakhub.com.tr)', description: 'YakNet SSO Server URL (Default: https://developer-console.yakhub.com.tr)',
private: false, private: false,
default: 'https://auth.yakhub.com.tr' default: 'https://developer-console.yakhub.com.tr'
}); });
registerSetting({ registerSetting({
name: 'auto-redirect-login', name: 'auto-redirect-login',
label: 'Giriş Sayfasında Doğrudan YakNet SSO\'ya Yönlendir', label: "Giriş Sayfasında Doğrudan YakNet SSO'ya Yönlendir",
type: 'input-checkbox', type: 'input-checkbox',
description: 'Aktif olduğunda, kullanıcılar giriş butonuna veya /login sayfasına gittiğinde standart PeerTube şifre formu yerine doğrudan YakNet SSO sunucusuna yönlendirilir.', description:
'Aktif olduğunda, kullanıcılar giriş butonuna veya /login sayfasına gittiğinde standart PeerTube şifre formu yerine doğrudan YakNet SSO sunucusuna yönlendirilir.',
private: false, private: false,
default: true default: true
}); });
@@ -183,7 +211,9 @@ async function register({ registerExternalAuth, registerSetting, settingsManager
const autoRedir = await settingsManager.getSetting('auto-redirect-login'); const autoRedir = await settingsManager.getSetting('auto-redirect-login');
if (cid) clientId = cid; if (cid) clientId = cid;
if (csec) clientSecret = csec; if (csec) clientSecret = csec;
if (burl) authBaseUrl = burl.replace(/\/+$/, ''); if (burl) {
authBaseUrl = normalizeAuthUrl(burl.replace(/\/+$/, ''));
}
if (autoRedir !== undefined && autoRedir !== null) { if (autoRedir !== undefined && autoRedir !== null) {
autoRedirectLogin = autoRedir === true || autoRedir === 'true'; autoRedirectLogin = autoRedir === true || autoRedir === 'true';
} else { } else {
@@ -202,7 +232,7 @@ async function register({ registerExternalAuth, registerSetting, settingsManager
authDisplayName: () => 'YakNet ile Giriş Yap', authDisplayName: () => 'YakNet ile Giriş Yap',
onAuthRequest: (req, res) => { onAuthRequest: (req, res) => {
const state = crypto.randomBytes(16).toString('hex'); const state = crypto.randomBytes(16).toString('hex');
const authUrl = `${authBaseUrl}/oauth/authorize?client_id=${encodeURIComponent(clientId)}&redirect_uri=${encodeURIComponent(callbackUrl)}&response_type=code&scope=&state=${state}`; const authUrl = `${normalizeAuthUrl(authBaseUrl)}/oauth/authorize?client_id=${encodeURIComponent(clientId)}&redirect_uri=${encodeURIComponent(callbackUrl)}&response_type=code&scope=&state=${state}`;
return res.redirect(authUrl); return res.redirect(authUrl);
} }
}); });
@@ -217,7 +247,7 @@ async function register({ registerExternalAuth, registerSetting, settingsManager
router.get('/auth', (req, res) => { router.get('/auth', (req, res) => {
const state = crypto.randomBytes(16).toString('hex'); const state = crypto.randomBytes(16).toString('hex');
const authUrl = `${authBaseUrl}/oauth/authorize?client_id=${encodeURIComponent(clientId)}&redirect_uri=${encodeURIComponent(callbackUrl)}&response_type=code&scope=&state=${state}`; const authUrl = `${normalizeAuthUrl(authBaseUrl)}/oauth/authorize?client_id=${encodeURIComponent(clientId)}&redirect_uri=${encodeURIComponent(callbackUrl)}&response_type=code&scope=&state=${state}`;
return res.redirect(authUrl); return res.redirect(authUrl);
}); });
@@ -235,7 +265,8 @@ async function register({ registerExternalAuth, registerSetting, settingsManager
} }
try { try {
const tokenRes = await postRequest(`${authBaseUrl}/oauth/token`, { const targetAuthUrl = normalizeAuthUrl(authBaseUrl);
const tokenRes = await postRequest(`${targetAuthUrl}/oauth/token`, {
grant_type: 'authorization_code', grant_type: 'authorization_code',
client_id: clientId, client_id: clientId,
client_secret: clientSecret, client_secret: clientSecret,
@@ -244,14 +275,14 @@ async function register({ registerExternalAuth, registerSetting, settingsManager
}); });
if (!tokenRes.data || !tokenRes.data.access_token) { if (!tokenRes.data || !tokenRes.data.access_token) {
logger.error('Failed to get access token from YakNet:', tokenRes); logger.error('Failed to get access token from YakNet: ' + JSON.stringify(tokenRes));
return res.redirect('/login?externalAuthError=true'); return res.redirect('/login?externalAuthError=true');
} }
const accessToken = tokenRes.data.access_token; const accessToken = tokenRes.data.access_token;
const userRes = await getRequest(`${authBaseUrl}/api/user`, accessToken); const userRes = await getRequest(`${targetAuthUrl}/api/user`, accessToken);
if (!userRes.data || !userRes.data.email) { if (!userRes.data || !userRes.data.email) {
logger.error('Failed to get user profile from YakNet:', userRes); logger.error('Failed to get user profile from YakNet: ' + JSON.stringify(userRes));
return res.redirect('/login?externalAuthError=true'); return res.redirect('/login?externalAuthError=true');
} }
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "peertube-plugin-auth-yaknet", "name": "peertube-plugin-auth-yaknet",
"version": "1.0.7", "version": "1.0.10",
"description": "YakNet SSO & OAuth2 Single Sign-On Authentication Plugin for PeerTube", "description": "YakNet SSO & OAuth2 Single Sign-On Authentication Plugin for PeerTube",
"main": "main.js", "main": "main.js",
"library": "./main.js", "library": "./main.js",