Fix users.ts and schema for override

This commit is contained in:
LukeGus
2025-09-03 13:09:53 -05:00
parent 81b85c04a3
commit 190470022a
2 changed files with 74 additions and 34 deletions

View File

@@ -1,6 +1,6 @@
import express from 'express'; import express from 'express';
import {db} from '../db/index.js'; import {db} from '../db/index.js';
import {users, settings} from '../db/schema.js'; import {users, settings, sshData, fileManagerRecent, fileManagerPinned, fileManagerShortcuts, dismissedAlerts} from '../db/schema.js';
import {eq, and} from 'drizzle-orm'; import {eq, and} from 'drizzle-orm';
import chalk from 'chalk'; import chalk from 'chalk';
import bcrypt from 'bcryptjs'; import bcrypt from 'bcryptjs';
@@ -234,6 +234,7 @@ router.post('/oidc-config', authenticateJWT, async (req, res) => {
issuer_url, issuer_url,
authorization_url, authorization_url,
token_url, token_url,
userinfo_url,
identifier_path, identifier_path,
name_path, name_path,
scopes scopes
@@ -252,6 +253,7 @@ router.post('/oidc-config', authenticateJWT, async (req, res) => {
issuer_url, issuer_url,
authorization_url, authorization_url,
token_url, token_url,
userinfo_url: userinfo_url || '',
identifier_path, identifier_path,
name_path, name_path,
scopes: scopes || 'openid email profile' scopes: scopes || 'openid email profile'
@@ -374,14 +376,38 @@ router.get('/oidc/callback', async (req, res) => {
const tokenData = await tokenResponse.json() as any; const tokenData = await tokenResponse.json() as any;
let userInfo: any = null; let userInfo: any = null;
const userInfoUrls = []; let userInfoUrls: string[] = [];
const normalizedIssuerUrl = config.issuer_url.endsWith('/') ? config.issuer_url.slice(0, -1) : config.issuer_url; const normalizedIssuerUrl = config.issuer_url.endsWith('/') ? config.issuer_url.slice(0, -1) : config.issuer_url;
const baseUrl = normalizedIssuerUrl.replace(/\/application\/o\/[^\/]+$/, ''); const baseUrl = normalizedIssuerUrl.replace(/\/application\/o\/[^\/]+$/, '');
userInfoUrls.push(`${baseUrl}/userinfo/`); try {
userInfoUrls.push(`${normalizedIssuerUrl}/userinfo/`); const discoveryUrl = `${normalizedIssuerUrl}/.well-known/openid-configuration`;
userInfoUrls.push(`${normalizedIssuerUrl}/userinfo`); const discoveryResponse = await fetch(discoveryUrl);
if (discoveryResponse.ok) {
const discovery = await discoveryResponse.json() as any;
if (discovery.userinfo_endpoint) {
userInfoUrls.push(discovery.userinfo_endpoint);
}
}
} catch (discoveryError) {
logger.error(`OIDC discovery failed: ${discoveryError}`);
}
if (config.userinfo_url) {
userInfoUrls.unshift(config.userinfo_url);
}
userInfoUrls.push(
`${baseUrl}/userinfo/`,
`${baseUrl}/userinfo`,
`${normalizedIssuerUrl}/userinfo/`,
`${normalizedIssuerUrl}/userinfo`,
`${baseUrl}/oauth2/userinfo/`,
`${baseUrl}/oauth2/userinfo`,
`${normalizedIssuerUrl}/oauth2/userinfo/`,
`${normalizedIssuerUrl}/oauth2/userinfo`
);
if (tokenData.id_token) { if (tokenData.id_token) {
try { try {
@@ -414,8 +440,11 @@ router.get('/oidc/callback', async (req, res) => {
if (userInfoResponse.ok) { if (userInfoResponse.ok) {
userInfo = await userInfoResponse.json(); userInfo = await userInfoResponse.json();
break; break;
} else {
logger.error(`Userinfo endpoint ${userInfoUrl} failed with status: ${userInfoResponse.status}`);
} }
} catch (error) { } catch (error) {
logger.error(`Userinfo endpoint ${userInfoUrl} failed:`, error);
continue; continue;
} }
} }
@@ -423,6 +452,10 @@ router.get('/oidc/callback', async (req, res) => {
if (!userInfo) { if (!userInfo) {
logger.error('Failed to get user information from all sources'); logger.error('Failed to get user information from all sources');
logger.error(`Tried userinfo URLs: ${userInfoUrls.join(', ')}`);
logger.error(`Token data keys: ${Object.keys(tokenData).join(', ')}`);
logger.error(`Has id_token: ${!!tokenData.id_token}`);
logger.error(`Has access_token: ${!!tokenData.access_token}`);
return res.status(400).json({error: 'Failed to get user information'}); return res.status(400).json({error: 'Failed to get user information'});
} }
@@ -1278,12 +1311,19 @@ router.delete('/delete-user', authenticateJWT, async (req, res) => {
const targetUserId = targetUser[0].id; const targetUserId = targetUser[0].id;
try { try {
db.$client.prepare('DELETE FROM file_manager_recent WHERE user_id = ?').run(targetUserId); await db.delete(fileManagerRecent).where(eq(fileManagerRecent.userId, targetUserId));
db.$client.prepare('DELETE FROM file_manager_pinned WHERE user_id = ?').run(targetUserId); await db.delete(fileManagerPinned).where(eq(fileManagerPinned.userId, targetUserId));
db.$client.prepare('DELETE FROM file_manager_shortcuts WHERE user_id = ?').run(targetUserId); await db.delete(fileManagerShortcuts).where(eq(fileManagerShortcuts.userId, targetUserId));
db.$client.prepare('DELETE FROM ssh_data WHERE user_id = ?').run(targetUserId);
await db.delete(dismissedAlerts).where(eq(dismissedAlerts.userId, targetUserId));
await db.delete(sshData).where(eq(sshData.userId, targetUserId));
// Note: All user-related data has been deleted above
// The tables config_editor_* and shared_hosts don't exist in the current schema
} catch (cleanupError) { } catch (cleanupError) {
logger.error(`Cleanup failed for user ${username}:`, cleanupError); logger.error(`Cleanup failed for user ${username}:`, cleanupError);
throw cleanupError;
} }
await db.delete(users).where(eq(users.id, targetUserId)); await db.delete(users).where(eq(users.id, targetUserId));