Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"ejs": "^3.1.9",
"express": "^4.17.6",
"express-session": "^1.17.3",
"he": "^1.2.0",
"helmet": "^6.0.1",
"http-errors": "^2.0.0",
"http-proxy-middleware": "^2.0.6",
Expand Down Expand Up @@ -68,6 +69,7 @@
"@types/express-oauth-server": "^2.0.4",
"@types/express-serve-static-core": "^4.17.33",
"@types/express-session": "^1.17.7",
"@types/he": "^1.2.0",
"@types/http-errors": "^2.0.1",
"@types/jest": "^29.2.6",
"@types/jsonwebtoken": "^9.0.1",
Expand Down
15 changes: 12 additions & 3 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,16 @@
import pgSession from 'connect-pg-simple';
import { authProviderFactory } from './main/services/authProviderFactory';
import path from 'path';
import helmet from 'helmet';

const app = express();
app.use(helmet({
hsts: {
maxAge: 31536000, // 1 year in seconds
includeSubDomains: true,
preload: true
}
}));
const sessionSecret: any = process.env.SESSION_SECRET
const PostgresqlStore = pgSession(session)
const sessionStore: any = new PostgresqlStore({
Expand Down Expand Up @@ -38,19 +46,20 @@
const keycloakRealm = appConfig.KEYCLOAK.REALM;

const keycloakConfig = {
resource: keycloakClientID,
realm: keycloakRealm,
authServerUrl: keycloakUrl,
bearerOnly: false

Check failure

Code scanning / CodeQL

Missing rate limiting High

This route handler performs
authorization
, but is not rate-limited.
};

const authProvider = authProviderFactory(authenticationType,keycloakConfig, sessionStore);
app.use(authProvider.init())
app.get('/console/logout', authProvider.authenticate(), async (req:any, res) => {
const authProvider = authProviderFactory(authenticationType, keycloakConfig, sessionStore);
app.use(authProvider.init());
app.get('/console/logout', authProvider.authenticate(), async (req: any, res) => {
await authProvider.logout(req, res);
res.redirect('/console');
});
app.get('/console', authProvider.authenticate(), (req, res) => {
res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});

Expand Down
10 changes: 9 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,22 @@ const invalidRouteHandler = sharedMiddlewares.get('invalidRoute');
app.set('port', port);
app.set('logger', logger);
app.disable('x-powered-by');
// app.use(helmet());
// ToDo: Move helmet and cors to app.ts and remove from here
app.use(helmet({
hsts: {
maxAge: 31536000, // 1 year in seconds
includeSubDomains: true,
preload: true
}
}));
Comment on lines +22 to +28
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

rg -n 'helmet' --type=ts -C3

Repository: Sanketika-Obsrv/obsrv-web-console

Length of output: 1078


🏁 Script executed:

head -30 src/index.ts

Repository: Sanketika-Obsrv/obsrv-web-console

Length of output: 959


🏁 Script executed:

head -30 src/app.ts

Repository: Sanketika-Obsrv/obsrv-web-console

Length of output: 1022


Duplicate Helmet registration — app imported from ./app already applies Helmet middleware.

app is imported from ./app (line 8), which already calls app.use(helmet({ hsts: … })) in app.ts line 14. Applying Helmet again here in index.ts creates a duplicate middleware registration on the same app instance, causing Helmet header handlers to run twice per request. Remove the Helmet call from either app.ts or index.ts.

🧰 Tools
🪛 ESLint

[error] 21-21: Insert ⏎····

(prettier/prettier)


[error] 22-22: Insert ······

(prettier/prettier)


[error] 23-23: Insert ········

(prettier/prettier)


[error] 24-24: Insert ········

(prettier/prettier)


[error] 25-25: Replace ····preload:·true with ············preload:·true,

(prettier/prettier)


[error] 26-26: Replace ··} with ········},

(prettier/prettier)


[error] 27-27: Replace }) with ····}),⏎

(prettier/prettier)

