Add local user authentication and admin capabilities

Implement local user authentication with password hashing, add admin roles for user management and audit log viewing, and introduce audit logging for critical actions.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 776963d0-f75d-42e2-a57b-cc36bdff8495
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 832a44ff-12ae-4096-8a0d-666ec083d536
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/0683fb79-a27c-485c-9333-5f4b288c4567/776963d0-f75d-42e2-a57b-cc36bdff8495/1p7jhzu
Replit-Helium-Checkpoint-Created: true
This commit is contained in:
cheffe01
2026-05-25 14:11:02 +00:00
parent b8ba53598d
commit c5ca3ca992
44 changed files with 2554 additions and 34 deletions
+114 -1
View File
@@ -33,6 +33,7 @@ export const ListToolsResponseItem = zod.object({
"category": zod.string(),
"websiteUrl": zod.string().nullish(),
"iconUrl": zod.string().nullish(),
"createdBy": zod.string().nullish(),
"features": zod.array(zod.string()).optional(),
"tags": zod.array(zod.string()).optional(),
"createdAt": zod.coerce.date(),
@@ -78,6 +79,7 @@ export const GetToolResponse = zod.object({
"category": zod.string(),
"websiteUrl": zod.string().nullish(),
"iconUrl": zod.string().nullish(),
"createdBy": zod.string().nullish(),
"features": zod.array(zod.string()).optional(),
"tags": zod.array(zod.string()).optional(),
"createdAt": zod.coerce.date(),
@@ -116,6 +118,7 @@ export const UpdateToolResponse = zod.object({
"category": zod.string(),
"websiteUrl": zod.string().nullish(),
"iconUrl": zod.string().nullish(),
"createdBy": zod.string().nullish(),
"features": zod.array(zod.string()).optional(),
"tags": zod.array(zod.string()).optional(),
"createdAt": zod.coerce.date(),
@@ -194,6 +197,7 @@ export const GetAnalyticsSummaryResponse = zod.object({
"category": zod.string(),
"websiteUrl": zod.string().nullish(),
"iconUrl": zod.string().nullish(),
"createdBy": zod.string().nullish(),
"features": zod.array(zod.string()).optional(),
"tags": zod.array(zod.string()).optional(),
"createdAt": zod.coerce.date(),
@@ -222,6 +226,7 @@ export const GetTopToolsResponseItem = zod.object({
"category": zod.string(),
"websiteUrl": zod.string().nullish(),
"iconUrl": zod.string().nullish(),
"createdBy": zod.string().nullish(),
"features": zod.array(zod.string()).optional(),
"tags": zod.array(zod.string()).optional(),
"createdAt": zod.coerce.date(),
@@ -283,6 +288,32 @@ export const ListAllFeaturesResponseItem = zod.string()
export const ListAllFeaturesResponse = zod.array(ListAllFeaturesResponseItem)
/**
* @summary Get authentication mode (oidc or local)
*/
export const GetAuthModeResponse = zod.object({
"mode": zod.enum(['oidc', 'local'])
})
/**
* @summary Local username/password login
*/
export const LocalLoginBody = zod.object({
"username": zod.string(),
"password": zod.string()
})
export const LocalLoginResponse = zod.object({
"sub": zod.string(),
"email": zod.string().nullish(),
"name": zod.string().nullish(),
"preferredUsername": zod.string().nullish(),
"role": zod.enum(['admin', 'user']).optional(),
"isLocal": zod.boolean().optional()
})
/**
* @summary Get current authenticated user
*/
@@ -290,7 +321,89 @@ export const GetMeResponse = zod.object({
"sub": zod.string(),
"email": zod.string().nullish(),
"name": zod.string().nullish(),
"preferredUsername": zod.string().nullish()
"preferredUsername": zod.string().nullish(),
"role": zod.enum(['admin', 'user']).optional(),
"isLocal": zod.boolean().optional()
})
/**
* @summary List all local users (admin only)
*/
export const ListUsersResponseItem = zod.object({
"id": zod.number(),
"username": zod.string(),
"email": zod.string().nullish(),
"role": zod.enum(['admin', 'user']),
"createdAt": zod.coerce.date()
})
export const ListUsersResponse = zod.array(ListUsersResponseItem)
/**
* @summary Create a new local user (admin only)
*/
export const createUserBodyUsernameMin = 2;
export const createUserBodyPasswordMin = 6;
export const CreateUserBody = zod.object({
"username": zod.string().min(createUserBodyUsernameMin),
"password": zod.string().min(createUserBodyPasswordMin),
"email": zod.string().optional(),
"role": zod.enum(['admin', 'user']).optional()
})
/**
* @summary Update user role (admin only)
*/
export const UpdateUserParams = zod.object({
"id": zod.coerce.number()
})
export const UpdateUserBody = zod.object({
"role": zod.enum(['admin', 'user'])
})
export const UpdateUserResponse = zod.object({
"id": zod.number(),
"username": zod.string(),
"email": zod.string().nullish(),
"role": zod.enum(['admin', 'user']),
"createdAt": zod.coerce.date()
})
/**
* @summary Delete a user (admin only)
*/
export const DeleteUserParams = zod.object({
"id": zod.coerce.number()
})
/**
* @summary List audit log entries (admin only)
*/
export const ListAuditLogsQueryParams = zod.object({
"entityType": zod.coerce.string().optional(),
"entityId": zod.coerce.number().optional(),
"limit": zod.coerce.number().optional()
})
export const ListAuditLogsResponseItem = zod.object({
"id": zod.number(),
"entityType": zod.string(),
"entityId": zod.number().nullish(),
"action": zod.string(),
"userId": zod.string(),
"username": zod.string(),
"changes": zod.string().nullish(),
"createdAt": zod.coerce.date()
})
export const ListAuditLogsResponse = zod.array(ListAuditLogsResponseItem)
@@ -0,0 +1,20 @@
/**
* Generated by orval v8.9.1 🍺
* Do not edit manually.
* Api
* ToolRate API — Tool listing and rating platform
* OpenAPI spec version: 0.1.0
*/
export interface AuditLog {
id: number;
entityType: string;
/** @nullable */
entityId?: number | null;
action: string;
userId: string;
username: string;
/** @nullable */
changes?: string | null;
createdAt: Date;
}
@@ -0,0 +1,12 @@
/**
* Generated by orval v8.9.1 🍺
* Do not edit manually.
* Api
* ToolRate API — Tool listing and rating platform
* OpenAPI spec version: 0.1.0
*/
import type { AuthModeMode } from './authModeMode';
export interface AuthMode {
mode: AuthModeMode;
}
@@ -0,0 +1,15 @@
/**
* Generated by orval v8.9.1 🍺
* Do not edit manually.
* Api
* ToolRate API — Tool listing and rating platform
* OpenAPI spec version: 0.1.0
*/
export type AuthModeMode = typeof AuthModeMode[keyof typeof AuthModeMode];
export const AuthModeMode = {
oidc: 'oidc',
local: 'local',
} as const;
@@ -5,6 +5,7 @@
* ToolRate API — Tool listing and rating platform
* OpenAPI spec version: 0.1.0
*/
import type { AuthUserRole } from './authUserRole';
export interface AuthUser {
sub: string;
@@ -14,4 +15,6 @@ export interface AuthUser {
name?: string | null;
/** @nullable */
preferredUsername?: string | null;
role?: AuthUserRole;
isLocal?: boolean;
}
@@ -0,0 +1,15 @@
/**
* Generated by orval v8.9.1 🍺
* Do not edit manually.
* Api
* ToolRate API — Tool listing and rating platform
* OpenAPI spec version: 0.1.0
*/
export type AuthUserRole = typeof AuthUserRole[keyof typeof AuthUserRole];
export const AuthUserRole = {
admin: 'admin',
user: 'user',
} as const;
+12
View File
@@ -7,15 +7,21 @@
*/
export * from './analyticsSummary';
export * from './auditLog';
export * from './authMode';
export * from './authModeMode';
export * from './authUser';
export * from './authUserRole';
export * from './categoryStats';
export * from './errorResponse';
export * from './getRatingDistributionParams';
export * from './getTopToolsMetric';
export * from './getTopToolsParams';
export * from './healthStatus';
export * from './listAuditLogsParams';
export * from './listToolsParams';
export * from './listToolsSort';
export * from './localLoginInput';
export * from './rating';
export * from './ratingDistribution';
export * from './ratingInput';
@@ -25,3 +31,9 @@ export * from './toolInput';
export * from './toolUpdate';
export * from './toolWithStats';
export * from './topToolEntry';
export * from './user';
export * from './userCreateInput';
export * from './userCreateInputRole';
export * from './userRole';
export * from './userRoleUpdate';
export * from './userRoleUpdateRole';
@@ -0,0 +1,13 @@
/**
* Generated by orval v8.9.1 🍺
* Do not edit manually.
* Api
* ToolRate API — Tool listing and rating platform
* OpenAPI spec version: 0.1.0
*/
export type ListAuditLogsParams = {
entityType?: string;
entityId?: number;
limit?: number;
};
@@ -0,0 +1,12 @@
/**
* Generated by orval v8.9.1 🍺
* Do not edit manually.
* Api
* ToolRate API — Tool listing and rating platform
* OpenAPI spec version: 0.1.0
*/
export interface LocalLoginInput {
username: string;
password: string;
}
+2
View File
@@ -15,6 +15,8 @@ export interface Tool {
websiteUrl?: string | null;
/** @nullable */
iconUrl?: string | null;
/** @nullable */
createdBy?: string | null;
features?: string[];
tags?: string[];
createdAt: Date;
@@ -15,6 +15,8 @@ export interface ToolWithStats {
websiteUrl?: string | null;
/** @nullable */
iconUrl?: string | null;
/** @nullable */
createdBy?: string | null;
features?: string[];
tags?: string[];
createdAt: Date;
+17
View File
@@ -0,0 +1,17 @@
/**
* Generated by orval v8.9.1 🍺
* Do not edit manually.
* Api
* ToolRate API — Tool listing and rating platform
* OpenAPI spec version: 0.1.0
*/
import type { UserRole } from './userRole';
export interface User {
id: number;
username: string;
/** @nullable */
email?: string | null;
role: UserRole;
createdAt: Date;
}
@@ -0,0 +1,17 @@
/**
* Generated by orval v8.9.1 🍺
* Do not edit manually.
* Api
* ToolRate API — Tool listing and rating platform
* OpenAPI spec version: 0.1.0
*/
import type { UserCreateInputRole } from './userCreateInputRole';
export interface UserCreateInput {
/** @minLength 2 */
username: string;
/** @minLength 6 */
password: string;
email?: string;
role?: UserCreateInputRole;
}
@@ -0,0 +1,15 @@
/**
* Generated by orval v8.9.1 🍺
* Do not edit manually.
* Api
* ToolRate API — Tool listing and rating platform
* OpenAPI spec version: 0.1.0
*/
export type UserCreateInputRole = typeof UserCreateInputRole[keyof typeof UserCreateInputRole];
export const UserCreateInputRole = {
admin: 'admin',
user: 'user',
} as const;
@@ -0,0 +1,15 @@
/**
* Generated by orval v8.9.1 🍺
* Do not edit manually.
* Api
* ToolRate API — Tool listing and rating platform
* OpenAPI spec version: 0.1.0
*/
export type UserRole = typeof UserRole[keyof typeof UserRole];
export const UserRole = {
admin: 'admin',
user: 'user',
} as const;
@@ -0,0 +1,12 @@
/**
* Generated by orval v8.9.1 🍺
* Do not edit manually.
* Api
* ToolRate API — Tool listing and rating platform
* OpenAPI spec version: 0.1.0
*/
import type { UserRoleUpdateRole } from './userRoleUpdateRole';
export interface UserRoleUpdate {
role: UserRoleUpdateRole;
}
@@ -0,0 +1,15 @@
/**
* Generated by orval v8.9.1 🍺
* Do not edit manually.
* Api
* ToolRate API — Tool listing and rating platform
* OpenAPI spec version: 0.1.0
*/
export type UserRoleUpdateRole = typeof UserRoleUpdateRole[keyof typeof UserRoleUpdateRole];
export const UserRoleUpdateRole = {
admin: 'admin',
user: 'user',
} as const;