6 Commits
6 changed files with 160 additions and 11 deletions
+4
View File
@@ -0,0 +1,4 @@
node_modules/
dist/
package-lock.json
pnpm-lock.yaml
+9
View File
@@ -0,0 +1,9 @@
{
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "none",
"printWidth": 120,
"arrowParens": "avoid",
"endOfLine": "auto"
}
+3 -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,8 @@ 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).
--- ---
+56 -1
View File
@@ -1,3 +1,58 @@
function registerClient({ registerHook, peertubeHelpers }) { function registerClient({ registerHook, peertubeHelpers }) {
// YakNet client script try {
fetch('/plugins/auth-yaknet/router/status')
.then(function (r) {
return r.json();
})
.then(function (status) {
if (!status || status.autoRedirectLogin === false) {
return; // Auto redirect is disabled by administrator
}
var isLoginUrl = window.location.pathname.includes('/login');
var isLocal = window.location.search.includes('local=true');
var isError = window.location.search.includes('externalAuthError');
// If user directly visits /login without local override or error, forward to YakNet SSO
if (isLoginUrl && !isLocal && !isError) {
window.location.replace('/plugins/auth-yaknet/router/auth');
return;
}
// Intercept clicks on login links/buttons
document.addEventListener(
'click',
function (e) {
var el = e.target;
if (el && el.closest) {
var isLoginBtn = el.closest(
'my-login-link, .login-button, a[href*="/login"]:not(#yaktube-show-admin-login), a[aria-label*="Giriş"], a[title*="Giriş"], a[title*="login"], a[aria-label*="login"]'
);
if (isLoginBtn && !window.location.search.includes('local=true')) {
e.preventDefault();
e.stopPropagation();
window.location.href = '/plugins/auth-yaknet/router/auth';
}
}
},
true
);
})
.catch(function () {});
// Alt+A shortcut for local admin login bypass
document.addEventListener('keydown', function (e) {
if (e.altKey && (e.key === 'a' || e.key === 'A')) {
if (!window.location.pathname.includes('/login')) {
window.location.href = '/login?local=true';
}
}
});
} catch (err) {
console.warn('[YakNet SSO] Client init error:', err);
}
}
if (typeof module !== 'undefined' && module.exports) {
module.exports = { registerClient: registerClient };
} }
+87 -7
View File
@@ -4,7 +4,7 @@ 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 postRequest(urlStr, data) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@@ -104,18 +104,93 @@ 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({
name: 'auto-redirect-login',
label: "Giriş Sayfasında Doğrudan YakNet SSO'ya Yönlendir",
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.',
private: false,
default: true
});
let autoRedirectLogin = true;
function syncConfigFiles(enable) {
const fs = require('fs');
const path = require('path');
// 1. Update local-production.json if present
const jsonCandidates = [
path.resolve(process.cwd(), 'config', 'local-production.json'),
path.resolve(__dirname, '..', '..', 'config', 'local-production.json'),
path.resolve(__dirname, '..', '..', '..', 'config', 'local-production.json'),
'c:/laragon/www/yaktube.yakhub.com.tr/config/local-production.json'
];
for (const jPath of jsonCandidates) {
if (fs.existsSync(jPath)) {
try {
const cfg = JSON.parse(fs.readFileSync(jPath, 'utf8'));
if (!cfg.menu) cfg.menu = {};
if (!cfg.menu.login) cfg.menu.login = {};
if (cfg.menu.login.redirect_on_single_external_auth !== enable) {
cfg.menu.login.redirect_on_single_external_auth = enable;
fs.writeFileSync(jPath, JSON.stringify(cfg, null, 2), 'utf8');
logger.info(`[YakNet SSO] Synced local-production.json redirect_on_single_external_auth = ${enable}`);
}
} catch (e) {
logger.warn('[YakNet SSO] Error updating local-production.json:', e.message);
}
break;
}
}
// 2. Update production.yaml if present
const yamlCandidates = [
path.resolve(process.cwd(), 'config', 'production.yaml'),
path.resolve(__dirname, '..', '..', 'config', 'production.yaml'),
path.resolve(__dirname, '..', '..', '..', 'config', 'production.yaml'),
'c:/laragon/www/yaktube.yakhub.com.tr/config/production.yaml'
];
for (const yPath of yamlCandidates) {
if (fs.existsSync(yPath)) {
try {
let yContent = fs.readFileSync(yPath, 'utf8');
const pattern = /(redirect_on_single_external_auth:\s*)(true|false)/;
if (pattern.test(yContent)) {
const updated = yContent.replace(pattern, `$1${enable}`);
if (updated !== yContent) {
fs.writeFileSync(yPath, updated, 'utf8');
logger.info(`[YakNet SSO] Synced production.yaml redirect_on_single_external_auth = ${enable}`);
}
}
} catch (e) {
logger.warn('[YakNet SSO] Error updating production.yaml:', e.message);
}
break;
}
}
}
async function loadSettings() { async function loadSettings() {
const cid = await settingsManager.getSetting('client-id'); const cid = await settingsManager.getSetting('client-id');
const csec = await settingsManager.getSetting('client-secret'); const csec = await settingsManager.getSetting('client-secret');
const burl = await settingsManager.getSetting('auth-base-url'); const burl = await settingsManager.getSetting('auth-base-url');
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 = burl.replace(/\/+$/, '');
if (autoRedir !== undefined && autoRedir !== null) {
autoRedirectLogin = autoRedir === true || autoRedir === 'true';
} else {
autoRedirectLogin = true;
}
syncConfigFiles(autoRedirectLogin);
} }
await loadSettings(); await loadSettings();
settingsManager.onSettingsChange(loadSettings); settingsManager.onSettingsChange(loadSettings);
@@ -135,6 +210,12 @@ async function register({ registerExternalAuth, registerSetting, settingsManager
const router = getRouter(); const router = getRouter();
router.get('/status', (req, res) => {
return res.json({
autoRedirectLogin: autoRedirectLogin !== false
});
});
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 = `${authBaseUrl}/oauth/authorize?client_id=${encodeURIComponent(clientId)}&redirect_uri=${encodeURIComponent(callbackUrl)}&response_type=code&scope=&state=${state}`;
@@ -211,10 +292,9 @@ async function register({ registerExternalAuth, registerSetting, settingsManager
if (peertubeHelpers && peertubeHelpers.database && peertubeHelpers.database.query) { if (peertubeHelpers && peertubeHelpers.database && peertubeHelpers.database.query) {
setTimeout(async () => { setTimeout(async () => {
try { try {
await peertubeHelpers.database.query( await peertubeHelpers.database.query('UPDATE "user" SET "emailVerified" = true WHERE email = $1', {
'UPDATE "user" SET "emailVerified" = true WHERE email = $1', bind: [email]
{ bind: [email] } });
);
} catch (e) { } catch (e) {
logger.warn('Failed to auto-verify email in DB for ' + email, e); logger.warn('Failed to auto-verify email in DB for ' + email, e);
} }
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "peertube-plugin-auth-yaknet", "name": "peertube-plugin-auth-yaknet",
"version": "1.0.5", "version": "1.0.9",
"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",