Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Analyze-1468] Add d2e-webapi function logic #663

Draft
wants to merge 25 commits into
base: develop
Choose a base branch
from

Conversation

brandantck
Copy link
Contributor

@brandantck brandantck commented Feb 11, 2025

  • resolves: https://github.com/data2evidence/internal/issues/1468

  • analytics-svc

    • Update rename cohort definition to `update cohort definition
  • terminology-svc

    • Add new endpoint resolveConceptSetExpression to get included concepts for a list of concept ids for webapi, reusing logic from included-concepts endpoint.
  • d2e-webapi

    • Add preHandler to expect token and datasetid to be in request headers.
    • Add logic for most routes except conceptset, and endpoints requiring more complicated webapi logic, e.g /check, /sql.

Followup tasks:

Merge Checklist

Please cross check this list if additions / modifications needs to be done on top of your core changes and tick them off. Reviewer can as well glance through and help the developer if something is missed out.

  • Automated Tests (Jasmine integration tests, Unit tests, and/or Performance tests)
  • Updated Manual tests / Demo Config
  • Documentation (Application guide, Admin guide, Markdown, Readme and/or Wiki)
  • Verified that local development environment is working with latest changes (integrated with latest develop branch)
  • following best practices in code review doc

@brandantck brandantck marked this pull request as ready for review February 12, 2025 07:28
@brandantck brandantck requested review from a team as code owners February 12, 2025 07:28
@brandantck brandantck marked this pull request as draft February 12, 2025 09:35
@brandantck brandantck marked this pull request as ready for review February 14, 2025 08:17
@brandantck brandantck marked this pull request as draft February 18, 2025 07:41
params.append("datasetId", datasetId);

const url = `${this.baseURL}/user-artifact/${UserArtifactServiceNames.ATLAS_COHORT_DEFINITIONS}/${atlasCohortDefinitionId}`;
const result = await axios.get(url, { params, ...options });

Check failure

Code scanning / CodeQL

Server-side request forgery Critical

The
URL
of this request depends on a
user-provided value
.

Copilot Autofix AI 2 days ago

To fix the SSRF vulnerability, we need to validate and sanitize the atlasCohortDefinitionId before using it in the URL. Since atlasCohortDefinitionId is expected to be a number, we can ensure it is a valid number and within an acceptable range. Additionally, we should use a more secure method to construct the URL, ensuring that only valid and expected paths are used.

  1. Validate the atlasCohortDefinitionId to ensure it is a positive integer.
  2. Construct the URL using a template string with validated parameters.
Suggested changeset 1
functions/d2e-webapi/src/api/PortalServerAPI.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/functions/d2e-webapi/src/api/PortalServerAPI.ts b/functions/d2e-webapi/src/api/PortalServerAPI.ts
--- a/functions/d2e-webapi/src/api/PortalServerAPI.ts
+++ b/functions/d2e-webapi/src/api/PortalServerAPI.ts
@@ -74,2 +74,5 @@
   ): Promise<IUserArtifactAtlasCohortDefinitionDto> {
+    if (!Number.isInteger(atlasCohortDefinitionId) || atlasCohortDefinitionId <= 0) {
+      throw new Error("Invalid atlasCohortDefinitionId");
+    }
     try {
EOF
@@ -74,2 +74,5 @@
): Promise<IUserArtifactAtlasCohortDefinitionDto> {
if (!Number.isInteger(atlasCohortDefinitionId) || atlasCohortDefinitionId <= 0) {
throw new Error("Invalid atlasCohortDefinitionId");
}
try {
Copilot is powered by AI and may make mistakes. Always verify output.
Positive Feedback
Negative Feedback

Provide additional feedback

Please help us improve GitHub Copilot by sharing more details about this comment.

Please select one or more of the options
order by
CONCEPT_NAME ASC
`;
const result = await client.query(sql);

Check failure

Code scanning / CodeQL

Database query built from user-controlled sources High

This query string depends on a
user-provided value
.

Copilot Autofix AI 2 days ago

To fix the problem, we need to ensure that user input is safely embedded into the SQL query. Since the current database does not support array SQL parameter types, we can manually construct the query with placeholders for each element in the searchConceptIds array and then pass the values as parameters.

  1. Modify the getConceptsFromIdentifiers method in functions/d2e-webapi/src/dao/cachedb.dao.ts to construct the query with placeholders.
  2. Pass the searchConceptIds array elements as parameters to the query.
Suggested changeset 1
functions/d2e-webapi/src/dao/cachedb.dao.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/functions/d2e-webapi/src/dao/cachedb.dao.ts b/functions/d2e-webapi/src/dao/cachedb.dao.ts
--- a/functions/d2e-webapi/src/dao/cachedb.dao.ts
+++ b/functions/d2e-webapi/src/dao/cachedb.dao.ts
@@ -59,2 +59,3 @@
 
