Initial commit: Telegram Management System
Some checks failed
Deploy / deploy (push) Has been cancelled
Some checks failed
Deploy / deploy (push) Has been cancelled
Full-stack web application for Telegram management - Frontend: Vue 3 + Vben Admin - Backend: NestJS - Features: User management, group broadcast, statistics 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
import { jest } from '@jest/globals';
|
||||
import { authenticate, generateToken, generateRefreshToken } from '../../../../../services/api-gateway/src/middleware/auth.js';
|
||||
import jwt from 'jsonwebtoken';
|
||||
|
||||
// Mock dependencies
|
||||
jest.mock('jsonwebtoken');
|
||||
jest.mock('../../../../../services/api-gateway/src/utils/cache.js', () => ({
|
||||
cache: {
|
||||
get: jest.fn(),
|
||||
set: jest.fn(),
|
||||
del: jest.fn()
|
||||
}
|
||||
}));
|
||||
|
||||
describe('Auth Middleware', () => {
|
||||
let req, res, next;
|
||||
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
headers: {},
|
||||
user: null
|
||||
};
|
||||
res = {
|
||||
status: jest.fn(() => res),
|
||||
json: jest.fn(() => res)
|
||||
};
|
||||
next = jest.fn();
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('authenticate', () => {
|
||||
it('should authenticate valid token', async () => {
|
||||
const token = 'valid-token';
|
||||
const decodedToken = {
|
||||
userId: 'user123',
|
||||
role: 'user',
|
||||
permissions: ['read', 'write']
|
||||
};
|
||||
|
||||
req.headers.authorization = `Bearer ${token}`;
|
||||
jwt.verify.mockReturnValue(decodedToken);
|
||||
|
||||
await authenticate(req, res, next);
|
||||
|
||||
expect(jwt.verify).toHaveBeenCalledWith(token, process.env.JWT_SECRET);
|
||||
expect(req.user).toEqual(decodedToken);
|
||||
expect(req.token).toBe(token);
|
||||
expect(next).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should reject missing authorization header', async () => {
|
||||
await authenticate(req, res, next);
|
||||
|
||||
expect(res.status).toHaveBeenCalledWith(401);
|
||||
expect(res.json).toHaveBeenCalledWith({
|
||||
success: false,
|
||||
error: 'No token provided'
|
||||
});
|
||||
expect(next).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should reject invalid token format', async () => {
|
||||
req.headers.authorization = 'InvalidFormat token';
|
||||
|
||||
await authenticate(req, res, next);
|
||||
|
||||
expect(res.status).toHaveBeenCalledWith(401);
|
||||
expect(res.json).toHaveBeenCalledWith({
|
||||
success: false,
|
||||
error: 'Invalid token format'
|
||||
});
|
||||
});
|
||||
|
||||
it('should reject expired token', async () => {
|
||||
req.headers.authorization = 'Bearer expired-token';
|
||||
jwt.verify.mockImplementation(() => {
|
||||
throw new Error('jwt expired');
|
||||
});
|
||||
|
||||
await authenticate(req, res, next);
|
||||
|
||||
expect(res.status).toHaveBeenCalledWith(401);
|
||||
expect(res.json).toHaveBeenCalledWith({
|
||||
success: false,
|
||||
error: 'Token expired'
|
||||
});
|
||||
});
|
||||
|
||||
it('should reject blacklisted token', async () => {
|
||||
const token = 'blacklisted-token';
|
||||
req.headers.authorization = `Bearer ${token}`;
|
||||
|
||||
const { cache } = require('../../../../../services/api-gateway/src/utils/cache.js');
|
||||
cache.get.mockResolvedValue('1');
|
||||
|
||||
await authenticate(req, res, next);
|
||||
|
||||
expect(cache.get).toHaveBeenCalledWith(`blacklist:${token}`);
|
||||
expect(res.status).toHaveBeenCalledWith(401);
|
||||
expect(res.json).toHaveBeenCalledWith({
|
||||
success: false,
|
||||
error: 'Token has been revoked'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('generateToken', () => {
|
||||
it('should generate access token with correct payload', () => {
|
||||
const payload = {
|
||||
userId: 'user123',
|
||||
role: 'admin',
|
||||
permissions: ['all']
|
||||
};
|
||||
const expectedToken = 'generated-token';
|
||||
|
||||
jwt.sign.mockReturnValue(expectedToken);
|
||||
|
||||
const token = generateToken(payload);
|
||||
|
||||
expect(jwt.sign).toHaveBeenCalledWith(
|
||||
payload,
|
||||
process.env.JWT_SECRET,
|
||||
{ expiresIn: '24h' }
|
||||
);
|
||||
expect(token).toBe(expectedToken);
|
||||
});
|
||||
});
|
||||
|
||||
describe('generateRefreshToken', () => {
|
||||
it('should generate refresh token with correct payload', () => {
|
||||
const payload = {
|
||||
userId: 'user123',
|
||||
role: 'user'
|
||||
};
|
||||
const expectedToken = 'refresh-token';
|
||||
|
||||
jwt.sign.mockReturnValue(expectedToken);
|
||||
|
||||
const token = generateRefreshToken(payload);
|
||||
|
||||
expect(jwt.sign).toHaveBeenCalledWith(
|
||||
payload,
|
||||
process.env.JWT_SECRET,
|
||||
{ expiresIn: '7d' }
|
||||
);
|
||||
expect(token).toBe(expectedToken);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,86 @@
|
||||
import { jest } from '@jest/globals';
|
||||
import { globalRateLimiter, strictRateLimiter, dynamicRateLimiter } from '../../../../../services/api-gateway/src/middleware/rateLimiter.js';
|
||||
|
||||
// Mock Redis store
|
||||
jest.mock('rate-limit-redis', () => ({
|
||||
default: jest.fn(() => ({
|
||||
increment: jest.fn(),
|
||||
decrement: jest.fn(),
|
||||
resetKey: jest.fn()
|
||||
}))
|
||||
}));
|
||||
|
||||
describe('Rate Limiter Middleware', () => {
|
||||
let req, res, next;
|
||||
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
ip: '127.0.0.1',
|
||||
user: { id: 'user123', role: 'user' },
|
||||
path: '/api/v1/test'
|
||||
};
|
||||
res = {
|
||||
status: jest.fn(() => res),
|
||||
json: jest.fn(() => res),
|
||||
set: jest.fn(() => res)
|
||||
};
|
||||
next = jest.fn();
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('globalRateLimiter', () => {
|
||||
it('should allow request within rate limit', async () => {
|
||||
// Mock the rate limiter to allow the request
|
||||
const middleware = globalRateLimiter;
|
||||
|
||||
// Since globalRateLimiter is created by express-rate-limit,
|
||||
// we need to test its configuration
|
||||
expect(middleware).toBeDefined();
|
||||
expect(typeof middleware).toBe('function');
|
||||
});
|
||||
|
||||
it('should set rate limit headers', async () => {
|
||||
// Test that rate limit headers are set correctly
|
||||
res.setHeader = jest.fn();
|
||||
|
||||
// Mock a successful request
|
||||
const mockRateLimitInfo = {
|
||||
limit: 100,
|
||||
current: 25,
|
||||
remaining: 75,
|
||||
resetTime: new Date(Date.now() + 60000)
|
||||
};
|
||||
|
||||
// Test headers would be set by the middleware
|
||||
expect(res.setHeader).not.toHaveBeenCalled(); // Initially not called
|
||||
});
|
||||
});
|
||||
|
||||
describe('strictRateLimiter', () => {
|
||||
it('should have stricter limits than global', () => {
|
||||
expect(strictRateLimiter).toBeDefined();
|
||||
expect(typeof strictRateLimiter).toBe('function');
|
||||
});
|
||||
});
|
||||
|
||||
describe('dynamicRateLimiter', () => {
|
||||
it('should apply different limits based on user role', async () => {
|
||||
// Test for admin user
|
||||
req.user.role = 'admin';
|
||||
expect(dynamicRateLimiter).toBeDefined();
|
||||
|
||||
// Test for regular user
|
||||
req.user.role = 'user';
|
||||
expect(dynamicRateLimiter).toBeDefined();
|
||||
|
||||
// Test for viewer
|
||||
req.user.role = 'viewer';
|
||||
expect(dynamicRateLimiter).toBeDefined();
|
||||
});
|
||||
|
||||
it('should apply default limits for unauthenticated users', async () => {
|
||||
req.user = null;
|
||||
expect(dynamicRateLimiter).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user