From 883736636b6a6c2647b038a829fd456d00a6cabe Mon Sep 17 00:00:00 2001 From: Faruk AYDIN Date: Wed, 16 Apr 2025 11:09:39 +0200 Subject: [PATCH 1/2] feat: Implement authentication for API tokens --- .../backend/src/helpers/authentication.js | 27 +++++++++++++++++++ .../src/helpers/authentication.test.js | 22 ++++++++++++++- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/packages/backend/src/helpers/authentication.js b/packages/backend/src/helpers/authentication.js index cfbb20d4..26851600 100644 --- a/packages/backend/src/helpers/authentication.js +++ b/packages/backend/src/helpers/authentication.js @@ -1,5 +1,6 @@ import User from '../models/user.js'; import AccessToken from '../models/access-token.js'; +import ApiToken from '../models/api-token.ee.js'; export const isAuthenticated = async (req) => { const token = req.headers['authorization']; @@ -46,3 +47,29 @@ export const authenticateUser = async (request, response, next) => { return response.status(401).end(); } }; + +export const isApiTokenAuthenticated = async (request) => { + const token = request.headers['x-api-token']; + + if (token == null) return false; + + try { + const apiToken = await ApiToken.query().findOne({ + token, + }); + + if (apiToken == null) return false; + + return true; + } catch (error) { + return false; + } +}; + +export const authenticateApiToken = async (request, response, next) => { + if (await isApiTokenAuthenticated(request)) { + next(); + } else { + return response.status(401).end(); + } +}; diff --git a/packages/backend/src/helpers/authentication.test.js b/packages/backend/src/helpers/authentication.test.js index 1b5f1620..024145c6 100644 --- a/packages/backend/src/helpers/authentication.test.js +++ b/packages/backend/src/helpers/authentication.test.js @@ -1,6 +1,7 @@ import { describe, it, expect } from 'vitest'; -import { isAuthenticated } from './authentication.js'; +import { isAuthenticated, isApiTokenAuthenticated } from './authentication.js'; import { createUser } from '../../test/factories/user.js'; +import { createApiToken } from '../../test/factories/api-token.js'; import createAuthTokenByUserId from '../helpers/create-auth-token-by-user-id.js'; describe('isAuthenticated', () => { @@ -31,3 +32,22 @@ describe('isAuthenticated', () => { expect(await isAuthenticated(req)).toBe(false); }); }); + +describe('isApiTokenAuthenticated', () => { + it('should return false if no token is provided', async () => { + const req = { headers: {} }; + expect(await isApiTokenAuthenticated(req)).toBe(false); + }); + + it('should return false if token is invalid', async () => { + const req = { headers: { 'x-api-token': 'invalidToken' } }; + expect(await isApiTokenAuthenticated(req)).toBe(false); + }); + + it('should return true if token is valid', async () => { + const apiToken = await createApiToken(); + + const req = { headers: { 'x-api-token': apiToken.token } }; + expect(await isApiTokenAuthenticated(req)).toBe(true); + }); +}); From 305de6b0287f51516b83919541d08e6bcb0bcde2 Mon Sep 17 00:00:00 2001 From: Faruk AYDIN Date: Wed, 16 Apr 2025 13:21:01 +0200 Subject: [PATCH 2/2] chore: Update ci node action version --- .github/workflows/ci.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4a75b0f3..71e931cf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,8 +13,8 @@ jobs: - run: echo "🎉 The job was automatically triggered by a ${{ github.event_name }} event." - run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!" - run: echo "🔎 The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}." - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: node-version: '18' cache: 'yarn' @@ -32,8 +32,8 @@ jobs: - run: echo "🎉 The job was automatically triggered by a ${{ github.event_name }} event." - run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!" - run: echo "🔎 The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}." - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: node-version: '18' cache: 'yarn' @@ -54,8 +54,8 @@ jobs: - run: echo "🎉 The job was automatically triggered by a ${{ github.event_name }} event." - run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!" - run: echo "🔎 The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}." - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: node-version: '18' cache: 'yarn' @@ -76,8 +76,8 @@ jobs: - run: echo "🎉 The job was automatically triggered by a ${{ github.event_name }} event." - run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!" - run: echo "🔎 The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}." - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: node-version: '18' cache: 'yarn'