+      const placeholders = searchConceptIds.map((_, index) => `$${index + 1}`).join(", ");
       const sql = `
@@ -74,3 +75,3 @@
                 where
-                      CONCEPT_ID in (${searchConceptIds.join(", ")})
+                      CONCEPT_ID in (${placeholders})
                 order by
@@ -78,3 +79,3 @@
             `;
-      const result = await client.query(sql);
+      const result = await client.query(sql, searchConceptIds);
       return result.rows;
EOF
@@ -59,2 +59,3 @@

const placeholders = searchConceptIds.map((_, index) => `$${index + 1}`).join(", ");
const sql = `
@@ -74,3 +75,3 @@
where
CONCEPT_ID in (${searchConceptIds.join(", ")})
CONCEPT_ID in (${placeholders})
order by
@@ -78,3 +79,3 @@
`;
const result = await client.query(sql);
const result = await client.query(sql, searchConceptIds);
return result.rows;
Copilot is powered by AI and may make mistakes. Always verify output.
Positive Feedback
Negative Feedback

Provide additional feedback

Please help us improve GitHub Copilot by sharing more details about this comment.

Please select one or more of the options
", "
)}) and descendant_concept_id in (${descendants.join(", ")});
`;
const result = await client.query(sql);

Check failure

Code scanning / CodeQL

Database query built from user-controlled sources High

This query string depends on a
user-provided value
.

Copilot Autofix AI 2 days ago

To fix the problem, we need to ensure that user-provided values are safely embedded into SQL queries. Since the current database does not support array SQL parameter types, we can use a combination of query parameterization for individual values and validation to ensure the integrity of the data.

  1. Validation: Ensure that the user-provided values (ancestors and descendants) are arrays of numbers and do not contain any malicious content.
  2. Query Construction: Construct the SQL query using parameterized queries for individual values to prevent SQL injection.
Suggested changeset 1
functions/d2e-webapi/src/dao/cachedb.dao.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/functions/d2e-webapi/src/dao/cachedb.dao.ts b/functions/d2e-webapi/src/dao/cachedb.dao.ts
--- a/functions/d2e-webapi/src/dao/cachedb.dao.ts
+++ b/functions/d2e-webapi/src/dao/cachedb.dao.ts
@@ -95,5 +95,13 @@
     try {
-      // TODO: Move ancestors and descendants as a sql parameter instead of being in the sql statement itself.
-      // ancestors and descendants has to be in sql statement now as cachedb does not support array sql parameter types
-      // https://github.com/alp-os/internal/issues/1411
+      // Validate ancestors and descendants to ensure they are arrays of numbers
+      if (!Array.isArray(ancestors) || !ancestors.every(Number.isInteger)) {
+        throw new Error("Invalid ancestors array");
+      }
+      if (!Array.isArray(descendants) || !descendants.every(Number.isInteger)) {
+        throw new Error("Invalid descendants array");
+      }
+
+      // Construct the SQL query using parameterized queries for individual values
+      const ancestorParams = ancestors.map((_, i) => `$${i + 1}`).join(", ");
+      const descendantParams = descendants.map((_, i) => `$${i + ancestors.length + 1}`).join(", ");
       const sql = `
@@ -101,7 +109,5 @@
             from ${vocabSchemaName}.concept_ancestor
-            where ancestor_concept_id in (${ancestors.join(
-              ", "
-            )}) and descendant_concept_id in (${descendants.join(", ")});
+            where ancestor_concept_id in (${ancestorParams}) and descendant_concept_id in (${descendantParams});
             `;
-      const result = await client.query(sql);
+      const result = await client.query(sql, [...ancestors, ...descendants]);
       return result.rows;
EOF
@@ -95,5 +95,13 @@
try {
// TODO: Move ancestors and descendants as a sql parameter instead of being in the sql statement itself.
// ancestors and descendants has to be in sql statement now as cachedb does not support array sql parameter types
// https://github.com/alp-os/internal/issues/1411
// Validate ancestors and descendants to ensure they are arrays of numbers
if (!Array.isArray(ancestors) || !ancestors.every(Number.isInteger)) {
throw new Error("Invalid ancestors array");
}
if (!Array.isArray(descendants) || !descendants.every(Number.isInteger)) {
throw new Error("Invalid descendants array");
}

// Construct the SQL query using parameterized queries for individual values
const ancestorParams = ancestors.map((_, i) => `$${i + 1}`).join(", ");
const descendantParams = descendants.map((_, i) => `$${i + ancestors.length + 1}`).join(", ");
const sql = `
@@ -101,7 +109,5 @@
from ${vocabSchemaName}.concept_ancestor
where ancestor_concept_id in (${ancestors.join(
", "
)}) and descendant_concept_id in (${descendants.join(", ")});
where ancestor_concept_id in (${ancestorParams}) and descendant_concept_id in (${descendantParams});
`;
const result = await client.query(sql);
const result = await client.query(sql, [...ancestors, ...descendants]);
return result.rows;
Copilot is powered by AI and may make mistakes. Always verify output.
Positive Feedback
Negative Feedback

Provide additional feedback

Please help us improve GitHub Copilot by sharing more details about this comment.

Please select one or more of the options
", "
)});
`;
const result = await client.query(sql);

