auth module controllers carried

This commit is contained in:
2025-07-26 21:51:27 +03:00
parent 2e10de9758
commit f39dc541e1
58 changed files with 745 additions and 527 deletions

View File

@@ -1,4 +1,4 @@
import crypto from 'crypto';
import * as crypto from 'crypto';
import { v4 as uuidv4 } from 'uuid';
interface TokenConfig {
@@ -12,28 +12,29 @@ const tokenConfig: TokenConfig = {
};
class PasswordHandlers {
generate_random_uu_id(is_string: boolean = true): string {
generateRandomUUID(is_string: boolean = true): string {
return is_string ? uuidv4().toString() : uuidv4();
}
create_hashed_password(
domain: string,
uuid: string,
password: string,
): string {
const data = `${domain}:${uuid}:${password}`;
create_hashed_password(uuid: string, password: string): string {
const data = `${uuid}:${password}`;
console.log(crypto.createHash('sha256').update(data).digest('hex'));
return crypto.createHash('sha256').update(data).digest('hex');
}
createSelectToken(accessToken: string, userUUID: string) {
const data = `${accessToken}:${userUUID}`;
return crypto.createHash('sha256').update(data).digest('hex');
}
check_password(
domain: string,
uuid: string,
password: string,
hashed_password: string,
): boolean {
return (
this.create_hashed_password(domain, uuid, password) === hashed_password
);
const created_hashed_password = this.create_hashed_password(uuid, password);
console.log('created_hashed_password', created_hashed_password);
return created_hashed_password === hashed_password;
}
generateAccessToken(): string {

View File

@@ -1,7 +1,7 @@
import {
TokenDictType,
OccupantTokenObject,
EmployeeTokenObject,
TokenDictTypes,
TokenDictInterface,
AuthToken,
UserType,
} from '@/src/types/auth/token';
import { CacheService } from '@/src/cache.service';
@@ -15,110 +15,50 @@ export class RedisHandlers {
constructor(
private readonly cacheService: CacheService,
private readonly passwordService: PasswordHandlers,
) {
this.cacheService = cacheService;
this.passwordService = passwordService;
) {}
generateSelectToken(accessToken: string, userUUID: string) {
return this.passwordService.createSelectToken(accessToken, userUUID);
}
async process_redis_object(redis_object: any): Promise<TokenDictType> {
if (!redis_object) {
throw new Error('Invalid Redis object: Object is null or undefined');
}
if (redis_object.user_type === UserType.employee) {
const validateEmployeeToken = (obj: any): obj is EmployeeTokenObject => {
return (
typeof obj === 'object' &&
obj !== null &&
typeof obj.user_type === 'number' &&
typeof obj.user_uu_id === 'string' &&
typeof obj.user_id === 'number' &&
typeof obj.person_id === 'number' &&
typeof obj.person_uu_id === 'string' &&
Array.isArray(obj.companies_id_list) &&
Array.isArray(obj.companies_uu_id_list) &&
Array.isArray(obj.duty_id_list) &&
Array.isArray(obj.duty_uu_id_list)
);
};
const empToken: EmployeeTokenObject = {
...redis_object,
is_employee: true,
is_occupant: false,
user_type: UserType.employee,
credential_token: redis_object.credential_token || '',
};
if (!validateEmployeeToken(empToken)) {
throw new Error(
'Invalid Redis object: Does not match EmployeeTokenObject interface',
);
}
return empToken;
}
if (redis_object.user_type === UserType.occupant) {
const validateOccupantToken = (obj: any): obj is OccupantTokenObject => {
return (
typeof obj === 'object' &&
obj !== null &&
typeof obj.user_type === 'number' &&
typeof obj.user_uu_id === 'string' &&
typeof obj.user_id === 'number' &&
typeof obj.person_id === 'number' &&
typeof obj.person_uu_id === 'string'
);
};
const occToken: OccupantTokenObject = {
...redis_object,
is_employee: false,
is_occupant: true,
user_type: UserType.occupant,
credential_token: redis_object.credential_token || '',
available_occupants: redis_object.available_occupants || null,
};
if (!validateOccupantToken(occToken)) {
throw new Error(
'Invalid Redis object: Does not match OccupantTokenObject interface',
);
}
return occToken;
}
throw new Error(`Invalid user_type: ${redis_object.user_type}`);
generateAccessToken() {
return this.passwordService.generateAccessToken();
}
async get_object_from_redis(access_token: string): Promise<TokenDictType> {
const token = await this.cacheService.get(access_token);
return this.process_redis_object(token);
async getLoginFromRedis(redisKey: string): Promise<AuthToken> {
return this.cacheService.get(redisKey);
}
async set_login_to_redis(user: users, token: TokenDictType): Promise<any> {
const generated_token = this.passwordService.generateAccessToken();
const listKeys = [this.AUTH_TOKEN, generated_token, user.uu_id];
await this.cacheService.set_with_ttl(
this.cacheService.createRegexPattern(listKeys),
token,
60 * 60 * 24,
);
return generated_token;
async getSelectFromRedis(redisKey: string): Promise<TokenDictInterface> {
return this.cacheService.get(redisKey);
}
async update_token_via_token(token: string, additional: any): Promise<any> {
const listKeys = [this.AUTH_TOKEN, token, '*'];
const accessObject = await this.cacheService.get_with_keys(listKeys);
if (!accessObject) throw new Error('Token not found');
const processedObject: TokenDictType =
await this.process_redis_object(accessObject);
if (processedObject.is_employee) {
processedObject.selected = additional;
}
if (processedObject.is_occupant) {
processedObject.selected = additional;
}
const listKeysNew = [this.AUTH_TOKEN, token, processedObject.user_uu_id];
await this.cacheService.set_with_ttl(
this.cacheService.createRegexPattern(listKeysNew),
processedObject,
60 * 60 * 24,
);
return token;
async renewTtlLoginFromRedis(redisKey: string): Promise<any> {
const token = await this.getLoginFromRedis(redisKey);
return this.cacheService.set_with_ttl(redisKey, token, 60 * 30);
}
async renewTtlSelectFromRedis(redisKey: string): Promise<any> {
const token = await this.getSelectFromRedis(redisKey);
return this.cacheService.set_with_ttl(redisKey, token, 60 * 30);
}
async setLoginToRedis(token: AuthToken, userUUID: string): Promise<any> {
const accessToken = this.generateAccessToken();
const redisKey = `${this.AUTH_TOKEN}:${accessToken}:${accessToken}:${userUUID}:${userUUID}`;
await this.cacheService.set_with_ttl(redisKey, token, 60 * 30);
return accessToken;
}
async setSelectToRedis(
accessToken: string,
token: TokenDictInterface,
userUUID: string,
livingUUID: string,
): Promise<any> {
const selectToken = this.generateSelectToken(accessToken, userUUID);
const redisKey = `${this.AUTH_TOKEN}:${accessToken}:${selectToken}:${userUUID}:${livingUUID}`;
await this.cacheService.set_with_ttl(redisKey, token, 60 * 30);
return selectToken;
}
}

View File

@@ -0,0 +1,95 @@
import { INestApplication, RequestMethod } from '@nestjs/common';
import { ModulesContainer, Reflector } from '@nestjs/core';
import { PATH_METADATA, METHOD_METADATA } from '@nestjs/common/constants';
import { PrismaService } from '@/src/prisma.service';
/**
* Helper: Method string'i döndür
*/
function getMethodString(requestMethod: RequestMethod): string {
return RequestMethod[requestMethod];
}
/**
* Helper: Path'leri normalize et (iki tane slash varsa düzelt)
*/
function normalizePath(...paths: string[]): string {
const normalized =
'/' +
paths
.filter(Boolean)
.map((p) => p.replace(/^\/|\/$/g, ''))
.filter((p) => p.length > 0)
.join('/');
return normalized === '/' ? '' : normalized; // Home route'ı dışla
}
export async function extractAndPersistRoutes(
app: INestApplication,
prisma: PrismaService,
): Promise<{ method: string; url: string }[]> {
const modulesContainer = app.get(ModulesContainer);
const reflector = app.get(Reflector);
const routes: { method: string; url: string }[] = [];
modulesContainer.forEach((moduleRef) => {
const controllers = [...moduleRef.controllers.values()];
controllers.forEach(({ metatype }) => {
if (!metatype || typeof metatype !== 'function') return;
const controllerPath =
reflector.get<string>(PATH_METADATA, metatype) ?? '';
const prototype = metatype.prototype;
const methodNames = Object.getOwnPropertyNames(prototype).filter(
(m) => m !== 'constructor',
);
methodNames.forEach((methodName) => {
const methodRef = prototype[methodName];
const routePath = reflector.get<string>(PATH_METADATA, methodRef);
const requestMethod = reflector.get<RequestMethod>(
METHOD_METADATA,
methodRef,
);
if (routePath !== undefined && requestMethod !== undefined) {
const method = getMethodString(requestMethod);
const fullPath = normalizePath(controllerPath, routePath);
if (fullPath !== '') {
routes.push({ method, url: fullPath });
}
}
});
});
});
const existing = await prisma.endpoint_restriction.findMany({
select: { endpoint_name: true, endpoint_method: true },
});
const existingSet = new Set(
existing.map((r) => `${r.endpoint_method}_${r.endpoint_name}`),
);
const newOnes = routes.filter(
(r) => !existingSet.has(`${r.method}_${r.url}`),
);
// İsteğe bağlı: veritabanına kaydet
// for (const route of newOnes) {
// await prisma.endpoint_restriction.create({
// data: {
// endpoint_method: route.method,
// endpoint_name: route.url,
// is_active: true,
// },
// });
// }
console.log('🧭 Route JSON Listesi:');
console.dir(routes, { depth: null });
return routes;
}

View File

@@ -1,9 +1,18 @@
import { Module } from '@nestjs/common';
import { PaginationHelper } from './pagination-helper';
import { PrismaService } from '@/src/prisma.service';
import { RedisHandlers } from './auth/redis_handlers';
import { PasswordHandlers } from './auth/login_handler';
import { CacheService } from '@/src/cache.service';
@Module({
providers: [PaginationHelper, PrismaService],
exports: [PaginationHelper],
providers: [
PaginationHelper,
PrismaService,
RedisHandlers,
PasswordHandlers,
CacheService,
],
exports: [PaginationHelper, RedisHandlers, PasswordHandlers, CacheService],
})
export class UtilsModule {}