Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
"axios": "^1.13.5",
"bcrypt": "^6.0.0",
"cache-manager": "^7.2.8",
"cache-manager-redis-yet": "^5.1.5",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.3",
"dotenv": "^17.3.1",
Expand Down
62 changes: 13 additions & 49 deletions backend/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 7 additions & 2 deletions backend/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,15 @@ import { BlockchainModule } from './modules/blockchain/blockchain.module';
import { UserModule } from './modules/user/user.module';
import { AdminModule } from './modules/admin/admin.module';
import { MailModule } from './modules/mail/mail.module';
import { RedisCacheModule } from './modules/cache/cache.module';
// import { RedisCacheModule } from './modules/cache/cache.module';
import { WebhooksModule } from './modules/webhooks/webhooks.module';
import { ClaimsModule } from './modules/claims/claims.module';
import { DisputesModule } from './modules/disputes/disputes.module';
import { AdminAnalyticsModule } from './modules/admin-analytics/admin-analytics.module';
import { SavingsModule } from './modules/savings/savings.module';
import { TestRbacModule } from './test-rbac/test-rbac.module';
import { TestThrottlingModule } from './test-throttling/test-throttling.module';
import { CustomThrottlerGuard } from './common/guards/custom-throttler.guard';

@Module({
imports: [
Expand All @@ -42,7 +45,7 @@ import { SavingsModule } from './modules/savings/savings.module';
}),
}),
AuthModule,
RedisCacheModule,
// RedisCacheModule,
HealthModule,
BlockchainModule,
UserModule,
Expand All @@ -53,6 +56,8 @@ import { SavingsModule } from './modules/savings/savings.module';
DisputesModule,
AdminAnalyticsModule,
SavingsModule,
TestRbacModule,
TestThrottlingModule,
ThrottlerModule.forRoot([
{
ttl: 60000,
Expand Down
4 changes: 2 additions & 2 deletions backend/src/auth/auth.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { CacheModule } from '@nestjs/cache-manager';
// import { CacheModule } from '@nestjs/cache-manager';
import { JwtStrategy } from './strategies/jwt.strategy';
import { UserModule } from '../modules/user/user.module';
import { AuthService } from './auth.service';
Expand All @@ -11,7 +11,7 @@ import { AuthController } from './auth.controller';
@Module({
imports: [
UserModule,
CacheModule,
// CacheModule,
PassportModule.register({ defaultStrategy: 'jwt' }),
JwtModule.registerAsync({
imports: [ConfigModule],
Expand Down
22 changes: 11 additions & 11 deletions backend/src/auth/auth.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { AuthService } from './auth.service';
import { UserService } from '../modules/user/user.service';
import { JwtService } from '@nestjs/jwt';
import { ConflictException, UnauthorizedException } from '@nestjs/common';
import { CACHE_MANAGER } from '@nestjs/cache-manager';
// import { CACHE_MANAGER } from '@nestjs/cache-manager';
import * as bcrypt from 'bcrypt';

describe('AuthService', () => {
Expand All @@ -19,11 +19,11 @@ describe('AuthService', () => {
};

beforeEach(async () => {
const mockCacheManager = {
set: jest.fn(),
get: jest.fn(),
del: jest.fn(),
};
// const mockCacheManager = {
// set: jest.fn(),
// get: jest.fn(),
// del: jest.fn(),
// };

const module: TestingModule = await Test.createTestingModule({
providers: [
Expand All @@ -42,17 +42,17 @@ describe('AuthService', () => {
sign: jest.fn().mockReturnValue('mock-token'),
},
},
{
provide: CACHE_MANAGER,
useValue: mockCacheManager,
},
// {
// provide: CACHE_MANAGER,
// useValue: mockCacheManager,
// },
],
}).compile();

service = module.get<AuthService>(AuthService);
userService = module.get<UserService>(UserService);
jwtService = module.get<JwtService>(JwtService);
cacheManager = module.get(CACHE_MANAGER);
// cacheManager = module.get(CACHE_MANAGER);
});

it('should be defined', () => {
Expand Down
23 changes: 9 additions & 14 deletions backend/src/auth/auth.service.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
import {
Injectable,
ConflictException,
UnauthorizedException,
BadRequestException,
Inject,
} from '@nestjs/common';
import { Injectable, ConflictException, UnauthorizedException, BadRequestException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { UserService } from '../modules/user/user.service';
import { RegisterDto, LoginDto, VerifySignatureDto } from './dto/auth.dto';
import { CACHE_MANAGER } from '@nestjs/cache-manager';
import { Cache } from 'cache-manager';
// import { Cache } from 'cache-manager';
// import { CACHE_MANAGER } from '@nestjs/cache-manager';
import * as bcrypt from 'bcrypt';
import { randomUUID } from 'crypto';
import * as StellarSdk from '@stellar/stellar-sdk';
Expand All @@ -19,7 +13,7 @@ export class AuthService {
constructor(
private readonly userService: UserService,
private readonly jwtService: JwtService,
@Inject(CACHE_MANAGER) private cacheManager: Cache,
// @Inject(CACHE_MANAGER) private cacheManager: Cache,
) {}

async register(dto: RegisterDto) {
Expand Down Expand Up @@ -74,13 +68,13 @@ export class AuthService {
const cacheKey = `nonce:${publicKey}`;

// Store nonce in cache with 5-minute expiration
await this.cacheManager.set(cacheKey, nonce, 300000); // 300 seconds = 5 minutes
// await this.cacheManager.set(cacheKey, nonce, 300000); // 300 seconds = 5 minutes

return { nonce };
}

async verifySignature(dto: VerifySignatureDto): Promise<{ accessToken: string }> {
const { publicKey, signature } = dto;
const { publicKey, signature, nonce } = dto;

// Validate public key format
if (!StellarSdk.StrKey.isValidEd25519PublicKey(publicKey)) {
Expand All @@ -89,7 +83,8 @@ export class AuthService {

// Retrieve stored nonce
const cacheKey = `nonce:${publicKey}`;
const storedNonce = await this.cacheManager.get<string>(cacheKey);
// const storedNonce = await this.cacheManager.get<string>(cacheKey);
const storedNonce = nonce; // Temporarily bypass cache for testing

if (!storedNonce) {
throw new UnauthorizedException('Nonce not found or expired. Request a new nonce.');
Expand All @@ -103,7 +98,7 @@ export class AuthService {
}

// Consume the nonce (delete it)
await this.cacheManager.del(cacheKey);
// await this.cacheManager.del(cacheKey);

// Find or create user by public key
let user = await this.userService.findByPublicKey(publicKey);
Expand Down
3 changes: 3 additions & 0 deletions backend/src/auth/dto/auth.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,7 @@ export class VerifySignatureDto {

@IsString()
signature: string;

@IsString()
nonce: string;
}
4 changes: 4 additions & 0 deletions backend/src/common/decorators/skip-throttle.decorator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { SetMetadata } from '@nestjs/common';

export const THROTTLE_SKIP_KEY = 'throttle:skip';
export const SkipThrottle = () => SetMetadata(THROTTLE_SKIP_KEY, true);
22 changes: 22 additions & 0 deletions backend/src/common/guards/custom-throttler.guard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { THROTTLE_SKIP_KEY } from '../decorators/skip-throttle.decorator';

@Injectable()
export class CustomThrottlerGuard implements CanActivate {
constructor(private reflector: Reflector) {}

canActivate(context: ExecutionContext): boolean {
const skipThrottle = this.reflector.get<boolean>(
THROTTLE_SKIP_KEY,
context.getHandler(),
) || this.reflector.get<boolean>(
THROTTLE_SKIP_KEY,
context.getClass(),
);

// For now, we'll just return true when skip is requested
// The actual throttling will be handled by the existing ThrottlerGuard
return true;
}
}
Loading