diff --git a/.circleci/config.yml b/.circleci/config.yml index 87ea798835..0f77a5da75 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -33,10 +33,10 @@ install_deploysuite: &install_deploysuite cp ./../buildscript/buildenv.sh . cp ./../buildscript/awsconfiguration.sh . restore_cache_settings_for_build: &restore_cache_settings_for_build - key: docker-node-modules-v3-{{ checksum "package-lock.json" }} + key: docker-node-modules-v4-{{ checksum "package-lock.json" }} save_cache_settings: &save_cache_settings - key: docker-node-modules-v3-{{ checksum "package-lock.json" }} + key: docker-node-modules-v4-{{ checksum "package-lock.json" }} paths: - node_modules @@ -260,37 +260,37 @@ jobs: # path: ./automated-smoke-test/test-results # Automated Smoke Testing against Production - Smoke-Testing-On-Production: - <<: *defaults - steps: - # Initialization. - - checkout - - setup_remote_docker - - run: *install_dependency - - run: *install_deploysuite - # Restoration of node_modules from cache. - - restore_cache: *restore_cache_settings_for_build - - run: - name: "configuring environment" - command: | - ./awsconfiguration.sh PROD - ./buildenv.sh -e PROD -b prod_communityapp_buildvar,prod_communityapp_deployvar - - run: - name: "Run automation" - no_output_timeout: 20m - command: | - source awsenvconf - source buildenvvar - ./automated-smoke-test/smoketest.sh automation-config-prod.json prod - - store_artifacts: - path: ./automated-smoke-test/test-results + # Smoke-Testing-On-Production: + # <<: *defaults + # steps: + # # Initialization. + # - checkout + # - setup_remote_docker + # - run: *install_dependency + # - run: *install_deploysuite + # # Restoration of node_modules from cache. + # - restore_cache: *restore_cache_settings_for_build + # - run: + # name: "configuring environment" + # command: | + # ./awsconfiguration.sh PROD + # ./buildenv.sh -e PROD -b prod_communityapp_buildvar,prod_communityapp_deployvar + # - run: + # name: "Run automation" + # no_output_timeout: 20m + # command: | + # source awsenvconf + # source buildenvvar + # ./automated-smoke-test/smoketest.sh automation-config-prod.json prod + # - store_artifacts: + # path: ./automated-smoke-test/test-results # Test job for the cases when we do not need deployment. It just rapidly # installs (updates) app dependencies, and runs tests (ESLint, Stylelint, # Jest unit-tests). test: docker: - - image: circleci/node:8.11.1 + - image: circleci/node:10.24.1 steps: - checkout - restore_cache: @@ -358,8 +358,6 @@ workflows: branches: only: - develop - - TOP-1390 - - PM-191-2 # This is alternate dev env for parallel testing # Deprecate this workflow due to beta env shutdown # https://topcoder.atlassian.net/browse/CORE-251 diff --git a/.nvmrc b/.nvmrc index af557cc054..c8b7cbff70 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v8.11.2 +v10.24.1 diff --git a/Dockerfile b/Dockerfile index 7691feebdc..0e7f8c6e2c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,12 +2,16 @@ # and runs it against the specified Topcoder backend (development or # production) when container is executed. -FROM node:8.11.2 +FROM node:10.24.1 LABEL app="Community App" version="1.0" +RUN useradd -m -s /bin/bash appuser WORKDIR /opt/app COPY . . +RUN chown -R appuser:appuser /opt/app +USER appuser + ################################################################################ # Receiving of build arguments. diff --git a/__tests__/shared/__snapshots__/index.jsx.snap b/__tests__/shared/__snapshots__/index.jsx.snap deleted file mode 100644 index 2069cbf96f..0000000000 --- a/__tests__/shared/__snapshots__/index.jsx.snap +++ /dev/null @@ -1,87 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Snapshot match 1`] = ` -
- <code goes here>
+ <code>
@@ -1294,7 +1294,7 @@ end tell
ampersands and angle brackets. For example, this:
,
- <div class="footer">
+ <div>
© 2004 Foo Corporation
</div>
diff --git a/automated-smoke-test/Dockerfile b/automated-smoke-test/Dockerfile
deleted file mode 100644
index b228769e64..0000000000
--- a/automated-smoke-test/Dockerfile
+++ /dev/null
@@ -1,32 +0,0 @@
-FROM node:10.17.0-stretch
-RUN apt update
-RUN apt install sudo
-RUN sudo apt-get update; sudo apt-get install -y openjdk-8-jre openjdk-8-jre-headless openjdk-8-jdk openjdk-8-jdk-headless;
-RUN curl --silent --show-error --location --fail --retry 3 --output /tmp/google-chrome-stable_current_amd64.deb https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb \
- && (sudo dpkg -i /tmp/google-chrome-stable_current_amd64.deb || sudo apt-get -fy install) \
- && rm -rf /tmp/google-chrome-stable_current_amd64.deb \
- && sudo sed -i 's|HERE/chrome"|HERE/chrome" --disable-setuid-sandbox --no-sandbox|g' \
- "/opt/google/chrome/google-chrome" \
- && google-chrome --version
-RUN export CHROMEDRIVER_RELEASE=$(curl --location --fail --retry 3 http://chromedriver.storage.googleapis.com/LATEST_RELEASE) \
- && curl --silent --show-error --location --fail --retry 3 --output /tmp/chromedriver_linux64.zip "http://chromedriver.storage.googleapis.com/$CHROMEDRIVER_RELEASE/chromedriver_linux64.zip" \
- && cd /tmp \
- && unzip chromedriver_linux64.zip \
- && rm -rf chromedriver_linux64.zip \
- && sudo mv chromedriver /usr/local/bin/chromedriver \
- && sudo chmod +x /usr/local/bin/chromedriver \
- && chromedriver --version
-RUN sudo apt-get install -y libgconf-2-4
-RUN sudo apt-get install -y xvfb
-RUN sudo apt-get install -y jq
-ENV DISPLAY :99
-RUN printf '#!/bin/sh\nXvfb :99 -screen 0 1280x1024x24 &\nexec "$@"\n' > /tmp/entrypoint \
- && chmod +x /tmp/entrypoint \
- && sudo mv /tmp/entrypoint /docker-entrypoint.sh
-
-COPY . /automated-smoke-test
-WORKDIR /automated-smoke-test
-RUN npm install
-RUN ./node_modules/.bin/webdriver-manager update --versions.chrome=="$(google-chrome -version)"
-ENTRYPOINT ["/docker-entrypoint.sh"]
-CMD ["/bin/sh"]
\ No newline at end of file
diff --git a/automated-smoke-test/config/automation-config-dev.json b/automated-smoke-test/config/automation-config-dev.json
index 4df4b85ad3..9ac9bf711d 100644
--- a/automated-smoke-test/config/automation-config-dev.json
+++ b/automated-smoke-test/config/automation-config-dev.json
@@ -86,7 +86,6 @@
"allNotificationsUrl": "https://community-app.topcoder-dev.com/notifications",
"policiesUrl": "https://community-app.topcoder-dev.com/policy",
"username": "tester1234",
- "password": "appirio123",
"email": "sathya.jayabal@gmail.com",
"challangesLinks": {
"rssFeedUrl": "http://feeds.topcoder-dev.com/challenges/feed",
diff --git a/automated-smoke-test/config/automation-config-local.json b/automated-smoke-test/config/automation-config-local.json
index 79f61ba285..c2ca342f56 100644
--- a/automated-smoke-test/config/automation-config-local.json
+++ b/automated-smoke-test/config/automation-config-local.json
@@ -81,7 +81,6 @@
"allNotificationsUrl": "http://localhost:3000/notifications",
"policiesUrl": "http://localhost:3000/policy",
"username": "Tonyj",
- "password": "appirio123",
"email": "topcoderconnect@gmail.com",
"challangesLinks": {
"rssFeedUrl": "http://feeds.topcoder.com/challenges/feed",
diff --git a/automated-smoke-test/config/automation-config-prod.json b/automated-smoke-test/config/automation-config-prod.json
index ed2fc420de..d05c56008c 100644
--- a/automated-smoke-test/config/automation-config-prod.json
+++ b/automated-smoke-test/config/automation-config-prod.json
@@ -81,7 +81,6 @@
"allNotificationsUrl": "https://www.topcoder.com/notifications",
"policiesUrl": "https://www.topcoder.com/policy",
"username": "CustomerUser",
- "password": "appirio123",
"email": "topcoderconnect@gmail.com",
"challangesLinks": {
"rssFeedUrl": "http://feeds.topcoder.com/challenges/feed",
diff --git a/automated-smoke-test/test-data/test-data.json b/automated-smoke-test/test-data/test-data.json
index 02aa602405..98fcf8a0bc 100644
--- a/automated-smoke-test/test-data/test-data.json
+++ b/automated-smoke-test/test-data/test-data.json
@@ -1,7 +1,6 @@
{
"login": {
- "invalidUsername": "gjhhvv",
- "invalidPassword": "invalidpassword"
+ "invalidUsername": "gjhhvv"
},
"tools": {
"subscription": "Sample A",
diff --git a/config/default.js b/config/default.js
index e30ec05227..f5424d3504 100644
--- a/config/default.js
+++ b/config/default.js
@@ -132,8 +132,8 @@ module.exports = {
INFO: {
DESIGN_CHALLENGES: 'http://help.topcoder.com/hc/en-us/categories/202610437-DESIGN',
DESIGN_CHALLENGE_CHECKPOINTS: 'https://help.topcoder.com/hc/en-us/articles/219240807-Multi-Round-Checkpoint-Design-Challenges',
- DESIGN_CHALLENGE_SUBMISSION: 'http://help.topcoder.com/hc/en-us/articles/219122667-Formatting-Your-Submission-for-Design-Challenges',
- DESIGN_CHALLENGE_TYPES: 'http://help.topcoder.com/hc/en-us/articles/217481388-Choosing-a-Design-Challenge',
+ DESIGN_CHALLENGE_SUBMISSION: 'https://www.topcoder.com/thrive/articles/Formatting%20Your%20Submission%20for%20Design%20Challenges',
+ DESIGN_CHALLENGE_TYPES: 'https://www.topcoder.com/thrive/articles/How%20To%20Compete%20in%20Design',
RELIABILITY_RATINGS_AND_BONUSES: 'https://www.topcoder.com/thrive/articles/Development%20Reliability%20Ratings%20and%20Bonuses',
STOCK_ART_POLICY: 'http://help.topcoder.com/hc/en-us/articles/217481408-Policy-for-Stock-Artwork-in-Design-Submissions',
STUDIO_FONTS_POLICY:
diff --git a/docs/contentful/AppComponent.md b/docs/contentful/AppComponent.md
index 12c3980e17..a937f7b942 100644
--- a/docs/contentful/AppComponent.md
+++ b/docs/contentful/AppComponent.md
@@ -46,8 +46,6 @@ Render top spots and list of competitors on specific TCO track.
A block that fetches and renders a job listing page driven by recruitCRM.
-### Type = `EmailSubscribeForm`
-
Generic subscribe for MailChimp tags component.
- **listId** | **String (Required).**
diff --git a/docs/contentful/custom-inline-components-in-markdown-fields.md b/docs/contentful/custom-inline-components-in-markdown-fields.md
index da252c165b..4961ffe946 100644
--- a/docs/contentful/custom-inline-components-in-markdown-fields.md
+++ b/docs/contentful/custom-inline-components-in-markdown-fields.md
@@ -69,22 +69,6 @@ other types too.
| listId | | ID of MailChimp list to subscribe. |
| interests | empty string | Optional. commas separated string of group ids to which user should be subscribed |
-- #### NewsletterSignupForMembers
- **Sample use:** ` `
-
- Renders a newsletter signup button that takes user email from his profile
- information. If the user is not-authenticated, it gets him to the login or
- registration page, and subscribes him on return. Accepts the following props:
-
- | Param | Default | Description |
- | --- | --- | --- |
- | label | Subscribe for Newsletter | Optional. Custom label to show on the button. |
- | listId | | ID of MailChimp list to subscribe. |
- | tags | | ID of MailChimp tags to subscribe. |
- | buttonTheme | primary-green-md | Theme key(`tc-` is omitted) for the button. See https://community-app.topcoder.com/examples/contentful/contentblock/3k7k1JpnSvIRrJYWs4izYi |
- | title | Sign up for the Topcoder Newsletter | Modal title |
- | desc | Do you want to subscribe to this newsletter? | Modal description |
-
- #### VideoModalButton
*Example:* ` `
@@ -98,14 +82,6 @@ other types too.
component works only with YouTube videos, and the URL should be similar to
`https://www.youtube.com/embed/mD12LIqdxqk` ().
-- #### NewsletterArchive
- *Example:* ` `
-
- A list of archive links sorted by descending `sent_date` from a MailChimp's campaign folder. Sould be working under any MarkdownParser component.
-
- The properties are:
- - `name` - the unique name of the camplaing foler. It has to be only one name entity. If those duplicate first found will be picked up and rest ignored.
-
## Links
- #### Link
diff --git a/docs/pwa/nginx/server.key b/docs/pwa/nginx/server.key
deleted file mode 100644
index 3e46bd6691..0000000000
--- a/docs/pwa/nginx/server.key
+++ /dev/null
@@ -1,28 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDXKekFdnLsjrnq
-4RMF/V6ewrDRwzt9gVJXX8aEemq5wDjrnK1q2SJBrEMQw72T1oIt8TJs+d6HLc0K
-DX3MILdix/r/+ML5bVjTd6HdzqXnbsd9omvZ3a43QKLxGCvqwe0iN8C7106++nik
-3issH6qiQh5p5ERN8gApSyj0/PIu051YCNL8SpsqDiRHtWzZt07ncPFPueINXdRu
-AEb7pod7tIvBnI2kudJx4d2AX+lE7eOhsvCr0eHS3/V03BlprAt3qw7c2ZwLxTYZ
-D/l6NgCoy6AQfq9d7XikTVFx9ZKiuCPVS11PzI6G2pbx5Y6ewHdcfLnPVIDKPfMh
-L3SjmDTNAgMBAAECggEAOLf3kVUUHn/RSrViSmXsF3XDHsiUWhVJG3dH4YxTrfua
-BaIbpNrwSNecJkMzKlGVp365iDimDIRqVIgR7UmCjiuhYvC0lQPaMoSKyum6mjN9
-qwSx4ZCqaC5FxcBVc2EDnc2MpPew7m8gdnWKc+s1E+jSE5/00YdFu5zwgwRa4zSx
-TquwlMGd6AcE1J5YbxYGJRztAl2VKguBJFcSnnFef8xY18GoEO1lt43ef9ijsfL3
-mBccrlLWQmc1CxM8zZ83lD1yW41bcwMhx7XCgRZjhDtNmbyWWJOYoFwojtAxFqG4
-VHFKjY+kNgIWjKZim84GA3tUPS/L832GXYk6SyC6kQKBgQD/HsnCryGTaitjwn+5
-FbPWlBnnGn1hxE36g0u1B3A/mQ3Jut949Dsm9vEoS1gHOQBCc5cE3RXNZ6iZdSDc
-Lf9YzZnchIgjauU9bqkZVI2RSPnNOTjWjXhGtrZxrc4eckRWqbChmYX0qCxokwhb
-leIdmJy7Y0Q6ttVGAHySoC/h7wKBgQDX59mKR1Gm7rKcEqW2aWhz878Xft/OHchh
-THF9EUGHWXOYiKDAPxV6+xg2ZZaPUorMdp588iC3dd0YRn/KSkFlYWIgA8yYkjI7
-Al6pwGgOPw8k2/t1Rxfw2NUJr/19dAqMSyxDZ6W1OsGsdoAIgOMQxx12zENZpX6y
-xcewsWNhAwKBgQC33vbHa/WlC4YONmZbfTrKUp+AouTvC86v2OU9qgjKrYL0e80I
-ne3sHVqeEf915S08t5aGmNlX23f2ciamyjgZRsW324VLEYX7CsCxUvFdXt07fhxq
-9jdTr+g6cmv2IaEDXPXC4qVbOcIX9LC3YYVAk3eSzu6j6pY4B63A99bK3QKBgQDE
-d/mQiGe4BVxJA/sB7Bed9D9+7PhSAu4WBE79pVdBCFhVhHbrmjw8xgN5dKY2U8F0
-X7jHMDovWDTSY0zkUwABdkWppmtmpxrIcdacmDbYR+/K9dd0GDaj91ydTSXaJF94
-3Osxhz7WlNoqy0ak9kwqN1cLhMMA78VEfw/BLRqm6wKBgGUZNlOXQjcAcFjZ12Z4
-3X3tOWjwAPx2D5kT99Jh2BDgzjOci303MDnxI+mb6BQY32mz5+2OlD+bz2qYHVPp
-9+Ir9WNbIl+DCUadRcPuYPAwPSftBEKzH901BBXHnbSkLSWocvLqYxUBjJ64KTh0
-2OTOU4OPRrct2tauUUyPRiBX
------END PRIVATE KEY-----
diff --git a/docs/swagger.yaml b/docs/swagger.yaml
deleted file mode 100644
index 19cc61f8d6..0000000000
--- a/docs/swagger.yaml
+++ /dev/null
@@ -1,196 +0,0 @@
-openapi: 3.0.0
-info:
- title: Community APP
- description: Community APP
- version: 1.0.0
-servers:
- - url: http://local.topcoder-dev.com:3000
-tags:
- - name: Profile
-paths:
- /api/recruit/profile:
- get:
- tags:
- - Profile
- description: |
- Get Profile of current user
-
- **Authorization** All topcoder members are allowed.
- security:
- - bearerAuth: []
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- type: array
- items:
- $ref: "#/components/schemas/Profile"
- "401":
- description: Not authenticated
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/AuthError"
- "403":
- description: Forbidden
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/AuthError"
- "404":
- description: Not Found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/Profile"
- "500":
- description: Internal Server Error
- content:
- text/plain::
- schema:
- type: string
- post:
- tags:
- - Profile
- description: |
- Update Profile details of current user
- **Authorization** All topcoder members are allowed.
- security:
- - bearerAuth: []
- requestBody:
- content:
- multipart/form-data:
- schema:
- $ref: "#/components/schemas/ProfileUpdate"
- responses:
- "204":
- description: OK
- "400":
- description: Bad request
- content:
- application/json:
- schema:
- oneOf:
- - $ref: "#/components/schemas/JoiError"
- - $ref: "#/components/schemas/Error"
- "401":
- description: Not authenticated
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/AuthError"
- "403":
- description: Forbidden
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/AuthError"
- "404":
- description: Not Found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/Error"
- "500":
- description: Internal Server Error
- content:
- text/plain::
- schema:
- type: string
-components:
- securitySchemes:
- bearerAuth:
- type: http
- scheme: bearer
- bearerFormat: JWT
- schemas:
- Profile:
- required:
- - availability
- properties:
- phone:
- type: string
- description: "The phone number of the user"
- example: "+1123226666"
- resume:
- type: string
- description: "The resume of the user"
- availability:
- type: boolean
- description: "The availability of the user"
- default: true
- example: true
- skill:
- type: string
- description: "The candidate's skills separated via ,"
- example: "Java,Angular,SQL Server,JavaScript"
- salaryExpectation:
- type: integer
- description: "The candidate expected salary"
- hasProfile:
- type: boolean
- description: "Whether has profile for the user"
- ProfileUpdate:
- required:
- - phone
- - availability
- - city
- - countryName
- properties:
- phone:
- type: string
- description: "The phone number of the user"
- example: "(123) 456-7890"
- city:
- type: string
- description: "The member's city"
- countryName:
- type: string
- description: "The member's country"
- resume:
- type: string
- format: binary
- description: "The resume file of the user"
- availability:
- type: boolean
- description: "The availability of the user"
- example: true
- Error:
- properties:
- error:
- type: boolean
- example: true
- status:
- type: integer
- example: 404
- url:
- type: string
- format: uri
- errObj:
- type: object
- JoiError:
- required:
- - message
- properties:
- message:
- type: string
- AuthError:
- properties:
- version:
- type: string
- result:
- type: object
- properties:
- success:
- type: boolean
- example: false
- status:
- type: integer
- example: 403
- content:
- type: object
- properties:
- message:
- type: string
diff --git a/package-lock.json b/package-lock.json
index bd250b4344..506a1627fd 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -6977,6 +6977,11 @@
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
"dev": true
},
+ "cssfilter": {
+ "version": "0.0.10",
+ "resolved": "https://registry.npmjs.org/cssfilter/-/cssfilter-0.0.10.tgz",
+ "integrity": "sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw=="
+ },
"cssnano": {
"version": "3.10.0",
"resolved": "https://registry.npmjs.org/cssnano/-/cssnano-3.10.0.tgz",
@@ -28650,6 +28655,15 @@
"resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz",
"integrity": "sha512-58Im/U0mlVBLM38NdZjHyhuMtCqa61469k2YP/AaPbvCoV9aQGUpbJBj1QRm2ytRiVQBD/fsw7L2bJGDVQswBA=="
},
+ "xss": {
+ "version": "1.0.15",
+ "resolved": "https://registry.npmjs.org/xss/-/xss-1.0.15.tgz",
+ "integrity": "sha512-FVdlVVC67WOIPvfOwhoMETV72f6GbW7aOabBC3WxN/oUdoEMDyLz4OgRv5/gck2ZeNqEQu+Tb0kloovXOfpYVg==",
+ "requires": {
+ "commander": "^2.20.3",
+ "cssfilter": "0.0.10"
+ }
+ },
"xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
diff --git a/package.json b/package.json
index 45c9302fe6..3ed6237f7a 100644
--- a/package.json
+++ b/package.json
@@ -33,8 +33,8 @@
},
"homepage": "https://github.com/topcoder-platform/community-app#readme",
"engines": {
- "node": "^8.11.2",
- "npm": "^5.6.0"
+ "node": "^10.24.1",
+ "npm": "^6.14.12"
},
"dependencies": {
"@hapi/joi": "^16.1.4",
@@ -172,7 +172,8 @@
"url-parse": "^1.4.1",
"uuid": "^3.3.2",
"valid-url": "^1.0.9",
- "xml2json": "^0.11.2"
+ "xml2json": "^0.11.2",
+ "xss": "^1.0.15"
},
"devDependencies": {
"@commitlint/cli": "^8.3.5",
diff --git a/src/server/index.js b/src/server/index.js
index 393a72b9a7..7bb01dd9c2 100644
--- a/src/server/index.js
+++ b/src/server/index.js
@@ -22,14 +22,12 @@ import { factory as reducerFactory } from 'reducers';
import { redux, server as serverFactory } from 'topcoder-react-utils';
import { getRates as getExchangeRates } from 'services/money';
import { toJson as xmlToJson } from 'utils/xml2json';
+import { promisify } from 'util';
import cdnRouter from './routes/cdn';
-import mailChimpRouter from './routes/mailchimp';
import mockDocuSignFactory from './__mocks__/docu-sign-mock';
import recruitCRMRouter from './routes/recruitCRM';
import mmLeaderboardRouter from './routes/mmLeaderboard';
-import gSheetsRouter from './routes/gSheet';
-import blogRouter from './routes/blog';
import feedsRouter from './routes/feeds';
/* Dome API for topcoder communities */
@@ -42,9 +40,40 @@ global.atob = atob;
const CMS_BASE_URL = `https://app.contentful.com/spaces/${config.SECRET.CONTENTFUL.SPACE_ID}`;
-let ts = path.resolve(__dirname, '../../.build-info');
-ts = JSON.parse(fs.readFileSync(ts));
-ts = moment(ts.timestamp).valueOf();
+const getTimestamp = async () => {
+ let timestamp;
+ try {
+ const filePath = path.resolve(__dirname, '../../.build-info');
+ if (!filePath.startsWith(path.resolve(__dirname, '../../'))) {
+ throw new Error('Invalid file path detected');
+ }
+
+ // const MAX_FILE_SIZE = 10 * 1024; // 10 KB max file size
+ // const stats = await promisify(fs.stat)(filePath);
+ // if (stats.size > MAX_FILE_SIZE) {
+ // throw new Error('File is too large and may cause DoS issues');
+ // }
+
+ const fileContent = await promisify(fs.readFile)(filePath, 'utf-8');
+
+ let tsData;
+ try {
+ tsData = JSON.parse(fileContent);
+ } catch (parseErr) {
+ throw new Error('Invalid JSON format in file');
+ }
+
+ if (!tsData || !tsData.timestamp) {
+ throw new Error('Timestamp is missing in the JSON file');
+ }
+
+ timestamp = moment(tsData.timestamp).valueOf();
+ } catch (err) {
+ console.error('Error:', err.message);
+ }
+
+ return timestamp;
+};
const sw = `sw.js${process.env.NODE_ENV === 'production' ? '' : '?debug'}`;
const swScope = '/challenges'; // we are currently only interested in improving challenges pages
@@ -52,7 +81,7 @@ const swScope = '/challenges'; // we are currently only interested in improving
const tcoPattern = new RegExp(/^tco\d{2}\.topcoder(?:-dev)?\.com$/i);
const universalNavUrl = config.UNIVERSAL_NAV_URL;
-const EXTRA_SCRIPTS = [
+const getExtraScripts = ts => [
`