UNPKG

@sync-in/server

Version:

The secure, open-source platform for file storage, sharing, collaboration, and sync

341 lines (340 loc) 12.5 kB
/* * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com> * This file is part of Sync-in | The open source file sync and share solution * See the LICENSE file for licensing details */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const _config = require("@nestjs/config"); const _jwt = require("@nestjs/jwt"); const _appbootstrap = require("../app.bootstrap"); const _user = require("../applications/users/constants/user"); const _usermodel = require("../applications/users/models/user.model"); const _adminusersmanagerservice = require("../applications/users/services/admin-users-manager.service"); const _test = require("../applications/users/utils/test"); const _functions = require("../common/functions"); const _shared = require("../common/shared"); const _utils = require("../infrastructure/database/utils"); const _auth = require("./constants/auth"); const _routes = require("./constants/routes"); const _tokenresponsedto = require("./dto/token-response.dto"); const _tokeninterface = require("./interfaces/token.interface"); describe('Auth (e2e)', ()=>{ let app; let authConfig; let jwtService; let adminUsersManager; let userTest; let refreshToken; let csrfToken; beforeAll(async ()=>{ app = await (0, _appbootstrap.appBootstrap)(); await app.init(); await app.getHttpAdapter().getInstance().ready(); authConfig = app.get(_config.ConfigService).get('auth'); jwtService = app.get(_jwt.JwtService); adminUsersManager = app.get(_adminusersmanagerservice.AdminUsersManager); userTest = new _usermodel.UserModel((0, _test.generateUserTest)(false), false); }); afterAll(async ()=>{ await expect(adminUsersManager.deleteUserOrGuest(userTest.id, userTest.login, { deleteSpace: true, isGuest: false })).resolves.not.toThrow(); await (0, _utils.dbCloseConnection)(app); await app.close(); }); it('should be defined', ()=>{ expect(authConfig).toBeDefined(); expect(jwtService).toBeDefined(); expect(adminUsersManager).toBeDefined(); expect(userTest).toBeDefined(); }); it('should get the database connection', async ()=>{ expect(await (0, _utils.dbCheckConnection)(app)).toBe(true); }); it(`POST ${_routes.API_AUTH_LOGIN} => 401`, async ()=>{ const res = await app.inject({ method: 'POST', url: _routes.API_AUTH_LOGIN, body: { login: userTest.login, password: userTest.password } }); expect(res.statusCode).toEqual(401); }); it(`POST ${_routes.API_AUTH_LOGIN} => 201`, async ()=>{ const userId = (await adminUsersManager.createUserOrGuest({ ...userTest }, _user.USER_ROLE.USER)).id; expect(userId).toBeDefined(); userTest.id = userId; const res = await app.inject({ method: 'POST', url: _routes.API_AUTH_LOGIN, body: { login: userTest.login, password: userTest.password } }); expect(res.statusCode).toEqual(201); expect(Object.keys(res.json())).toEqual(expect.arrayContaining([ 'user', 'token' ])); expect(res.headers['set-cookie']).toHaveLength(4); const cookies = getCookies(res.headers['set-cookie']); /* Access cookie [ 'sync-in-access=value, 'Max-Age=3600', 'Path=/', 'HttpOnly', 'Secure', 'SameSite=Strict' ] */ /* Refresh cookie [ 'sync-in-refresh=value, 'Max-Age=14400', 'Path=/api/auth/refresh', 'HttpOnly', 'Secure', 'SameSite=Strict' ] */ /* WS cookie [ 'sync-in-ws=value, 'Max-Age=14400', 'Path=/socket.io', 'HttpOnly', 'Secure', 'SameSite=Strict' ] */ /* CSRF cookie [ 'sync-in-csrf=value, 'Max-Age=14400', 'Path=/', 'Secure', 'SameSite=Strict' ] */ cookiesChecks(cookies); // Verify token for (const cookie of cookies){ const token = cookie.content[0].substring(cookie.content[0].indexOf('=') + 1); if (cookie.type === _tokeninterface.TOKEN_TYPE.CSRF) { // needed for the following tests csrfToken = (0, _shared.decodeUrl)(token); continue; } const decodedToken = await jwtService.verifyAsync(token, { secret: authConfig.token[cookie.type].secret }); expect(decodedToken.iat).toBeCloseTo((0, _shared.currentTimeStamp)(), -1); expect(decodedToken.exp).toBeCloseTo((0, _shared.currentTimeStamp)() + (0, _functions.convertHumanTimeToSeconds)(authConfig.token[cookie.type].expiration), -1); expect(decodedToken.identity.id).toBe(userTest.id); if (cookie.type === _tokeninterface.TOKEN_TYPE.REFRESH) { // needed for the following tests refreshToken = token; } } }); it(`POST ${_routes.API_AUTH_LOGOUT} => 201`, async ()=>{ const res = await app.inject({ method: 'POST', url: _routes.API_AUTH_LOGOUT, body: null }); expect(res.statusCode).toEqual(201); expect(res.headers['set-cookie']).toHaveLength(4); const cookies = getCookies(res.headers['set-cookie']); /* Access cookie [ 'sync-in-access=', 'Max-Age=0', 'Path=/', 'Expires=Thu, 01 Jan 1970 00:00:00 GMT', 'HttpOnly', 'Secure', 'SameSite=Strict' ] */ /* Refresh cookie [ 'sync-in-refresh=', 'Max-Age=0', 'Path=/api/auth/refresh', 'Expires=Thu, 01 Jan 1970 00:00:00 GMT', 'HttpOnly', 'Secure', 'SameSite=Strict' ] */ /* WS cookie [ 'sync-in-ws=', 'Max-Age=0', 'Path=/socket.io', 'Expires=Thu, 01 Jan 1970 00:00:00 GMT', 'HttpOnly', 'Secure', 'SameSite=Strict' ] */ /* CSRF cookie [ 'sync-in-csrf=', 'Max-Age=0', 'Path=/api/auth/refresh', 'Expires=Thu, 01 Jan 1970 00:00:00 GMT', 'HttpOnly', 'Secure', 'SameSite=Strict' ] */ cookiesChecks(cookies, true); }); it(`POST ${_routes.API_AUTH_REFRESH} => 201`, async ()=>{ const res = await app.inject({ method: 'POST', headers: { [authConfig.token.csrf.name]: csrfToken }, url: _routes.API_AUTH_REFRESH, cookies: { [authConfig.token.refresh.name]: refreshToken } }); expect(res.statusCode).toEqual(201); const cookies = getCookies(res.headers['set-cookie']); cookiesChecks(cookies); }); it(`POST ${_routes.API_AUTH_REFRESH} => 401 (with CSRF)`, async ()=>{ const res = await app.inject({ method: 'POST', url: _routes.API_AUTH_REFRESH, headers: { [authConfig.token.csrf.name]: csrfToken }, cookies: { [authConfig.token.refresh.name]: 'bar' } }); expect(res.statusCode).toEqual(401); }); it(`POST ${_routes.API_AUTH_REFRESH} => 403 (without CSRF)`, async ()=>{ const res = await app.inject({ method: 'POST', url: _routes.API_AUTH_REFRESH, cookies: { [authConfig.token.refresh.name]: refreshToken } }); expect(res.statusCode).toEqual(403); expect(res.json().message).toEqual(_auth.CSRF_ERROR.MISSING_HEADERS); }); it(`POST ${_routes.API_AUTH_TOKEN} => 401`, async ()=>{ const res = await app.inject({ method: 'POST', url: _routes.API_AUTH_TOKEN, body: { login: userTest.login, password: 'bar' } }); expect(res.statusCode).toEqual(401); }); it(`POST ${_routes.API_AUTH_TOKEN} => 201`, async ()=>{ const res = await app.inject({ method: 'POST', url: _routes.API_AUTH_TOKEN, body: { login: userTest.login, password: userTest.password } }); expect(res.statusCode).toEqual(201); const content = res.json(); expect(()=>(0, _functions.transformAndValidate)(_tokenresponsedto.TokenResponseDto, content)).not.toThrow(); for (const type of _auth.TOKEN_TYPES.filter((p)=>p === _tokeninterface.TOKEN_TYPE.ACCESS || p === _tokeninterface.TOKEN_TYPE.REFRESH)){ expect(content[type]).toBeDefined(); expect(content[`${type}_expiration`]).toBeCloseTo((0, _shared.currentTimeStamp)() + (0, _functions.convertHumanTimeToSeconds)(authConfig.token[type].expiration), -1); } }); it(`POST ${_routes.API_AUTH_TOKEN_REFRESH} => 401`, async ()=>{ const res = await app.inject({ method: 'POST', url: _routes.API_AUTH_TOKEN_REFRESH, headers: { authorization: 'Bearer bar' } }); expect(res.statusCode).toEqual(401); }); it(`POST ${_routes.API_AUTH_TOKEN_REFRESH} => 201`, async ()=>{ const res = await app.inject({ method: 'POST', url: _routes.API_AUTH_TOKEN_REFRESH, headers: { authorization: `Bearer ${refreshToken}` } }); expect(res.statusCode).toEqual(201); expect(()=>(0, _functions.transformAndValidate)(_tokenresponsedto.TokenResponseDto, res.json())).not.toThrow(); }); function getCookies(setCookie) { const cookies = []; for (const c of setCookie){ const cookieName = c.split('=')[0]; const cookieValues = c.split('; '); switch(cookieName){ case authConfig.token.access.name: cookies.push({ type: _tokeninterface.TOKEN_TYPE.ACCESS, content: cookieValues }); break; case authConfig.token.refresh.name: cookies.push({ type: _tokeninterface.TOKEN_TYPE.REFRESH, content: cookieValues }); break; case authConfig.token.ws.name: cookies.push({ type: _tokeninterface.TOKEN_TYPE.WS, content: cookieValues }); break; case authConfig.token.csrf.name: cookies.push({ type: _tokeninterface.TOKEN_TYPE.CSRF, content: cookieValues }); break; } } return cookies; } function cookiesChecks(cookies, clear = false) { for (const cookie of cookies){ expect(cookie.content[0].split('=')[0]).toBe(authConfig.token[cookie.type].name); expect(cookie.content[2].split('=')[1]).toBe(_auth.TOKEN_PATHS[cookie.type]); if (cookie.type === _tokeninterface.TOKEN_TYPE.CSRF) { expect(cookie.content).not.toContain('HttpOnly'); } else { expect(cookie.content).toContain('HttpOnly'); } expect(cookie.content).not.toContain('Secure'); expect(cookie.content[cookie.content.length - 1].split('=')[1].toLowerCase()).toBe(authConfig.cookieSameSite); if (clear) { expect(cookie.content[0].split('=')[1]).toBe(''); expect(cookie.content[1].split('=')[1]).toBe('0'); expect(cookie.content[3].split('=')[1]).toBe('Thu, 01 Jan 1970 00:00:00 GMT'); } else { expect(parseInt(cookie.content[1].split('=')[1])).toBeCloseTo((0, _functions.convertHumanTimeToSeconds)(authConfig.token[cookie.type].expiration), -1); expect(cookie.content[0].split('=')[1]).not.toBe(''); } } } }); //# sourceMappingURL=auth.e2e-spec.js.map