Fix jwt-token

This commit is contained in:
2025-09-14 21:07:43 +02:00
parent d6293dd8ba
commit 019eb8c2b2
20 changed files with 7185 additions and 29 deletions

View File

@@ -0,0 +1,389 @@
const { describe, it, beforeEach, afterEach, before, after } = require('mocha');
const { expect } = require('chai');
const sinon = require('sinon');
const request = require('supertest');
const express = require('express');
const authRoutes = require('../../routes/auth');
const { setupTestEnvironment, teardownTestEnvironment, cleanDatabase, createTestUser, createTestTenant, generateTestToken } = require('../setup');
describe('Auth Routes', () => {
let app, models, sequelize;
before(async () => {
({ models, sequelize } = await setupTestEnvironment());
// Setup express app for testing
app = express();
app.use(express.json());
app.use('/auth', authRoutes);
});
after(async () => {
await teardownTestEnvironment();
});
beforeEach(async () => {
await cleanDatabase();
});
describe('POST /auth/login', () => {
it('should login with valid credentials', async () => {
const tenant = await createTestTenant({ slug: 'test-tenant' });
const user = await createTestUser({
username: 'testuser',
password: '$2b$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
tenant_id: tenant.id
});
const response = await request(app)
.post('/auth/login')
.send({
username: 'testuser',
password: 'password'
});
expect(response.status).to.equal(200);
expect(response.body.success).to.be.true;
expect(response.body.data.token).to.exist;
expect(response.body.data.user.username).to.equal('testuser');
});
it('should reject invalid username', async () => {
const response = await request(app)
.post('/auth/login')
.send({
username: 'nonexistent',
password: 'password'
});
expect(response.status).to.equal(401);
expect(response.body.success).to.be.false;
expect(response.body.message).to.equal('Invalid credentials');
});
it('should reject invalid password', async () => {
const user = await createTestUser({
username: 'testuser',
password: '$2b$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi'
});
const response = await request(app)
.post('/auth/login')
.send({
username: 'testuser',
password: 'wrongpassword'
});
expect(response.status).to.equal(401);
expect(response.body.success).to.be.false;
});
it('should reject inactive user', async () => {
const user = await createTestUser({
username: 'inactive',
password: '$2b$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi',
is_active: false
});
const response = await request(app)
.post('/auth/login')
.send({
username: 'inactive',
password: 'password'
});
expect(response.status).to.equal(401);
expect(response.body.success).to.be.false;
expect(response.body.message).to.equal('Account is inactive');
});
it('should include tenant information in JWT token', async () => {
const tenant = await createTestTenant({ slug: 'test-tenant' });
const user = await createTestUser({
username: 'testuser',
password: '$2b$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi',
tenant_id: tenant.id
});
const response = await request(app)
.post('/auth/login')
.send({
username: 'testuser',
password: 'password'
});
expect(response.status).to.equal(200);
const jwt = require('jsonwebtoken');
const decoded = jwt.verify(response.body.data.token, process.env.JWT_SECRET || 'test-secret');
expect(decoded.tenantId).to.equal(tenant.slug);
});
it('should validate required fields', async () => {
const response = await request(app)
.post('/auth/login')
.send({
username: 'testuser'
// missing password
});
expect(response.status).to.equal(400);
expect(response.body.success).to.be.false;
});
it('should handle database errors gracefully', async () => {
// Mock database error
const originalFindOne = models.User.findOne;
models.User.findOne = sinon.stub().rejects(new Error('Database error'));
const response = await request(app)
.post('/auth/login')
.send({
username: 'testuser',
password: 'password'
});
expect(response.status).to.equal(500);
expect(response.body.success).to.be.false;
// Restore original method
models.User.findOne = originalFindOne;
});
});
describe('POST /auth/register', () => {
it('should register new user when registration allowed', async () => {
const tenant = await createTestTenant({
slug: 'test-tenant',
allow_registration: true
});
const response = await request(app)
.post('/auth/register')
.set('Host', 'test-tenant.example.com')
.send({
username: 'newuser',
email: 'new@example.com',
password: 'password123',
firstName: 'New',
lastName: 'User'
});
expect(response.status).to.equal(201);
expect(response.body.success).to.be.true;
expect(response.body.data.user.username).to.equal('newuser');
});
it('should reject registration when not allowed', async () => {
const tenant = await createTestTenant({
slug: 'test-tenant',
allow_registration: false
});
const response = await request(app)
.post('/auth/register')
.set('Host', 'test-tenant.example.com')
.send({
username: 'newuser',
email: 'new@example.com',
password: 'password123'
});
expect(response.status).to.equal(403);
expect(response.body.success).to.be.false;
expect(response.body.message).to.include('Registration not allowed');
});
it('should reject duplicate username', async () => {
const tenant = await createTestTenant({
slug: 'test-tenant',
allow_registration: true
});
await createTestUser({
username: 'existing',
tenant_id: tenant.id
});
const response = await request(app)
.post('/auth/register')
.set('Host', 'test-tenant.example.com')
.send({
username: 'existing',
email: 'new@example.com',
password: 'password123'
});
expect(response.status).to.equal(400);
expect(response.body.success).to.be.false;
expect(response.body.message).to.include('already exists');
});
it('should reject duplicate email', async () => {
const tenant = await createTestTenant({
slug: 'test-tenant',
allow_registration: true
});
await createTestUser({
username: 'existing',
email: 'existing@example.com',
tenant_id: tenant.id
});
const response = await request(app)
.post('/auth/register')
.set('Host', 'test-tenant.example.com')
.send({
username: 'newuser',
email: 'existing@example.com',
password: 'password123'
});
expect(response.status).to.equal(400);
expect(response.body.success).to.be.false;
});
it('should validate password strength', async () => {
const tenant = await createTestTenant({
slug: 'test-tenant',
allow_registration: true
});
const response = await request(app)
.post('/auth/register')
.set('Host', 'test-tenant.example.com')
.send({
username: 'newuser',
email: 'new@example.com',
password: '123' // weak password
});
expect(response.status).to.equal(400);
expect(response.body.success).to.be.false;
expect(response.body.message).to.include('password');
});
it('should validate email format', async () => {
const tenant = await createTestTenant({
slug: 'test-tenant',
allow_registration: true
});
const response = await request(app)
.post('/auth/register')
.set('Host', 'test-tenant.example.com')
.send({
username: 'newuser',
email: 'invalid-email',
password: 'password123'
});
expect(response.status).to.equal(400);
expect(response.body.success).to.be.false;
});
it('should enforce IP restrictions during registration', async () => {
const tenant = await createTestTenant({
slug: 'test-tenant',
allow_registration: true,
ip_restrictions_enabled: true,
allowed_ips: '192.168.1.1'
});
const response = await request(app)
.post('/auth/register')
.set('Host', 'test-tenant.example.com')
.set('X-Forwarded-For', '192.168.2.1') // Not allowed IP
.send({
username: 'newuser',
email: 'new@example.com',
password: 'password123'
});
expect(response.status).to.equal(403);
expect(response.body.success).to.be.false;
expect(response.body.message).to.include('IP address not allowed');
});
});
describe('POST /auth/refresh', () => {
it('should refresh valid token', async () => {
const user = await createTestUser();
const token = generateTestToken(user);
const response = await request(app)
.post('/auth/refresh')
.set('Authorization', `Bearer ${token}`);
expect(response.status).to.equal(200);
expect(response.body.success).to.be.true;
expect(response.body.data.token).to.exist;
expect(response.body.data.token).to.not.equal(token); // New token
});
it('should reject refresh without token', async () => {
const response = await request(app)
.post('/auth/refresh');
expect(response.status).to.equal(401);
expect(response.body.success).to.be.false;
});
it('should reject refresh with invalid token', async () => {
const response = await request(app)
.post('/auth/refresh')
.set('Authorization', 'Bearer invalid.token');
expect(response.status).to.equal(401);
expect(response.body.success).to.be.false;
});
});
describe('POST /auth/logout', () => {
it('should logout successfully', async () => {
const user = await createTestUser();
const token = generateTestToken(user);
const response = await request(app)
.post('/auth/logout')
.set('Authorization', `Bearer ${token}`);
expect(response.status).to.equal(200);
expect(response.body.success).to.be.true;
expect(response.body.message).to.equal('Logged out successfully');
});
it('should logout without token', async () => {
const response = await request(app)
.post('/auth/logout');
expect(response.status).to.equal(200);
expect(response.body.success).to.be.true;
});
});
describe('GET /auth/me', () => {
it('should return current user info', async () => {
const tenant = await createTestTenant();
const user = await createTestUser({ tenant_id: tenant.id });
const token = generateTestToken(user, tenant);
const response = await request(app)
.get('/auth/me')
.set('Authorization', `Bearer ${token}`);
expect(response.status).to.equal(200);
expect(response.body.success).to.be.true;
expect(response.body.data.username).to.equal(user.username);
expect(response.body.data.email).to.equal(user.email);
});
it('should require authentication', async () => {
const response = await request(app)
.get('/auth/me');
expect(response.status).to.equal(401);
expect(response.body.success).to.be.false;
});
});
});