@oas-tools/oas-telemetry 0.7.0-alpha.4 → 0.7.0-alpha.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.env.example CHANGED
@@ -24,12 +24,14 @@ OASTLM_CONFIG_GENERAL_SPEC_FILE_NAME=
24
24
 
25
25
  # Enable authentication | Possible values: "true", "false" | Default: "false"
26
26
  OASTLM_CONFIG_AUTH_ENABLED=
27
- # Maximum age for API keys (ms) | Default: 3600000 (1 hour)
28
- OASTLM_CONFIG_AUTH_API_KEY_MAX_AGE=
29
27
  # Password for authentication | Default: "oas-telemetry-password"
30
28
  OASTLM_CONFIG_AUTH_PASSWORD=
31
29
  # JWT secret for authentication | Default: "oas-telemetry-secret"
32
30
  OASTLM_CONFIG_AUTH_JWT_SECRET=
31
+ # Access token max age (ms) | Default: 300000 (5 minutes)
32
+ OASTLM_CONFIG_AUTH_ACCESS_TOKEN_MAX_AGE=
33
+ # Refresh token max age (ms) | Default: 604800000 (7 days)
34
+ OASTLM_CONFIG_AUTH_REFRESH_TOKEN_MAX_AGE=
33
35
 
34
36
 
35
37
  # Enable memory exporter for traces | Possible values: "true", "false" | Default: "true"
@@ -18,9 +18,10 @@ const loadEnv = () => {
18
18
  },
19
19
  auth: {
20
20
  enabled: getParsedEnvVar("OASTLM_CONFIG_AUTH_ENABLED", v => v === "true"),
21
- apiKeyMaxAge: getParsedEnvVar("OASTLM_CONFIG_AUTH_API_KEY_MAX_AGE", v => parseInt(v, 10)),
22
21
  password: getParsedEnvVar("OASTLM_CONFIG_AUTH_PASSWORD"),
23
- jwtSecret: getParsedEnvVar("OASTLM_CONFIG_AUTH_JWT_SECRET")
22
+ jwtSecret: getParsedEnvVar("OASTLM_CONFIG_AUTH_JWT_SECRET"),
23
+ accessTokenMaxAge: getParsedEnvVar("OASTLM_CONFIG_AUTH_ACCESS_TOKEN_MAX_AGE", v => parseInt(v, 10)),
24
+ refreshTokenMaxAge: getParsedEnvVar("OASTLM_CONFIG_AUTH_REFRESH_TOKEN_MAX_AGE", v => parseInt(v, 10))
24
25
  },
