diff --git a/.circleci/config.yml b/.circleci/config.yml
index 621db64129..b813779aa7 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
@@ -73,7 +73,7 @@ jobs:
command: |
source awsenvconf
source buildenvvar
- ./master_deploy.sh -d ECS -e DEV -t latest -s dev_communityapp_taskvar -i communityapp
+ ./master_deploy.sh -d ECS -e DEV -t latest -s dev_communityapp_taskvar -i communityapp -p FARGATE
# Build & Deploy against testing backend
# "build-test":
@@ -224,7 +224,7 @@ jobs:
command: |
source awsenvconf
source buildenvvar
- ./master_deploy.sh -d ECS -e PROD -t latest -s prod_communityapp_taskvar -i communityapp
+ ./master_deploy.sh -d ECS -e PROD -t latest -s prod_communityapp_taskvar -i communityapp -p FARGATE
curl --request POST \
--url https://circleci.com/api/v2/project/github/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME/pipeline \
--header "Circle-Token: ${CIRCLE_TOKEN}" \
@@ -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:
@@ -360,6 +360,7 @@ workflows:
- develop
- TOP-1390
- PM-191-2
+ - pm-199
# 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/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/components/Settings/Account/__snapshots__/index.jsx.snap b/__tests__/shared/components/Settings/Account/__snapshots__/index.jsx.snap
deleted file mode 100644
index 207666379e..0000000000
--- a/__tests__/shared/components/Settings/Account/__snapshots__/index.jsx.snap
+++ /dev/null
@@ -1,2132 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`renders account setting page correctly 1`] = `
-
- Account information & Security
-
-
- <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.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..3ee3671a78 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 => [
`