🤖 Prompt for AI Agents
In `@src/index.ts` around lines 21 - 27, The Helmet middleware is being registered
twice on the same Express app instance — remove the duplicate registration by
deleting the app.use(helmet({ hsts: { maxAge: 31536000, includeSubDomains: true,
preload: true } })) call from index.ts (since app is imported from ./app which
already applies Helmet), or alternatively remove the Helmet setup in the app
module so only one module calls helmet; ensure only one app.use(helmet(...))
remains referencing the app variable to avoid double header handling.

app.use(cors());
app.use(express.static(path.join(__dirname, 'build')));

// mount routers
mountRoutes(app);

app.get('*', function (req, res) {
res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});

Expand Down
1 change: 1 addition & 0 deletions src/main/controllers/auth_logout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export default {
request.logout({ keepSessionInfo: false }, ((error: any) => {
error && console.log("Error while logout", error)
}))
response.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
response.status(200).json({ "status": "successful" })
},
};
1 change: 1 addition & 0 deletions src/main/controllers/auth_user_info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export default {
scope: authInfo?.scope,
email: user?.email_address
}
response.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
response.json(data);
},
};
1 change: 1 addition & 0 deletions src/main/controllers/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import appConfig from '../../shared/resources/appConfig';
export default {
name: 'config:vars',
handler: () => async (request: Request, response: Response, next: NextFunction) => {
response.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
response.json({
"GRAFANA_URL": appConfig.GRAFANA.URL,
"SUPERSET_URL": appConfig.SUPERSET.URL,
Expand Down
6 changes: 4 additions & 2 deletions src/main/controllers/dataset_aggregator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,9 +221,11 @@ const generateDatasetState = async (state: Record<string, any>) => {
export default {
name: 'dataset:state',
handler: () => async (request: Request, response: Response, next: NextFunction) => {
let { datasetId } = request.params;
let { status } = request.query;
let datasetId = _.get(request, 'params.datasetId');
const status = _.get(request, 'query.status');

datasetId = status === "Live" ? _.split(datasetId, '.', 1)[0] : datasetId
Comment on lines +226 to 227
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix lint errors: trailing whitespace and missing semicolon.

ESLint reports a blank line with whitespace on Line 226 and a missing semicolon on Line 227. Also, double quotes should be single quotes per prettier config.

Proposed fix
         const status = _.get(request, 'query.status');
-        
-        datasetId = status === "Live" ? _.split(datasetId, '.', 1)[0] : datasetId
+        datasetId = status === 'Live' ? _.split(datasetId, '.', 1)[0] : datasetId;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
datasetId = status === "Live" ? _.split(datasetId, '.', 1)[0] : datasetId
datasetId = status === 'Live' ? _.split(datasetId, '.', 1)[0] : datasetId;
🧰 Tools
🪛 ESLint

[error] 226-226: Delete ········

(prettier/prettier)


[error] 227-227: Replace "Live"·?·_.split(datasetId,·'.',·1)[0]·:·datasetId with 'Live'·?·_.split(datasetId,·'.',·1)[0]·:·datasetId;

(prettier/prettier)

🤖 Prompt for AI Agents
In `@src/main/controllers/dataset_aggregator.ts` around lines 226 - 227, Remove
the trailing blank whitespace and fix the semicolon and quote style on the
datasetId reassignment inside the dataset aggregation logic: change the line
"datasetId = status === "Live" ? _.split(datasetId, '.', 1)[0] : datasetId" to
use single quotes for 'Live' and '.' and terminate the statement with a
semicolon; ensure the preceding blank line has no trailing spaces. This affects
the reassignment expression for datasetId (the _.split usage) in the dataset
aggregation function in dataset_aggregator.ts.

response.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
try {
const dataset = await fetchDataset({ datasetId, status });
const payload = {
Expand Down
1 change: 1 addition & 0 deletions src/main/controllers/dataset_diff.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export default {
name: 'dataset:diff',
handler: () => async (request: Request, response: Response, next: NextFunction) => {
const { datasetId } = request.params;
response.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
try {
let liveDataset = await fetchDataset({ datasetId });
if (_.get(liveDataset, "api_version") !== "v2") {
Expand Down
27 changes: 13 additions & 14 deletions src/main/controllers/dataset_exists.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,27 @@
import { NextFunction, Request, Response } from "express";
import { fetchDataset, fetchDraftDataset } from "../services/dataset";
import _ from "lodash";
import { getDiff } from "json-difference";
import { NextFunction, Request, Response } from 'express';
import _ from 'lodash';
import { fetchDataset, fetchDraftDataset } from '../services/dataset';

export default {
name: 'dataset:exists',
handler: () => async (request: Request, response: Response, next: NextFunction) => {
const { datasetId } = request.params;
const datasetId = _.get(request.params, 'datasetId');
response.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
try {
const liveDataset = await Promise.allSettled([fetchDataset({ datasetId })])
if(liveDataset[0].status == 'fulfilled') {
const liveDataset = await Promise.allSettled([fetchDataset({ datasetId })])
if (liveDataset[0].status === 'fulfilled') {
return response.status(200).json(liveDataset[0].value)
}
const draftDataset = await Promise.allSettled([fetchDraftDataset({ datasetId })])
if(draftDataset[0].status == 'fulfilled') {

const draftDataset = await Promise.allSettled([fetchDraftDataset({ datasetId })])
if (draftDataset[0].status === 'fulfilled') {
return response.status(200).json(draftDataset[0].value)
}

if(draftDataset[0].status == 'rejected') {
return response.status(_.get(draftDataset[0], ['reason', 'status'])).json(_.get(draftDataset[0], ['reason', 'response', 'data']))
if (draftDataset[0].status === 'rejected') {
const errorData = _.get(draftDataset[0], ['reason', 'response', 'data']);
return response.status(_.get(draftDataset[0], ['reason', 'status'])).json(errorData)
Comment on lines +21 to +23
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Bug: reason.status is not the HTTP status code — use reason.response.status.

For Axios errors, the HTTP status code lives at error.response.status, not error.status. The error data on line 22 is correctly extracted from reason.response.data, but the status on line 23 reads from reason.status (which is typically undefined). When response.status(undefined) is called, Express coerces it to 200, so the client receives error data with a 200 OK — silently masking the failure.

Proposed fix
             if (draftDataset[0].status === 'rejected') {
                 const errorData = _.get(draftDataset[0], ['reason', 'response', 'data']);
-                return response.status(_.get(draftDataset[0], ['reason', 'status'])).json(errorData)
+                const statusCode = _.get(draftDataset[0], ['reason', 'response', 'status'], 500);
+                return response.status(statusCode).json(errorData)
             }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (draftDataset[0].status === 'rejected') {
const errorData = _.get(draftDataset[0], ['reason', 'response', 'data']);
return response.status(_.get(draftDataset[0], ['reason', 'status'])).json(errorData)
if (draftDataset[0].status === 'rejected') {
const errorData = _.get(draftDataset[0], ['reason', 'response', 'data']);
const statusCode = _.get(draftDataset[0], ['reason', 'response', 'status'], 500);
return response.status(statusCode).json(errorData);
}
🧰 Tools
🪛 ESLint

[error] 23-23: Insert ;

(prettier/prettier)

🤖 Prompt for AI Agents
In `@src/main/controllers/dataset_exists.ts` around lines 21 - 23, The code in
dataset_exists that sets the response status uses reason.status (which is
undefined for Axios errors) causing Express to send 200; change the status
extraction to use reason.response.status (e.g., _.get(draftDataset[0],
['reason','response','status'])) and provide a numeric fallback (like 500) to
ensure a valid HTTP status; update the response.status(...) call accordingly
where draftDataset[0].status === 'rejected' and errorData is computed.

}


} catch (error) {
next(error);
}
Expand Down
1 change: 1 addition & 0 deletions src/main/controllers/getAllFields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export default {
const { dataset_id } = request.params;
const status: any = request.query.status;
let flattenResult: any = [];
response.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
try {
const dataset = await fetchDatasetRecord(dataset_id, status);
const data_schema = _.get(dataset, "data_schema", {});
Expand Down
3 changes: 2 additions & 1 deletion src/main/controllers/metrics_scrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ export default {
handler: () => async (request: Request, response: Response, next: NextFunction) => {
try {
response.set('Content-Type', register.contentType);
const metrics = await register.metrics()
const metrics = await register.metrics();
response.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
response.status(200).send(metrics);
} catch (error) {
next(error);
Expand Down
24 changes: 17 additions & 7 deletions src/main/controllers/test_connection.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,30 @@
import { NextFunction, Request, Response } from "express";
import { Kafka } from "kafkajs";
import _ from "lodash";
import { NextFunction, Request, Response } from 'express';
import { Kafka } from 'kafkajs';
import * as _ from 'lodash';

export default {
name: 'connector:test',
handler: () => async (request: Request, response: Response, next: NextFunction) => {
response.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
try {
const { kafkaBrokers, topic } = request.body;
const topic = _.get(request.body, 'topic', "").toString().trim();
const kafkaBrokers = _.get(request.body, 'kafkaBrokers', "").toString().trim();
Comment on lines +10 to +11
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

_.get returns null (not the default) when the property exists but is null, causing .toString() to throw.

_.get only falls back to the default value when the resolved value is undefined. A request body like { "topic": null } will bypass the default, and null.toString() throws a TypeError caught by line 24, returning a misleading 500 instead of 400.

Use nullish coalescing or an explicit fallback:

Proposed fix
-            const topic = _.get(request.body, 'topic', "").toString().trim();
-            const kafkaBrokers = _.get(request.body, 'kafkaBrokers', "").toString().trim();
+            const topic = String(_.get(request.body, 'topic') ?? '').trim();
+            const kafkaBrokers = String(_.get(request.body, 'kafkaBrokers') ?? '').trim();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const topic = _.get(request.body, 'topic', "").toString().trim();
const kafkaBrokers = _.get(request.body, 'kafkaBrokers', "").toString().trim();
const topic = String(_.get(request.body, 'topic') ?? '').trim();
const kafkaBrokers = String(_.get(request.body, 'kafkaBrokers') ?? '').trim();
🧰 Tools
🪛 ESLint

[error] 10-10: Replace "" with ''

(prettier/prettier)


[error] 11-11: Replace "" with ''

(prettier/prettier)

🤖 Prompt for AI Agents
In `@src/main/controllers/test_connection.ts` around lines 10 - 11, The current
use of _.get for topic and kafkaBrokers can return null (not undefined), causing
.toString() to throw; update the assignment of topic and kafkaBrokers to safely
coerce null/undefined to an empty string before calling toString()/trim() (e.g.,
use nullish coalescing or explicit String() on _.get(request.body, 'topic',
undefined) and _.get(request.body, 'kafkaBrokers', undefined) so that topic and
kafkaBrokers are always a string), and keep the rest of the validation/error
path in the same handler (ensure references to topic and kafkaBrokers use the
new safe values).


if (!kafkaBrokers || !topic) {
response.setHeader('Content-Type', 'application/json');
return response.status(400).send({ error: "kafkaBrokers and topic are required" });
}

const topicsList = await service.getTopics(kafkaBrokers);
const topicExists = topicsList.includes(topic);
if (!topicExists) throw { message: "Topic does not exist" };
const result = { connectionEstablished: true, topicExists: topicExists }
if (!topicExists) throw new Error("Topic does not exist");
const result = { connectionEstablished: true, topicExists: topicExists };
response.setHeader('Content-Type', 'application/json');
response.status(200).send(result);
} catch (error: any) {
console.log(error?.message);
next("Failed to establish connection to the client")
response.setHeader('Content-Type', 'application/json');
response.status(500).send({ error: "Failed to establish connection to the client" });
Comment on lines +20 to +27
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Topic-not-found is misreported as a connection failure (500).

Line 20 throws when the topic doesn't exist, but the catch block on line 27 returns a generic 500 "Failed to establish connection". A missing topic on a reachable broker is not a connection failure — it's a valid result. Previously the handler could distinguish these cases; now all errors are flattened into the same 500.

Consider returning the topic-not-found case as a successful connection with topicExists: false (which is arguably the point of a "test connection" endpoint), or at least return a distinct status/message.

Proposed fix: return topicExists: false instead of throwing
-            if (!topicExists) throw new Error("Topic does not exist");
-            const result = { connectionEstablished: true, topicExists: topicExists };
+            const result = { connectionEstablished: true, topicExists };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (!topicExists) throw new Error("Topic does not exist");
const result = { connectionEstablished: true, topicExists: topicExists };
response.setHeader('Content-Type', 'application/json');
response.status(200).send(result);
} catch (error: any) {
console.log(error?.message);
next("Failed to establish connection to the client")
response.setHeader('Content-Type', 'application/json');
response.status(500).send({ error: "Failed to establish connection to the client" });
const result = { connectionEstablished: true, topicExists };
response.setHeader('Content-Type', 'application/json');
response.status(200).send(result);
} catch (error: any) {
console.log(error?.message);
response.setHeader('Content-Type', 'application/json');
response.status(500).send({ error: "Failed to establish connection to the client" });
🧰 Tools
🪛 ESLint

[error] 20-20: Replace "Topic·does·not·exist" with 'Topic·does·not·exist'

(prettier/prettier)


[error] 25-25: Unexpected console statement.

(no-console)


[error] 27-27: Replace "Failed·to·establish·connection·to·the·client" with 'Failed·to·establish·connection·to·the·client'

(prettier/prettier)

🤖 Prompt for AI Agents
In `@src/main/controllers/test_connection.ts` around lines 20 - 27, The handler
currently throws "Topic does not exist" which gets caught and turned into a 500;
change the flow so that when topicExists is false you do not throw but instead
return a 200 with { connectionEstablished: true, topicExists: false } (i.e.,
remove the throw new Error("Topic does not exist") and let the existing result
send path handle it), or alternately detect that specific error in the catch
(error?.message === "Topic does not exist") and respond with 200 and
topicExists: false; update the logic around topicExists, result, and the catch
block to ensure only real connection failures produce the 500 error response.

}
}
};
Expand Down
7 changes: 4 additions & 3 deletions src/main/controllers/user_create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ export default {
name: 'user:create',
handler: () => async (req: Request, res: Response, next: NextFunction) => {
try {
const apiId = _.get(req, ['body', 'id']);
const userRequest = _.get(req, ['body', 'request']);
const isOwner = _.get(req, ['session', 'userDetails', 'is_owner']);

res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
if (!isOwner && userRequest?.roles?.includes('admin')) {
return res.status(403).json({
error: 'Only an owner can assign the admin role'
Expand All @@ -28,10 +29,10 @@ export default {
const keycloakToken = JSON.parse(req?.session['keycloak-token']);
const access_token = keycloakToken.access_token;
const result = await userCreateWithKeycloak(access_token, userRequest);
res.status(200).json(transform({ id: req.body.id, result: { id: result.id, user_name: result.user_name, email_address: result.email_address } }));
res.status(200).json(transform({ id: apiId, result: { id: result.id, user_name: result.user_name } }));
} else if (authenticationType === 'basic') {
const result = await userCreateAsBasic(userRequest);
res.status(200).json(transform({ id: req.body.id, result: { id: result.id, user_name: result.user_name, email_address: result.email_address } }));
res.status(200).json(transform({ id: apiId, result: { id: result.id, user_name: result.user_name } }));
}
} catch (error) {
next(error);
Expand Down
4 changes: 3 additions & 1 deletion src/main/controllers/user_list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export default {
name: 'user:list',
handler: () => async (request: Request, response: Response, next: NextFunction) => {
try {
const apiId = _.get(request, ['body', 'id']);
const user = _.get(request, ['body', 'request']);
const result = await userService.findAll(user);

Expand All @@ -16,7 +17,8 @@ export default {
});

const responseData = { data: usersList, count: _.size(usersList) };
response.status(200).json(transform({ id: request.body.id, result: responseData }));
response.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
response.status(200).json(transform({ id: apiId, result: responseData }));
} catch (error) {
if (error === 'user_not_found') {
const err = new Error('User not found');
Expand Down
2 changes: 2 additions & 0 deletions src/main/controllers/user_manage_roles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export default {
updated_by: userId,
},
);
res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
res.status(200).json(transform({ id: req.body.id, result: { id: result.id, user_name: result.user_name, roles: result.roles } }));
} catch (error) {
if (error === 'user_not_found') {
Expand All @@ -47,6 +48,7 @@ export default {
} else {
const e = error as Error;
if (e.message && (e.message.includes('Only the owner can modify the admin role'))) {
res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
return res.status(403).json({ error: e.message });
}
next(error);
Expand Down
2 changes: 1 addition & 1 deletion src/main/controllers/user_manage_status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export default {
const user = await userService.find({ user_name });

const hasAdminRole = user?.roles.includes('admin');

res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
if (hasAdminRole && !isOwner) {
return res.status(403).json({
error: 'Only the owner can change the status of an admin user'
Expand Down
5 changes: 4 additions & 1 deletion src/main/controllers/user_read.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ const getUserDetails = function (request: Request) {
};
return userDetails;
} else if (authenticationType === 'keycloak') {
const keycloakToken = JSON.parse(request?.session['keycloak-token']);
const sessionToken = _.get(request, ['session','keycloak-token']);
const keycloakToken = typeof sessionToken === 'string' ? JSON.parse(sessionToken) : sessionToken;
const access_token = keycloakToken?.access_token;
const preferred_username = request?.session?.preferred_username;
const userDetails = {
Expand All @@ -36,6 +37,7 @@ export default {
const sessionUserName = sessionUserDetails?.sessionUserName;
const user = await userService.find({ user_name: sessionUserName });
const { password, ...userInfo } = user;

const responseData = {
id: 'api.user.read',
result: userInfo,
Expand All @@ -45,6 +47,7 @@ export default {
if (includeToken) {
responseData.result.token = sessionUserDetails?.token;
}
response.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
response.status(200).json(transform(responseData));
} catch (error) {
next(error);
Expand Down
3 changes: 2 additions & 1 deletion src/main/controllers/user_update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ export default {
const { user_name, ...updateInfo } = _.get(req, ['body', 'request']);
const sessionUserName = _.get(req, ['session', 'userDetails', 'user_name']);
const userId = _.get(req, ['session', 'userDetails', 'id']);
res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
if (user_name !== sessionUserName) {
res.status(403).json(
return res.status(403).json(
transform({
responseCode: 'FORBIDDEN',
params: {
Expand Down
1 change: 1 addition & 0 deletions src/main/helpers/proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const authenticationType = appConfig.AUTHENTICATION_TYPE;

export const onError = ({ entity }: any) => (err: any, req: Request, res: Response) => {
incrementFailedApiCalls({ entity, endpoint: req.url });
res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
res.status(500).send('Something went wrong. Please try again later.');
}

Expand Down
1 change: 1 addition & 0 deletions src/main/middlewares/authorization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export default {
if (hasAccess) {
next();
} else {
res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
res.status(403).json(
transform({
params: {
Expand Down
1 change: 1 addition & 0 deletions src/main/services/keycloakAuthProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export class KeycloakAuthProvider implements BaseAuthProvider {
deauthenticated(req);
} catch (error) {
console.error('Logout error:', error);
res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
res.status(500).send('Logout failed');
}
}
Expand Down
15 changes: 0 additions & 15 deletions src/main/services/oauthUsers.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,3 @@

// const service = {
// async find(data: any): Promise<any> {
// const users = await find(table, data)
// if (users.length > 0) {
// return Promise.resolve(users[0])
// }
// return Promise.reject('user_not_found')
// },
// async create(userInfo: User): Promise<any> {
// const user = await insert(table, userInfo);
// return user;
// }
// }

import { getFind, getSave, getUpdate, getFindAll} from "./oauthHelper";

const table = "oauth_users";
Expand Down
1 change: 1 addition & 0 deletions src/shared/middlewares/globalErrorHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export default {
} = error;

const { id = 'api' } = request.responsePayload || {};
response.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
logger.error(error)
if (request.url.includes("oauth/v1/login")) {
return response.redirect(`${appConfig.BASE_URL}/login?err=Invalid Credentials`);
Expand Down
Loading
Loading