Check failure

Code scanning / CodeQL

Database query built from user-controlled sources High

This query string depends on a
user-provided value
.

Copilot Autofix AI 2 days ago

To fix the problem, we need to ensure that user-provided data is safely embedded into the SQL query. Since the current database does not support array SQL parameter types, we can use a library like sqlstring to escape the user input before embedding it into the query string. This will prevent SQL injection attacks by ensuring that the user input is treated as a literal value.

  1. Import the sqlstring library.
  2. Use sqlstring.escape to escape the user-provided data before embedding it into the SQL query string.
Suggested changeset 2
functions/d2e-webapi/src/dao/cachedb.dao.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/functions/d2e-webapi/src/dao/cachedb.dao.ts b/functions/d2e-webapi/src/dao/cachedb.dao.ts
--- a/functions/d2e-webapi/src/dao/cachedb.dao.ts
+++ b/functions/d2e-webapi/src/dao/cachedb.dao.ts
@@ -2,2 +2,3 @@
 import pg from "pg";
+import SqlString from "sqlstring";
 import {
@@ -124,6 +125,5 @@
       // https://github.com/alp-os/internal/issues/1411
+      const escapedConceptIds = searchConceptIds.map(id => SqlString.escape(id)).join(", ");
       const sql = `
-          select concept_id_1, concept_id_2, relationship_id from ${vocabSchemaName}.concept_recommended WHERE concept_id_1 IN (${searchConceptIds.join(
-        ", "
-      )});
+          select concept_id_1, concept_id_2, relationship_id from ${vocabSchemaName}.concept_recommended WHERE concept_id_1 IN (${escapedConceptIds});
               `;
@@ -152,2 +152,3 @@
       // https://github.com/alp-os/internal/issues/1411
+      const escapedConceptIds = conceptIds.map(id => SqlString.escape(id)).join(", ");
       const sql = `
@@ -156,3 +157,3 @@
           WHERE
-          concept_id IN (${conceptIds.join(", ")})
+          concept_id IN (${escapedConceptIds})
           ${invalidReasonWhereClause}
EOF
@@ -2,2 +2,3 @@
import pg from "pg";
import SqlString from "sqlstring";
import {
@@ -124,6 +125,5 @@
// https://github.com/alp-os/internal/issues/1411
const escapedConceptIds = searchConceptIds.map(id => SqlString.escape(id)).join(", ");
const sql = `
select concept_id_1, concept_id_2, relationship_id from ${vocabSchemaName}.concept_recommended WHERE concept_id_1 IN (${searchConceptIds.join(
", "
)});
select concept_id_1, concept_id_2, relationship_id from ${vocabSchemaName}.concept_recommended WHERE concept_id_1 IN (${escapedConceptIds});
`;
@@ -152,2 +152,3 @@
// https://github.com/alp-os/internal/issues/1411
const escapedConceptIds = conceptIds.map(id => SqlString.escape(id)).join(", ");
const sql = `
@@ -156,3 +157,3 @@
WHERE
concept_id IN (${conceptIds.join(", ")})
concept_id IN (${escapedConceptIds})
${invalidReasonWhereClause}
functions/package.json
Outside changed files

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/functions/package.json b/functions/package.json
--- a/functions/package.json
+++ b/functions/package.json
@@ -2264,2 +2264,5 @@
     }
+  },
+  "dependencies": {
+    "sqlstring": "^2.3.3"
   }
EOF
@@ -2264,2 +2264,5 @@
}
},
"dependencies": {
"sqlstring": "^2.3.3"
}
This fix introduces these dependencies
Package Version Security advisories
sqlstring (npm) 2.3.3 None
Copilot is powered by AI and may make mistakes. Always verify output.
Positive Feedback
Negative Feedback

Provide additional feedback

Please help us improve GitHub Copilot by sharing more details about this comment.

Please select one or more of the options
order by domain_id, vocabulary_id;
`;

const result = await client.query<ICachedbConcept>(sql);

Check failure

Code scanning / CodeQL

Database query built from user-controlled sources High

This query string depends on a
user-provided value
.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant