Fix registration issues and implement PostgreSQL database for persistent storage.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 705f2157-ef97-4fbd-89e4-8c7f2ecaea90
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/7ed01c5f-a82d-405a-b728-b2e3d127c60c/161c3a9f-0168-4125-bae3-1975632f0e7f.jpg
This commit is contained in:
alphaeusmote
2025-04-08 02:01:40 +00:00
2 changed files with 169 additions and 255 deletions
+3
View File
@@ -140,6 +140,7 @@ export default function AuthPage() {
email: "", email: "",
fullName: "", fullName: "",
acceptTerms: false, acceptTerms: false,
role: "user",
}, },
}); });
@@ -298,6 +299,7 @@ export default function AuthPage() {
<Input <Input
placeholder="Enter your full name" placeholder="Enter your full name"
{...field} {...field}
value={field.value || ""}
disabled={registerMutation.isPending} disabled={registerMutation.isPending}
/> />
</FormControl> </FormControl>
@@ -317,6 +319,7 @@ export default function AuthPage() {
type="email" type="email"
placeholder="Enter your email" placeholder="Enter your email"
{...field} {...field}
value={field.value || ""}
disabled={registerMutation.isPending} disabled={registerMutation.isPending}
/> />
</FormControl> </FormControl>
+165 -254
View File
@@ -3,15 +3,27 @@ import {
LdapConnection, InsertLdapConnection, LdapConnection, InsertLdapConnection,
AdUser, InsertAdUser, AdGroup, InsertAdGroup, AdUser, InsertAdUser, AdGroup, InsertAdGroup,
AdOrgUnit, InsertAdOrgUnit, AdComputer, InsertAdComputer, AdOrgUnit, InsertAdOrgUnit, AdComputer, InsertAdComputer,
AdDomain, InsertAdDomain AdDomain, InsertAdDomain,
users, apiTokens, ldapConnections, adUsers, adGroups, adOrgUnits, adComputers, adDomains
} from "@shared/schema"; } from "@shared/schema";
import session from "express-session"; import session from "express-session";
import createMemoryStore from "memorystore"; import createMemoryStore from "memorystore";
import crypto from "crypto"; import crypto from "crypto";
import { db } from "./db";
import { eq, and } from "drizzle-orm";
import connectPg from "connect-pg-simple";
import { Pool } from "@neondatabase/serverless";
// Memory store for sessions // Memory store for sessions
const MemoryStore = createMemoryStore(session); const MemoryStore = createMemoryStore(session);
// PostgreSQL session store
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
});
const PostgresStore = connectPg(session);
export interface IStorage { export interface IStorage {
// User management // User management
getUser(id: number): Promise<User | undefined>; getUser(id: number): Promise<User | undefined>;
@@ -71,417 +83,316 @@ export interface IStorage {
listAdDomains(connectionId: number, query?: any): Promise<AdDomain[]>; listAdDomains(connectionId: number, query?: any): Promise<AdDomain[]>;
// Session store // Session store
sessionStore: session.SessionStore; sessionStore: any;
} }
export class MemStorage implements IStorage { // Database Storage implementation
private users: Map<number, User>; export class DatabaseStorage implements IStorage {
private apiTokens: Map<number, ApiToken>; sessionStore: any;
private ldapConnections: Map<number, LdapConnection>;
private adUsers: Map<number, AdUser>;
private adGroups: Map<number, AdGroup>;
private adOrgUnits: Map<number, AdOrgUnit>;
private adComputers: Map<number, AdComputer>;
private adDomains: Map<number, AdDomain>;
sessionStore: session.SessionStore;
private userCurrentId: number;
private tokenCurrentId: number;
private connectionCurrentId: number;
private adUserCurrentId: number;
private adGroupCurrentId: number;
private adOrgUnitCurrentId: number;
private adComputerCurrentId: number;
private adDomainCurrentId: number;
constructor() { constructor() {
this.users = new Map(); this.sessionStore = new PostgresStore({
this.apiTokens = new Map(); pool,
this.ldapConnections = new Map(); createTableIfMissing: true
this.adUsers = new Map();
this.adGroups = new Map();
this.adOrgUnits = new Map();
this.adComputers = new Map();
this.adDomains = new Map();
this.userCurrentId = 1;
this.tokenCurrentId = 1;
this.connectionCurrentId = 1;
this.adUserCurrentId = 1;
this.adGroupCurrentId = 1;
this.adOrgUnitCurrentId = 1;
this.adComputerCurrentId = 1;
this.adDomainCurrentId = 1;
this.sessionStore = new MemoryStore({
checkPeriod: 86400000 // 24h
}); });
} }
// User management // User management
async getUser(id: number): Promise<User | undefined> { async getUser(id: number): Promise<User | undefined> {
return this.users.get(id); const result = await db.select().from(users).where(eq(users.id, id));
return result.length > 0 ? result[0] : undefined;
} }
async getUserByUsername(username: string): Promise<User | undefined> { async getUserByUsername(username: string): Promise<User | undefined> {
return Array.from(this.users.values()).find( const result = await db.select().from(users).where(eq(users.username, username));
(user) => user.username.toLowerCase() === username.toLowerCase(), return result.length > 0 ? result[0] : undefined;
);
} }
async createUser(insertUser: InsertUser): Promise<User> { async createUser(insertUser: InsertUser): Promise<User> {
const id = this.userCurrentId++; const result = await db.insert(users).values(insertUser).returning();
const now = new Date(); return result[0];
const user: User = {
...insertUser,
id,
createdAt: now,
role: insertUser.role || "user"
};
this.users.set(id, user);
return user;
} }
async updateUser(id: number, userData: Partial<User>): Promise<User | undefined> { async updateUser(id: number, userData: Partial<User>): Promise<User | undefined> {
const user = await this.getUser(id); const result = await db.update(users).set(userData).where(eq(users.id, id)).returning();
if (!user) return undefined; return result.length > 0 ? result[0] : undefined;
const updatedUser = { ...user, ...userData };
this.users.set(id, updatedUser);
return updatedUser;
} }
async deleteUser(id: number): Promise<boolean> { async deleteUser(id: number): Promise<boolean> {
return this.users.delete(id); const result = await db.delete(users).where(eq(users.id, id)).returning({ id: users.id });
return result.length > 0;
} }
async listUsers(): Promise<User[]> { async listUsers(): Promise<User[]> {
return Array.from(this.users.values()); return db.select().from(users);
} }
// API Token management // API Token management
async getApiToken(id: number): Promise<ApiToken | undefined> { async getApiToken(id: number): Promise<ApiToken | undefined> {
return this.apiTokens.get(id); const result = await db.select().from(apiTokens).where(eq(apiTokens.id, id));
return result.length > 0 ? result[0] : undefined;
} }
async getApiTokenByToken(token: string): Promise<ApiToken | undefined> { async getApiTokenByToken(token: string): Promise<ApiToken | undefined> {
return Array.from(this.apiTokens.values()).find( const result = await db.select().from(apiTokens).where(eq(apiTokens.token, token));
(apiToken) => apiToken.token === token, return result.length > 0 ? result[0] : undefined;
);
} }
async createApiToken(insertToken: InsertApiToken): Promise<ApiToken> { async createApiToken(insertToken: InsertApiToken): Promise<ApiToken> {
const id = this.tokenCurrentId++; const result = await db.insert(apiTokens).values(insertToken).returning();
const now = new Date(); return result[0];
const token: ApiToken = { ...insertToken, id, createdAt: now };
this.apiTokens.set(id, token);
return token;
} }
async deleteApiToken(id: number): Promise<boolean> { async deleteApiToken(id: number): Promise<boolean> {
return this.apiTokens.delete(id); const result = await db.delete(apiTokens).where(eq(apiTokens.id, id)).returning({ id: apiTokens.id });
return result.length > 0;
} }
async listApiTokensByUserId(userId: number): Promise<ApiToken[]> { async listApiTokensByUserId(userId: number): Promise<ApiToken[]> {
return Array.from(this.apiTokens.values()).filter( return db.select().from(apiTokens).where(eq(apiTokens.userId, userId));
(token) => token.userId === userId,
);
} }
// LDAP Connection management // LDAP Connection management
async getLdapConnection(id: number): Promise<LdapConnection | undefined> { async getLdapConnection(id: number): Promise<LdapConnection | undefined> {
return this.ldapConnections.get(id); const result = await db.select().from(ldapConnections).where(eq(ldapConnections.id, id));
return result.length > 0 ? result[0] : undefined;
} }
async createLdapConnection(insertConnection: InsertLdapConnection): Promise<LdapConnection> { async createLdapConnection(insertConnection: InsertLdapConnection): Promise<LdapConnection> {
const id = this.connectionCurrentId++; const result = await db.insert(ldapConnections).values(insertConnection).returning();
const now = new Date(); return result[0];
const connection: LdapConnection = {
...insertConnection,
id,
createdAt: now,
lastConnected: null,
status: "disconnected"
};
this.ldapConnections.set(id, connection);
return connection;
} }
async updateLdapConnection(id: number, connectionData: Partial<LdapConnection>): Promise<LdapConnection | undefined> { async updateLdapConnection(id: number, connectionData: Partial<LdapConnection>): Promise<LdapConnection | undefined> {
const connection = await this.getLdapConnection(id); const result = await db.update(ldapConnections).set(connectionData).where(eq(ldapConnections.id, id)).returning();
if (!connection) return undefined; return result.length > 0 ? result[0] : undefined;
const updatedConnection = { ...connection, ...connectionData };
this.ldapConnections.set(id, updatedConnection);
return updatedConnection;
} }
async deleteLdapConnection(id: number): Promise<boolean> { async deleteLdapConnection(id: number): Promise<boolean> {
return this.ldapConnections.delete(id); const result = await db.delete(ldapConnections).where(eq(ldapConnections.id, id)).returning({ id: ldapConnections.id });
return result.length > 0;
} }
async listLdapConnections(): Promise<LdapConnection[]> { async listLdapConnections(): Promise<LdapConnection[]> {
return Array.from(this.ldapConnections.values()); return db.select().from(ldapConnections);
} }
// AD Users // AD Users
async getAdUser(id: number): Promise<AdUser | undefined> { async getAdUser(id: number): Promise<AdUser | undefined> {
return this.adUsers.get(id); const result = await db.select().from(adUsers).where(eq(adUsers.id, id));
return result.length > 0 ? result[0] : undefined;
} }
async createAdUser(user: InsertAdUser): Promise<AdUser> { async createAdUser(user: InsertAdUser): Promise<AdUser> {
const id = this.adUserCurrentId++; const result = await db.insert(adUsers).values(user).returning();
const adUser: AdUser = { ...user, id }; return result[0];
this.adUsers.set(id, adUser);
return adUser;
} }
async updateAdUser(id: number, userData: Partial<AdUser>): Promise<AdUser | undefined> { async updateAdUser(id: number, userData: Partial<AdUser>): Promise<AdUser | undefined> {
const user = await this.getAdUser(id); const result = await db.update(adUsers).set(userData).where(eq(adUsers.id, id)).returning();
if (!user) return undefined; return result.length > 0 ? result[0] : undefined;
const updatedUser = { ...user, ...userData };
this.adUsers.set(id, updatedUser);
return updatedUser;
} }
async deleteAdUser(id: number): Promise<boolean> { async deleteAdUser(id: number): Promise<boolean> {
return this.adUsers.delete(id); const result = await db.delete(adUsers).where(eq(adUsers.id, id)).returning({ id: adUsers.id });
return result.length > 0;
} }
async listAdUsers(connectionId: number, query?: any): Promise<AdUser[]> { async listAdUsers(connectionId: number, query?: any): Promise<AdUser[]> {
let users = Array.from(this.adUsers.values()).filter( let adUsersQuery = db.select().from(adUsers).where(eq(adUsers.connectionId, connectionId));
(user) => user.connectionId === connectionId,
);
// Apply filtering logic based on query // Handle filtering logic
if (query) { if (query && query.select) {
if (query.filter) { // Note: This is a simplified implementation
// Simple filter implementation - can be expanded // For production, you would need a more robust property selection mechanism
const filterParts = query.filter.split(' '); const users = await adUsersQuery;
if (filterParts.length === 3) { const properties = query.select.split(',');
const [property, operator, value] = filterParts;
const unquotedValue = value.replace(/^'|'$/g, '');
if (operator === 'eq') { return users.map(user => {
users = users.filter(user => (user as any)[property] === unquotedValue); const result: any = { id: user.id };
properties.forEach(prop => {
if ((user as any)[prop] !== undefined) {
result[prop] = (user as any)[prop];
} }
}
}
// Apply property selection
if (query.select) {
const properties = query.select.split(',');
users = users.map(user => {
const result: any = { id: user.id };
properties.forEach(prop => {
if ((user as any)[prop] !== undefined) {
result[prop] = (user as any)[prop];
}
});
return result as AdUser;
}); });
} return result as AdUser;
});
} }
return users; return adUsersQuery;
} }
// AD Groups // AD Groups
async getAdGroup(id: number): Promise<AdGroup | undefined> { async getAdGroup(id: number): Promise<AdGroup | undefined> {
return this.adGroups.get(id); const result = await db.select().from(adGroups).where(eq(adGroups.id, id));
return result.length > 0 ? result[0] : undefined;
} }
async createAdGroup(group: InsertAdGroup): Promise<AdGroup> { async createAdGroup(group: InsertAdGroup): Promise<AdGroup> {
const id = this.adGroupCurrentId++; const result = await db.insert(adGroups).values(group).returning();
const adGroup: AdGroup = { ...group, id }; return result[0];
this.adGroups.set(id, adGroup);
return adGroup;
} }
async updateAdGroup(id: number, groupData: Partial<AdGroup>): Promise<AdGroup | undefined> { async updateAdGroup(id: number, groupData: Partial<AdGroup>): Promise<AdGroup | undefined> {
const group = await this.getAdGroup(id); const result = await db.update(adGroups).set(groupData).where(eq(adGroups.id, id)).returning();
if (!group) return undefined; return result.length > 0 ? result[0] : undefined;
const updatedGroup = { ...group, ...groupData };
this.adGroups.set(id, updatedGroup);
return updatedGroup;
} }
async deleteAdGroup(id: number): Promise<boolean> { async deleteAdGroup(id: number): Promise<boolean> {
return this.adGroups.delete(id); const result = await db.delete(adGroups).where(eq(adGroups.id, id)).returning({ id: adGroups.id });
return result.length > 0;
} }
async listAdGroups(connectionId: number, query?: any): Promise<AdGroup[]> { async listAdGroups(connectionId: number, query?: any): Promise<AdGroup[]> {
let groups = Array.from(this.adGroups.values()).filter( let adGroupsQuery = db.select().from(adGroups).where(eq(adGroups.connectionId, connectionId));
(group) => group.connectionId === connectionId,
);
// Apply filtering logic // Handle filtering logic (similar to listAdUsers)
if (query) { if (query && query.select) {
if (query.select) { const groups = await adGroupsQuery;
const properties = query.select.split(','); const properties = query.select.split(',');
groups = groups.map(group => {
const result: any = { id: group.id }; return groups.map(group => {
properties.forEach(prop => { const result: any = { id: group.id };
if ((group as any)[prop] !== undefined) { properties.forEach(prop => {
result[prop] = (group as any)[prop]; if ((group as any)[prop] !== undefined) {
} result[prop] = (group as any)[prop];
}); }
return result as AdGroup;
}); });
} return result as AdGroup;
});
} }
return groups; return adGroupsQuery;
} }
// AD Organizational Units // AD Organizational Units
async getAdOrgUnit(id: number): Promise<AdOrgUnit | undefined> { async getAdOrgUnit(id: number): Promise<AdOrgUnit | undefined> {
return this.adOrgUnits.get(id); const result = await db.select().from(adOrgUnits).where(eq(adOrgUnits.id, id));
return result.length > 0 ? result[0] : undefined;
} }
async createAdOrgUnit(ou: InsertAdOrgUnit): Promise<AdOrgUnit> { async createAdOrgUnit(ou: InsertAdOrgUnit): Promise<AdOrgUnit> {
const id = this.adOrgUnitCurrentId++; const result = await db.insert(adOrgUnits).values(ou).returning();
const adOrgUnit: AdOrgUnit = { ...ou, id }; return result[0];
this.adOrgUnits.set(id, adOrgUnit);
return adOrgUnit;
} }
async updateAdOrgUnit(id: number, ouData: Partial<AdOrgUnit>): Promise<AdOrgUnit | undefined> { async updateAdOrgUnit(id: number, ouData: Partial<AdOrgUnit>): Promise<AdOrgUnit | undefined> {
const ou = await this.getAdOrgUnit(id); const result = await db.update(adOrgUnits).set(ouData).where(eq(adOrgUnits.id, id)).returning();
if (!ou) return undefined; return result.length > 0 ? result[0] : undefined;
const updatedOu = { ...ou, ...ouData };
this.adOrgUnits.set(id, updatedOu);
return updatedOu;
} }
async deleteAdOrgUnit(id: number): Promise<boolean> { async deleteAdOrgUnit(id: number): Promise<boolean> {
return this.adOrgUnits.delete(id); const result = await db.delete(adOrgUnits).where(eq(adOrgUnits.id, id)).returning({ id: adOrgUnits.id });
return result.length > 0;
} }
async listAdOrgUnits(connectionId: number, query?: any): Promise<AdOrgUnit[]> { async listAdOrgUnits(connectionId: number, query?: any): Promise<AdOrgUnit[]> {
let orgUnits = Array.from(this.adOrgUnits.values()).filter( let adOrgUnitsQuery = db.select().from(adOrgUnits).where(eq(adOrgUnits.connectionId, connectionId));
(ou) => ou.connectionId === connectionId,
);
// Apply filtering logic // Handle filtering logic (similar to listAdUsers)
if (query) { if (query && query.select) {
if (query.select) { const orgUnits = await adOrgUnitsQuery;
const properties = query.select.split(','); const properties = query.select.split(',');
orgUnits = orgUnits.map(ou => {
const result: any = { id: ou.id }; return orgUnits.map(ou => {
properties.forEach(prop => { const result: any = { id: ou.id };
if ((ou as any)[prop] !== undefined) { properties.forEach(prop => {
result[prop] = (ou as any)[prop]; if ((ou as any)[prop] !== undefined) {
} result[prop] = (ou as any)[prop];
}); }
return result as AdOrgUnit;
}); });
} return result as AdOrgUnit;
});
} }
return orgUnits; return adOrgUnitsQuery;
} }
// AD Computers // AD Computers
async getAdComputer(id: number): Promise<AdComputer | undefined> { async getAdComputer(id: number): Promise<AdComputer | undefined> {
return this.adComputers.get(id); const result = await db.select().from(adComputers).where(eq(adComputers.id, id));
return result.length > 0 ? result[0] : undefined;
} }
async createAdComputer(computer: InsertAdComputer): Promise<AdComputer> { async createAdComputer(computer: InsertAdComputer): Promise<AdComputer> {
const id = this.adComputerCurrentId++; const result = await db.insert(adComputers).values(computer).returning();
const adComputer: AdComputer = { ...computer, id }; return result[0];
this.adComputers.set(id, adComputer);
return adComputer;
} }
async updateAdComputer(id: number, computerData: Partial<AdComputer>): Promise<AdComputer | undefined> { async updateAdComputer(id: number, computerData: Partial<AdComputer>): Promise<AdComputer | undefined> {
const computer = await this.getAdComputer(id); const result = await db.update(adComputers).set(computerData).where(eq(adComputers.id, id)).returning();
if (!computer) return undefined; return result.length > 0 ? result[0] : undefined;
const updatedComputer = { ...computer, ...computerData };
this.adComputers.set(id, updatedComputer);
return updatedComputer;
} }
async deleteAdComputer(id: number): Promise<boolean> { async deleteAdComputer(id: number): Promise<boolean> {
return this.adComputers.delete(id); const result = await db.delete(adComputers).where(eq(adComputers.id, id)).returning({ id: adComputers.id });
return result.length > 0;
} }
async listAdComputers(connectionId: number, query?: any): Promise<AdComputer[]> { async listAdComputers(connectionId: number, query?: any): Promise<AdComputer[]> {
let computers = Array.from(this.adComputers.values()).filter( let adComputersQuery = db.select().from(adComputers).where(eq(adComputers.connectionId, connectionId));
(computer) => computer.connectionId === connectionId,
);
// Apply filtering logic // Handle filtering logic (similar to listAdUsers)
if (query) { if (query && query.select) {
if (query.select) { const computers = await adComputersQuery;
const properties = query.select.split(','); const properties = query.select.split(',');
computers = computers.map(computer => {
const result: any = { id: computer.id }; return computers.map(computer => {
properties.forEach(prop => { const result: any = { id: computer.id };
if ((computer as any)[prop] !== undefined) { properties.forEach(prop => {
result[prop] = (computer as any)[prop]; if ((computer as any)[prop] !== undefined) {
} result[prop] = (computer as any)[prop];
}); }
return result as AdComputer;
}); });
} return result as AdComputer;
});
} }
return computers; return adComputersQuery;
} }
// AD Domains // AD Domains
async getAdDomain(id: number): Promise<AdDomain | undefined> { async getAdDomain(id: number): Promise<AdDomain | undefined> {
return this.adDomains.get(id); const result = await db.select().from(adDomains).where(eq(adDomains.id, id));
return result.length > 0 ? result[0] : undefined;
} }
async createAdDomain(domain: InsertAdDomain): Promise<AdDomain> { async createAdDomain(domain: InsertAdDomain): Promise<AdDomain> {
const id = this.adDomainCurrentId++; const result = await db.insert(adDomains).values(domain).returning();
const adDomain: AdDomain = { ...domain, id }; return result[0];
this.adDomains.set(id, adDomain);
return adDomain;
} }
async updateAdDomain(id: number, domainData: Partial<AdDomain>): Promise<AdDomain | undefined> { async updateAdDomain(id: number, domainData: Partial<AdDomain>): Promise<AdDomain | undefined> {
const domain = await this.getAdDomain(id); const result = await db.update(adDomains).set(domainData).where(eq(adDomains.id, id)).returning();
if (!domain) return undefined; return result.length > 0 ? result[0] : undefined;
const updatedDomain = { ...domain, ...domainData };
this.adDomains.set(id, updatedDomain);
return updatedDomain;
} }
async deleteAdDomain(id: number): Promise<boolean> { async deleteAdDomain(id: number): Promise<boolean> {
return this.adDomains.delete(id); const result = await db.delete(adDomains).where(eq(adDomains.id, id)).returning({ id: adDomains.id });
return result.length > 0;
} }
async listAdDomains(connectionId: number, query?: any): Promise<AdDomain[]> { async listAdDomains(connectionId: number, query?: any): Promise<AdDomain[]> {
let domains = Array.from(this.adDomains.values()).filter( let adDomainsQuery = db.select().from(adDomains).where(eq(adDomains.connectionId, connectionId));
(domain) => domain.connectionId === connectionId,
);
// Apply filtering logic // Handle filtering logic (similar to listAdUsers)
if (query) { if (query && query.select) {
if (query.select) { const domains = await adDomainsQuery;
const properties = query.select.split(','); const properties = query.select.split(',');
domains = domains.map(domain => {
const result: any = { id: domain.id }; return domains.map(domain => {
properties.forEach(prop => { const result: any = { id: domain.id };
if ((domain as any)[prop] !== undefined) { properties.forEach(prop => {
result[prop] = (domain as any)[prop]; if ((domain as any)[prop] !== undefined) {
} result[prop] = (domain as any)[prop];
}); }
return result as AdDomain;
}); });
} return result as AdDomain;
});
} }
return domains; return adDomainsQuery;
} }
} }
export const storage = new MemStorage(); export const storage = new DatabaseStorage();