25
26
  traces: {
26
27
  memoryExporter: {
@@ -70,10 +71,11 @@ const defaultConfig = exports.defaultConfig = {
70
71
  },
71
72
  auth: {
72
73
  enabled: false,
73
- apiKeyMaxAge: 1000 * 60 * 60,
74
- // 1 hour
75
74
  password: "oas-telemetry-password",
76
- jwtSecret: "oas-telemetry-secret"
75
+ jwtSecret: "oas-telemetry-secret",
76
+ accessTokenMaxAge: 1000 * 60 * 5,
77
+ // 5 minutes
78
+ refreshTokenMaxAge: 1000 * 60 * 60 * 24 * 7 // 7 days
77
79
  },
78
80
  ai: {
79
81
  openAIKey: null,
@@ -23,13 +23,21 @@ const configureRoutes = (router, oasTlmConfig) => {
23
23
  if (_bootConfig.bootEnvVariables.OASTLM_BOOT_ENV === 'development') {
24
24
  _logger.default.info("Running in development mode, enabling CORS for all origins");
25
25
  router.use((0, _cors.default)({
26
- origin: '*',
27
- // Permitir todas las solicitudes en desarrollo
28
- methods: ['GET', 'POST', 'PUT', 'DELETE'],
29
- allowedHeaders: ['Content-Type', 'Authorization']
26
+ origin: (origin, callback) => {
27
+ if (!origin || /^http:\/\/localhost:\d+$/.test(origin)) {
28
+ callback(null, true);
29
+ } else {
30
+ callback(new Error('Not allowed by CORS'));
31
+ }
32
+ },
33
+ credentials: true
30
34
  }));
31
35
  }
32
- router.use((req, res, next) => {
36
+ const telemetryBaseUrl = oasTlmConfig.general.baseUrl;
37
+ // Sub-router for all telemetry endpoints
38
+ const telemetryRouter = (0, _express.Router)();
39
+ // Body parser for JSON requests
40
+ telemetryRouter.use((req, res, next) => {
33
41
  if (req.body !== undefined) {
34
42
  return next(); // Already parsed, no need to parse again.
35
43
  }
@@ -37,52 +45,32 @@ const configureRoutes = (router, oasTlmConfig) => {
37
45
  limit: '10mb'
38
46
  })(req, res, next);
39
47
  });
40
- const allAuthMiddlewares = getWrappedMiddlewares(() => oasTlmConfig.auth.enabled, [(0, _cookieParser.default)(), (0, _authRoutes.getAuthRoutes)(oasTlmConfig), (0, _authMiddleware.getAuthMiddleware)(oasTlmConfig)]);
41
- const baseUrl = oasTlmConfig.general.baseUrl;
42
- router.use(baseUrl, allAuthMiddlewares);
43
- router.use(baseUrl + "/traces", (0, _traceRoutes.getTraceRoutes)());
44
- router.use(baseUrl + "/metrics", (0, _metricsRoutes.getMetricsRoutes)());
45
- router.use(baseUrl + "/logs", (0, _logRoutes.getLogRoutes)());
46
- router.use(baseUrl + "/ai", getWrappedMiddlewares(() => oasTlmConfig.ai.openAIKey !== null, [(0, _aiRoutes.getAIRoutes)(oasTlmConfig)]));
47
- // WARNING: This path must be the same as the one used in the UI package App.tsx "oas-telemetry-ui"
48
- router.use(baseUrl + "/oas-telemetry-ui", (0, _uiRoutes.getUIRoutes)());
49
- router.use(baseUrl + "/utils", (0, _utilRoutes.getUtilsRoutes)(oasTlmConfig));
50
- router.use(baseUrl + "/plugins", (0, _pluginRoutes.getPluginRoutes)());
51
- router.get(baseUrl + '/health', (_req, res) => {
48
+ telemetryRouter.get('/health', (_req, res) => {
52
49
  res.status(200).send({
53
50
  status: 'OK'
54
51
  });
55
52
  });
56
- //redirect to the UI when accessing the base URL
57
- router.get(baseUrl, (req, res) => {
58
- res.redirect(baseUrl + "/oas-telemetry-ui");
53
+ // Redirect to the UI when accessing the base URL
54
+ telemetryRouter.get('/', (req, res) => {
55
+ res.redirect(`${telemetryBaseUrl}/oas-telemetry-ui/`);
59
56
  });
57
+ // WARNING: This path must be the same as the one used in the UI package App.tsx "oas-telemetry-ui"
58
+ telemetryRouter.use("/oas-telemetry-ui", (0, _uiRoutes.getUIRoutes)());
59
+ // Auth routes must be registered. If authentication is not enabled, all requests will be allowed.
60
+ // Frontend will use these endpoints;
61
+ telemetryRouter.use((0, _cookieParser.default)());
62
+ // Refresh token uses /auth/refresh path, careful if you change it
63
+ telemetryRouter.use('/auth', (0, _authRoutes.getAuthRoutes)(oasTlmConfig));
64
+ telemetryRouter.use((0, _authMiddleware.getAuthMiddleware)(oasTlmConfig));
65
+ telemetryRouter.use("/traces", (0, _traceRoutes.getTraceRoutes)());
66
+ telemetryRouter.use("/metrics", (0, _metricsRoutes.getMetricsRoutes)());
67
+ telemetryRouter.use("/logs", (0, _logRoutes.getLogRoutes)());
68
+ if (oasTlmConfig.ai.openAIKey) {
69
+ telemetryRouter.use("/ai", (0, _aiRoutes.getAIRoutes)(oasTlmConfig));
70
+ }
71
+ telemetryRouter.use("/utils", (0, _utilRoutes.getUtilsRoutes)(oasTlmConfig));
72
+ telemetryRouter.use("/plugins", (0, _pluginRoutes.getPluginRoutes)());
73
+ // Mount the telemetryRouter under telemetryBaseUrl
74
+ router.use(telemetryBaseUrl, telemetryRouter);
60
75
  };
61
- /**
62
- * This function wraps the provided middleware functions with a condition callback.
63
- * If the condition callback returns true, the middleware/router will be executed.
64
- * If the condition callback returns false, the middleware/router will be skipped.
65
- *
66
- * @callback {function} conditionCallback A callback function that returns a boolean to determine if the middleware should be used.
67
- * @param {Array} middlewares An array of middleware or routers to be wrapped.
68
- * @returns {Array} An array of wrapped middleware functions.
69
- */
70
- exports.configureRoutes = configureRoutes;
71
- function getWrappedMiddlewares(conditionCallback, middlewares) {
72
- return middlewares.map(middleware => {
73
- return function (req, res, next) {
74
- if (conditionCallback()) {
75
- if (typeof middleware === 'function') {
76
- // look for handle property, if it exists, it's a router. If not call middleware
77
- if (middleware.handle) {
78
- middleware.handle(req, res, next);
79
- } else {
80
- middleware(req, res, next);
81
- }
82
- }
83
- } else {
84
- next();
85
- }
86
- };
87
- });
88
- }
76
+ exports.configureRoutes = configureRoutes;
@@ -3,69 +3,134 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.getLogout = exports.getLogin = exports.getCheck = void 0;
6
+ exports.getRefresh = exports.getLogout = exports.getLogin = exports.getAuthEnabled = void 0;
7
7
  var _jsonwebtoken = _interopRequireDefault(require("jsonwebtoken"));
8
8
  var _logger = _interopRequireDefault(require("../utils/logger.cjs"));
9
9
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
10
+ function generateAccessToken(secret, expiresIn) {
11
+ return _jsonwebtoken.default.sign({
12
+ type: "access"
13
+ }, secret, {
14
+ expiresIn: Math.floor(expiresIn / 1000)
15
+ });
16
+ }
17
+ function generateRefreshToken(secret, expiresIn) {
18
+ return _jsonwebtoken.default.sign({
19
+ type: "refresh"
20
+ }, secret, {
21
+ expiresIn: Math.floor(expiresIn / 1000)
22
+ });
23
+ }
10
24
  const getLogin = oasTlmConfig => (req, res) => {
25
+ if (!oasTlmConfig.auth.enabled) {
26
+ res.status(200).json({
27
+ valid: true,
28
+ message: "Auth disabled"
29
+ });
30
+ return;
31
+ }
11
32
  try {
12
33
  const {
13
34
  password
14
35
  } = req.body;
15
36
  if (password === oasTlmConfig.auth.password) {
16
- const options = {
17
- maxAge: oasTlmConfig.auth.apiKeyMaxAge,
37
+ const accessToken = generateAccessToken(oasTlmConfig.auth.jwtSecret, oasTlmConfig.auth.accessTokenMaxAge);
38
+ const refreshToken = generateRefreshToken(oasTlmConfig.auth.jwtSecret, oasTlmConfig.auth.refreshTokenMaxAge);
39
+ res.cookie("accessToken", accessToken, {
40
+ maxAge: oasTlmConfig.auth.accessTokenMaxAge,
18
41
  httpOnly: true,
19
- secure: true,
20
- signed: false
21
- };
22
- const apiKey = _jsonwebtoken.default.sign({
23
- password: oasTlmConfig.auth.password
24
- }, oasTlmConfig.auth.jwtSecret);
25
- res.cookie('apiKey', apiKey, options);
42
+ secure: process.env.NODE_ENV === "production",
43
+ sameSite: "lax",
44
+ path: "/"
45
+ });
46
+ res.cookie("refreshToken", refreshToken, {
47
+ maxAge: oasTlmConfig.auth.refreshTokenMaxAge,
48
+ httpOnly: true,
49
+ secure: process.env.NODE_ENV === "production",
50
+ sameSite: "lax",
51
+ path: oasTlmConfig.general.baseUrl + "/auth/refresh" // <-- cambiado de "/auth/refresh" a oasTlmConfig.general.baseUrl + "/auth/refresh"
52
+ });
26
53
  res.status(200).json({
27
54
  valid: true,
28
- message: 'API Key is valid'
55
+ message: "Login successful"
29
56
  });
30
57
  return;
31
58
  }
32
59
  res.status(400).json({
33
60
  valid: false,
34
- message: 'Invalid API Key'
61
+ message: "Invalid password"
35
62
  });
36
63
  } catch (error) {
37
- _logger.default.log("Error: ", error);
64
+ _logger.default.error("Login error: ", error);
38
65
  res.status(500).json({
39
66
  valid: false,
40
- message: 'Internal server error'
67
+ message: "Internal server error"
41
68
  });
42
69
  }
43
70
  };
44
71
  exports.getLogin = getLogin;
45
72
  const getLogout = oasTlmConfig => (req, res) => {
46
- res.clearCookie('apiKey');
47
- res.redirect(oasTlmConfig.general.baseUrl + oasTlmConfig.general.uiPath + '/login');
73
+ if (!oasTlmConfig.auth.enabled) {
74
+ res.status(200).json({
75
+ valid: true,
76
+ message: "Auth disabled"
77
+ });
78
+ return;
79
+ }
80
+ res.clearCookie('accessToken', {
81
+ path: '/'
82
+ });
83
+ res.clearCookie('refreshToken', {
84
+ path: oasTlmConfig.general.baseUrl + '/auth/refresh'
85
+ }); // <-- cambiado de "/auth/refresh" a oasTlmConfig.general.baseUrl + "/auth/refresh"
86
+ res.status(200).json({
87
+ valid: true,
88
+ message: "Logged out"
89
+ });
48
90
  };
49
91
  exports.getLogout = getLogout;
50
- const getCheck = oasTlmConfig => (req, res) => {
51
- if (!req.cookies.apiKey) {
92
+ const getRefresh = oasTlmConfig => (req, res) => {
93
+ if (!oasTlmConfig.auth.enabled) {
52
94
  res.status(200).json({
95
+ valid: true,
96
+ message: "Auth disabled"
97
+ });
98
+ return;
99
+ }
100
+ const refreshToken = req.cookies.refreshToken;
101
+ if (!refreshToken) {
102
+ res.status(401).json({
53
103
  valid: false,
54
- message: 'API Key is invalid'
104
+ message: "No refresh token"
55
105
  });
56
106
  return;
57
107
  }
58
- const decoded = _jsonwebtoken.default.verify(req.cookies.apiKey, oasTlmConfig.auth.jwtSecret);
59
- if (decoded.password === oasTlmConfig.auth.password) {
108
+ try {
109
+ const payload = _jsonwebtoken.default.verify(refreshToken, oasTlmConfig.auth.jwtSecret);
110
+ if (payload.type !== "refresh") throw new Error("Invalid token type");
111
+ const accessToken = generateAccessToken(oasTlmConfig.auth.jwtSecret, oasTlmConfig.auth.accessTokenMaxAge);
112
+ res.cookie("accessToken", accessToken, {
113
+ maxAge: oasTlmConfig.auth.accessTokenMaxAge,
114
+ httpOnly: true,
115
+ secure: process.env.NODE_ENV === "production",
116
+ sameSite: "lax",
117
+ path: "/"
118
+ });
60
119
  res.status(200).json({
61
120
  valid: true,
62
- message: 'API Key is valid'
121
+ message: "Refreshed"
122
+ });
123
+ } catch (err) {
124
+ res.status(401).json({
125
+ valid: false,
126
+ message: "Invalid refresh token"
63
127
  });
64
- return;
65
128
  }
129
+ };
130
+ exports.getRefresh = getRefresh;
131
+ const getAuthEnabled = oasTlmConfig => (req, res) => {
66
132
  res.status(200).json({
67
- valid: false,
68
- message: 'Invalid API Key'
133
+ enabled: !!oasTlmConfig.auth.enabled
69
134
  });
70
135
  };
71
- exports.getCheck = getCheck;
136
+ exports.getAuthEnabled = getAuthEnabled;
@@ -8,13 +8,26 @@ var _jsonwebtoken = _interopRequireDefault(require("jsonwebtoken"));
8
8
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
9
9
  function getAuthMiddleware(oasTlmConfig) {
10
10
  return function authMiddleware(req, res, next) {
11
- const apiKey = req.cookies.apiKey;
12
- if (apiKey) {
13
- const decoded = _jsonwebtoken.default.verify(apiKey, oasTlmConfig.auth.jwtSecret);
14
- if (decoded.password === oasTlmConfig.auth.password) {
15
- return next();
16
- }
11
+ if (!oasTlmConfig.auth.enabled) {
12
+ return next();
13
+ }
14
+ const token = req.cookies.accessToken;
15
+ if (!token) {
16
+ res.status(401).json({
17
+ valid: false,
18
+ message: "No access token"
19
+ });
20
+ return;
21
+ }
22
+ try {
23
+ const payload = _jsonwebtoken.default.verify(token, oasTlmConfig.auth.jwtSecret);
24
+ if (payload.type !== "access") throw new Error("Invalid token type");
25
+ return next();
26
+ } catch {
27
+ res.status(401).json({
28
+ valid: false,
29
+ message: "Invalid access token"
30
+ });
17
31
  }
18
- res.status(401).redirect(oasTlmConfig.general.baseUrl + oasTlmConfig.general.uiPath + '/login');
19
32
  };
20
33
  }
@@ -9,8 +9,9 @@ var _authController = require("./authController.cjs");
9
9
  const getAuthRoutes = oasTlmConfig => {
10
10
  const router = (0, _express.Router)();
11
11
  router.post('/login', (0, _authController.getLogin)(oasTlmConfig));
12
- router.get('/logout', (0, _authController.getLogout)(oasTlmConfig));
13
- router.get('/check', (0, _authController.getCheck)(oasTlmConfig));
12
+ router.post('/refresh', (0, _authController.getRefresh)(oasTlmConfig));
13
+ router.post('/logout', (0, _authController.getLogout)(oasTlmConfig));
14
+ router.get('/enabled', (0, _authController.getAuthEnabled)(oasTlmConfig));
14
15
  return router;
15
16
  };
16
17
  exports.getAuthRoutes = getAuthRoutes;
@@ -11,9 +11,10 @@ const loadEnv = () => {
11
11
  },
12
12
  auth: {
13
13
  enabled: getParsedEnvVar("OASTLM_CONFIG_AUTH_ENABLED", (v) => v === "true"),
14
- apiKeyMaxAge: getParsedEnvVar("OASTLM_CONFIG_AUTH_API_KEY_MAX_AGE", (v) => parseInt(v, 10)),
15
14
  password: getParsedEnvVar("OASTLM_CONFIG_AUTH_PASSWORD"),
16
15
  jwtSecret: getParsedEnvVar("OASTLM_CONFIG_AUTH_JWT_SECRET"),
16
+ accessTokenMaxAge: getParsedEnvVar("OASTLM_CONFIG_AUTH_ACCESS_TOKEN_MAX_AGE", (v) => parseInt(v, 10)),
17
+ refreshTokenMaxAge: getParsedEnvVar("OASTLM_CONFIG_AUTH_REFRESH_TOKEN_MAX_AGE", (v) => parseInt(v, 10)),
17
18
  },
18
19
  traces: {
19
20
  memoryExporter: {
@@ -61,9 +62,10 @@ export const defaultConfig = {
61
62
  },
62
63
  auth: {
63
64
  enabled: false,
64
- apiKeyMaxAge: 1000 * 60 * 60, // 1 hour
65
65
  password: "oas-telemetry-password",
66
66
  jwtSecret: "oas-telemetry-secret",
67
+ accessTokenMaxAge: 1000 * 60 * 5, // 5 minutes
68
+ refreshTokenMaxAge: 1000 * 60 * 60 * 24 * 7, // 7 days
67
69
  },
68
70
  ai: {
69
71
  openAIKey: null,
@@ -1,4 +1,4 @@
1
- import { json } from "express";
1
+ import { Router, json } from "express";
2
2
  import logger from "./utils/logger.js";
3
3
  import cors from 'cors';
4
4
  import { getTraceRoutes } from "./tlm-trace/traceRoutes.js";
@@ -16,62 +16,50 @@ export const configureRoutes = (router, oasTlmConfig) => {
16
16
  if (bootEnvVariables.OASTLM_BOOT_ENV === 'development') {
17
17
  logger.info("Running in development mode, enabling CORS for all origins");
18
18
  router.use(cors({
19
- origin: '*', // Permitir todas las solicitudes en desarrollo
20
- methods: ['GET', 'POST', 'PUT', 'DELETE'],
21
- allowedHeaders: ['Content-Type', 'Authorization'],
19
+ origin: (origin, callback) => {
20
+ if (!origin || /^http:\/\/localhost:\d+$/.test(origin)) {
21
+ callback(null, true);
22
+ }
23
+ else {
24
+ callback(new Error('Not allowed by CORS'));
25
+ }
26
+ },
27
+ credentials: true
22
28
  }));
23
29
  }
24
- router.use((req, res, next) => {
30
+ const telemetryBaseUrl = oasTlmConfig.general.baseUrl;
31
+ // Sub-router for all telemetry endpoints
32
+ const telemetryRouter = Router();
33
+ // Body parser for JSON requests
34
+ telemetryRouter.use((req, res, next) => {
25
35
  if (req.body !== undefined) {
26
36
  return next(); // Already parsed, no need to parse again.
27
37
  }
28
38
  return json({ limit: '10mb' })(req, res, next);
29
39
  });
30
- const allAuthMiddlewares = getWrappedMiddlewares(() => oasTlmConfig.auth.enabled, [cookieParser(), getAuthRoutes(oasTlmConfig), getAuthMiddleware(oasTlmConfig)]);
31
- const baseUrl = oasTlmConfig.general.baseUrl;
32
- router.use(baseUrl, allAuthMiddlewares);
33
- router.use(baseUrl + "/traces", getTraceRoutes());
34
- router.use(baseUrl + "/metrics", getMetricsRoutes());
35
- router.use(baseUrl + "/logs", getLogRoutes());
36
- router.use(baseUrl + "/ai", getWrappedMiddlewares(() => oasTlmConfig.ai.openAIKey !== null, [getAIRoutes(oasTlmConfig)]));
37
- // WARNING: This path must be the same as the one used in the UI package App.tsx "oas-telemetry-ui"
38
- router.use(baseUrl + "/oas-telemetry-ui", getUIRoutes());
39
- router.use(baseUrl + "/utils", getUtilsRoutes(oasTlmConfig));
40
- router.use(baseUrl + "/plugins", getPluginRoutes());
41
- router.get(baseUrl + '/health', (_req, res) => {
40
+ telemetryRouter.get('/health', (_req, res) => {
42
41
  res.status(200).send({ status: 'OK' });
43
42
  });
44
- //redirect to the UI when accessing the base URL
45
- router.get(baseUrl, (req, res) => {
46
- res.redirect(baseUrl + "/oas-telemetry-ui");
43
+ // Redirect to the UI when accessing the base URL
44
+ telemetryRouter.get('/', (req, res) => {
45
+ res.redirect(`${telemetryBaseUrl}/oas-telemetry-ui/`);
47
46
  });
47
+ // WARNING: This path must be the same as the one used in the UI package App.tsx "oas-telemetry-ui"
48
+ telemetryRouter.use("/oas-telemetry-ui", getUIRoutes());
49
+ // Auth routes must be registered. If authentication is not enabled, all requests will be allowed.
50
+ // Frontend will use these endpoints;
51
+ telemetryRouter.use(cookieParser());
52
+ // Refresh token uses /auth/refresh path, careful if you change it
53
+ telemetryRouter.use('/auth', getAuthRoutes(oasTlmConfig));
54
+ telemetryRouter.use(getAuthMiddleware(oasTlmConfig));
55
+ telemetryRouter.use("/traces", getTraceRoutes());
56
+ telemetryRouter.use("/metrics", getMetricsRoutes());
57
+ telemetryRouter.use("/logs", getLogRoutes());
58
+ if (oasTlmConfig.ai.openAIKey) {
59
+ telemetryRouter.use("/ai", getAIRoutes(oasTlmConfig));
60
+ }
61
+ telemetryRouter.use("/utils", getUtilsRoutes(oasTlmConfig));
62
+ telemetryRouter.use("/plugins", getPluginRoutes());
63
+ // Mount the telemetryRouter under telemetryBaseUrl
64
+ router.use(telemetryBaseUrl, telemetryRouter);
48
65
  };
49
- /**
50
- * This function wraps the provided middleware functions with a condition callback.
51
- * If the condition callback returns true, the middleware/router will be executed.
52
- * If the condition callback returns false, the middleware/router will be skipped.
53
- *
54
- * @callback {function} conditionCallback A callback function that returns a boolean to determine if the middleware should be used.
55
- * @param {Array} middlewares An array of middleware or routers to be wrapped.
56
- * @returns {Array} An array of wrapped middleware functions.
57
- */
58
- function getWrappedMiddlewares(conditionCallback, middlewares) {
59
- return middlewares.map(middleware => {
60
- return function (req, res, next) {
61
- if (conditionCallback()) {
62
- if (typeof middleware === 'function') {
63
- // look for handle property, if it exists, it's a router. If not call middleware
64
- if (middleware.handle) {
65
- middleware.handle(req, res, next);
66
- }
67
- else {
68
- middleware(req, res, next);
69
- }
70
- }
71
- }
72
- else {
73
- next();
74
- }
75
- };
76
- });
77
- }
@@ -1,40 +1,82 @@
1
1
  import jwt from 'jsonwebtoken';
2
2
  import logger from '../utils/logger.js';
3
+ function generateAccessToken(secret, expiresIn) {
4
+ return jwt.sign({ type: "access" }, secret, { expiresIn: Math.floor(expiresIn / 1000) });
5
+ }
6
+ function generateRefreshToken(secret, expiresIn) {
7
+ return jwt.sign({ type: "refresh" }, secret, { expiresIn: Math.floor(expiresIn / 1000) });
8
+ }
3
9
  export const getLogin = (oasTlmConfig) => (req, res) => {
10
+ if (!oasTlmConfig.auth.enabled) {
11
+ res.status(200).json({ valid: true, message: "Auth disabled" });
12
+ return;
13
+ }
4
14
  try {
5
15
  const { password } = req.body;
6
16
  if (password === oasTlmConfig.auth.password) {
7
- const options = {
8
- maxAge: oasTlmConfig.auth.apiKeyMaxAge,
17
+ const accessToken = generateAccessToken(oasTlmConfig.auth.jwtSecret, oasTlmConfig.auth.accessTokenMaxAge);
18
+ const refreshToken = generateRefreshToken(oasTlmConfig.auth.jwtSecret, oasTlmConfig.auth.refreshTokenMaxAge);
19
+ res.cookie("accessToken", accessToken, {
20
+ maxAge: oasTlmConfig.auth.accessTokenMaxAge,
21
+ httpOnly: true,
22
+ secure: process.env.NODE_ENV === "production",
23
+ sameSite: "lax",
24
+ path: "/"
25
+ });
26
+ res.cookie("refreshToken", refreshToken, {
27
+ maxAge: oasTlmConfig.auth.refreshTokenMaxAge,
9
28
  httpOnly: true,
10
- secure: true,
11
- signed: false
12
- };
13
- const apiKey = jwt.sign({ password: oasTlmConfig.auth.password }, oasTlmConfig.auth.jwtSecret);
14
- res.cookie('apiKey', apiKey, options);
15
- res.status(200).json({ valid: true, message: 'API Key is valid' });
29
+ secure: process.env.NODE_ENV === "production",
30
+ sameSite: "lax",
31
+ path: oasTlmConfig.general.baseUrl + "/auth/refresh" // <-- cambiado de "/auth/refresh" a oasTlmConfig.general.baseUrl + "/auth/refresh"
32
+ });
33
+ res.status(200).json({ valid: true, message: "Login successful" });
16
34
  return;
17
35
  }
18
- res.status(400).json({ valid: false, message: 'Invalid API Key' });
36
+ res.status(400).json({ valid: false, message: "Invalid password" });
19
37
  }
20
38
  catch (error) {
21
- logger.log("Error: ", error);
22
- res.status(500).json({ valid: false, message: 'Internal server error' });
39
+ logger.error("Login error: ", error);
40
+ res.status(500).json({ valid: false, message: "Internal server error" });
23
41
  }
24
42
  };
25
43
  export const getLogout = (oasTlmConfig) => (req, res) => {
26
- res.clearCookie('apiKey');
27
- res.redirect(oasTlmConfig.general.baseUrl + oasTlmConfig.general.uiPath + '/login');
44
+ if (!oasTlmConfig.auth.enabled) {
45
+ res.status(200).json({ valid: true, message: "Auth disabled" });
46
+ return;
47
+ }
48
+ res.clearCookie('accessToken', { path: '/' });
49
+ res.clearCookie('refreshToken', { path: oasTlmConfig.general.baseUrl + '/auth/refresh' }); // <-- cambiado de "/auth/refresh" a oasTlmConfig.general.baseUrl + "/auth/refresh"
50
+ res.status(200).json({ valid: true, message: "Logged out" });
28
51
  };
29
- export const getCheck = (oasTlmConfig) => (req, res) => {
30
- if (!req.cookies.apiKey) {
31
- res.status(200).json({ valid: false, message: 'API Key is invalid' });
52
+ export const getRefresh = (oasTlmConfig) => (req, res) => {
53
+ if (!oasTlmConfig.auth.enabled) {
54
+ res.status(200).json({ valid: true, message: "Auth disabled" });
32
55
  return;
33
56
  }
34
- const decoded = jwt.verify(req.cookies.apiKey, oasTlmConfig.auth.jwtSecret);
35
- if (decoded.password === oasTlmConfig.auth.password) {
36
- res.status(200).json({ valid: true, message: 'API Key is valid' });
57
+ const refreshToken = req.cookies.refreshToken;
58
+ if (!refreshToken) {
59
+ res.status(401).json({ valid: false, message: "No refresh token" });
37
60
  return;
38
61
  }
39
- res.status(200).json({ valid: false, message: 'Invalid API Key' });
62
+ try {
63
+ const payload = jwt.verify(refreshToken, oasTlmConfig.auth.jwtSecret);
64
+ if (payload.type !== "refresh")
65
+ throw new Error("Invalid token type");
66
+ const accessToken = generateAccessToken(oasTlmConfig.auth.jwtSecret, oasTlmConfig.auth.accessTokenMaxAge);
67
+ res.cookie("accessToken", accessToken, {
68
+ maxAge: oasTlmConfig.auth.accessTokenMaxAge,
69
+ httpOnly: true,
70
+ secure: process.env.NODE_ENV === "production",
71
+ sameSite: "lax",
72
+ path: "/"
73
+ });
74
+ res.status(200).json({ valid: true, message: "Refreshed" });
75
+ }
76
+ catch (err) {
77
+ res.status(401).json({ valid: false, message: "Invalid refresh token" });
78
+ }
79
+ };
80
+ export const getAuthEnabled = (oasTlmConfig) => (req, res) => {
81
+ res.status(200).json({ enabled: !!oasTlmConfig.auth.enabled });
40
82
  };
@@ -1,13 +1,22 @@
1
- import jwt from 'jsonwebtoken';
1
+ import jwt from "jsonwebtoken";
2
2
  export function getAuthMiddleware(oasTlmConfig) {
3
3
  return function authMiddleware(req, res, next) {
4
- const apiKey = req.cookies.apiKey;
5
- if (apiKey) {
6
- const decoded = jwt.verify(apiKey, oasTlmConfig.auth.jwtSecret);
7
- if (decoded.password === oasTlmConfig.auth.password) {
8
- return next();
9
- }
10
- }
11
- res.status(401).redirect(oasTlmConfig.general.baseUrl + oasTlmConfig.general.uiPath + '/login');
4
+ if (!oasTlmConfig.auth.enabled) {
5
+ return next();
6
+ }
7
+ const token = req.cookies.accessToken;
8
+ if (!token) {
9
+ res.status(401).json({ valid: false, message: "No access token" });
10
+ return;
11
+ }
12
+ try {
13
+ const payload = jwt.verify(token, oasTlmConfig.auth.jwtSecret);
14
+ if (payload.type !== "access")
15
+ throw new Error("Invalid token type");
16
+ return next();
17
+ }
18
+ catch {
19
+ res.status(401).json({ valid: false, message: "Invalid access token" });
20
+ }
12
21
  };
13
22
  }
@@ -1,9 +1,10 @@
1
1
  import { Router } from 'express';
2
- import { getLogin, getLogout, getCheck } from './authController.js';
2
+ import { getLogin, getLogout, getRefresh, getAuthEnabled } from './authController.js';
3
3
  export const getAuthRoutes = (oasTlmConfig) => {
4
4
  const router = Router();
5
5
  router.post('/login', getLogin(oasTlmConfig));
6
- router.get('/logout', getLogout(oasTlmConfig));
7
- router.get('/check', getCheck(oasTlmConfig));
6
+ router.post('/refresh', getRefresh(oasTlmConfig));
7
+ router.post('/logout', getLogout(oasTlmConfig));
8
+ router.get('/enabled', getAuthEnabled(oasTlmConfig));
8
9
  return router;
9
10
  };