feat: enhance authentication and user management with token-based system

- Implemented robust token-based authentication with access and refresh tokens
- Added JWT token generation, verification, and rotation mechanisms
- Created services for token management, Memcached, and MinIO storage
- Enhanced user registration and login with device-specific tokens
- Added support for profile picture upload and management via MinIO
- Implemented secure password hashing with crypto
- Updated Prisma schema to support refresh tokens and profile picture storage
- Added GraphQL mutations for logout, token refresh, and profile picture handling
- Integrated environment configuration with Zod validation
- Improved error handling and authentication middleware
This commit is contained in:
Juan Sebastián Montoya 2025-03-09 22:34:57 -05:00
parent d4d99fb5e7
commit d29d116214
22 changed files with 1992 additions and 388 deletions

View file

@ -0,0 +1,106 @@
import { Client } from 'minio';
import { MinioConfig } from '../config';
/**
* Service for handling MinIO operations
*/
export class MinioService {
private client: Client;
private bucketName: string;
private readonly defaultExpiry = 60 * 60; // 1 hour in seconds
private initialized = false;
/**
* Creates a new MinioService instance
* @param config - MinIO configuration
*/
constructor(config: MinioConfig) {
this.client = new Client(config);
this.bucketName = config.bucketName;
}
/**
* Initializes the MinIO service by ensuring the bucket exists
*/
public async initialize(): Promise<void> {
if (this.initialized) {
return;
}
const bucketExists = await this.client.bucketExists(this.bucketName);
if (!bucketExists) {
await this.client.makeBucket(this.bucketName, 'us-east-1');
// Set the bucket policy to allow public read access
const policy = {
Version: '2012-10-17',
Statement: [
{
Effect: 'Allow',
Principal: { AWS: ['*'] },
Action: ['s3:GetObject'],
Resource: [`arn:aws:s3:::${this.bucketName}/*`],
},
],
};
await this.client.setBucketPolicy(
this.bucketName,
JSON.stringify(policy)
);
}
this.initialized = true;
}
/**
* Generates a presigned URL for uploading a file
* @param objectName - Name of the object to upload
* @param expiryInSeconds - Expiry time in seconds (default: 1 hour)
* @returns Presigned URL for uploading
*/
public async generateUploadUrl(
objectName: string,
expiryInSeconds: number = this.defaultExpiry
): Promise<string> {
return this.client.presignedPutObject(
this.bucketName,
objectName,
expiryInSeconds
);
}
/**
* Generates a presigned URL for downloading a file
* @param objectName - Name of the object to download
* @param expiryInSeconds - Expiry time in seconds (default: 1 hour)
* @returns Presigned URL for downloading
*/
public async generateDownloadUrl(
objectName: string,
expiryInSeconds: number = this.defaultExpiry
): Promise<string> {
return this.client.presignedGetObject(
this.bucketName,
objectName,
expiryInSeconds
);
}
/**
* Checks if an object exists in the bucket
* @param objectName - Name of the object to check
* @returns True if the object exists, false otherwise
*/
public async objectExists(objectName: string): Promise<boolean> {
try {
await this.client.statObject(this.bucketName, objectName);
return true;
} catch (error) {
return false;
}
}
/**
* Deletes an object from the bucket
* @param objectName - Name of the object to delete
*/
public async deleteObject(objectName: string): Promise<void> {
await this.client.removeObject(this.bucketName, objectName);
}
}