diff --git a/client/index.html b/client/index.html
index e22818560..ff986837e 100644
--- a/client/index.html
+++ b/client/index.html
@@ -2,17 +2,19 @@
- <%= htmlWebpackPlugin.options.view.ctfName %>
+ {{ ctfName }}
-
-
-
+
+
+
+
+
<% preact.headEnd %>
diff --git a/client/src/api/util.js b/client/src/api/util.js
index c1387a419..70c3b5c2d 100644
--- a/client/src/api/util.js
+++ b/client/src/api/util.js
@@ -1,5 +1,5 @@
import { route } from 'preact-router'
-import config from '../../../config/client'
+import config from '../config'
export const relog = () => {
localStorage.removeItem('token')
diff --git a/client/src/components/ctftime-additional.js b/client/src/components/ctftime-additional.js
index a89e493f4..57a1a6fd9 100644
--- a/client/src/components/ctftime-additional.js
+++ b/client/src/components/ctftime-additional.js
@@ -1,5 +1,5 @@
import Form from '../components/form'
-import config from '../../../config/client'
+import config from '../config'
import withStyles from '../components/jss'
import { register } from '../api/auth'
import UserCircle from '../icons/user-circle.svg'
diff --git a/client/src/components/profile/memberscard.js b/client/src/components/profile/memberscard.js
index 959bcda6d..f788550ab 100644
--- a/client/src/components/profile/memberscard.js
+++ b/client/src/components/profile/memberscard.js
@@ -2,7 +2,7 @@ import withStyles from '../jss'
import { getMembers, addMember, removeMember } from '../../api/members'
import { updateAccount } from '../../api/profile'
import { useState, useCallback, useEffect } from 'preact/hooks'
-import config from '../../../../config/client'
+import config from '../../config'
import Form from '../form'
import { useToast } from '../toast'
diff --git a/client/src/config.js b/client/src/config.js
new file mode 100644
index 000000000..58eb52365
--- /dev/null
+++ b/client/src/config.js
@@ -0,0 +1,3 @@
+const config = JSON.parse(document.head.querySelector('meta[name="rctf-config"]').content)
+
+export default config
diff --git a/client/src/index.js b/client/src/index.js
index 2b0d2643d..893c63bb0 100644
--- a/client/src/index.js
+++ b/client/src/index.js
@@ -1,6 +1,6 @@
import { useState, useCallback } from 'preact/hooks'
import Router from 'preact-router'
-import config from '../../config/client'
+import config from './config'
import 'cirrus-ui'
import withStyles from './components/jss'
diff --git a/client/src/routes/admin/challs.js b/client/src/routes/admin/challs.js
index 1fb72db3d..ca7ccdc4c 100644
--- a/client/src/routes/admin/challs.js
+++ b/client/src/routes/admin/challs.js
@@ -1,6 +1,6 @@
import { useState, useEffect } from 'preact/hooks'
-import config from '../../../../config/client'
+import config from '../../config'
import withStyles from '../../components/jss'
import Problem from '../../components/admin/problem'
diff --git a/client/src/routes/challs.js b/client/src/routes/challs.js
index 21e1aef5a..7babf8075 100644
--- a/client/src/routes/challs.js
+++ b/client/src/routes/challs.js
@@ -1,6 +1,6 @@
import { useCallback, useState, useEffect, useMemo } from 'preact/hooks'
-import config from '../../../config/client'
+import config from '../config'
import withStyles from '../components/jss'
import Problem from '../components/problem'
diff --git a/client/src/routes/error.js b/client/src/routes/error.js
index e5b577e32..38d6b7df5 100644
--- a/client/src/routes/error.js
+++ b/client/src/routes/error.js
@@ -1,5 +1,5 @@
import { Component } from 'preact'
-import config from '../../../config/client'
+import config from '../config'
import 'linkstate/polyfill'
import withStyles from '../components/jss'
diff --git a/client/src/routes/home.js b/client/src/routes/home.js
index a048b802f..4eafbe032 100644
--- a/client/src/routes/home.js
+++ b/client/src/routes/home.js
@@ -1,5 +1,5 @@
import { Component } from 'preact'
-import config from '../../../config/client'
+import config from '../config'
import 'linkstate/polyfill'
import withStyles from '../components/jss'
diff --git a/client/src/routes/login.js b/client/src/routes/login.js
index f8e520369..8fb46aa0a 100644
--- a/client/src/routes/login.js
+++ b/client/src/routes/login.js
@@ -1,6 +1,6 @@
import { Component } from 'preact'
import Form from '../components/form'
-import config from '../../../config/client'
+import config from '../config'
import 'linkstate/polyfill'
import withStyles from '../components/jss'
diff --git a/client/src/routes/profile.js b/client/src/routes/profile.js
index c82400e95..ec6675b34 100644
--- a/client/src/routes/profile.js
+++ b/client/src/routes/profile.js
@@ -1,6 +1,6 @@
import { useState, useCallback, useEffect } from 'preact/hooks'
import { memo } from 'preact/compat'
-import config from '../../../config/client'
+import config from '../config'
import withStyles from '../components/jss'
import { privateProfile, publicProfile, deleteAccount, updateAccount, updateEmail, deleteEmail } from '../api/profile'
diff --git a/client/src/routes/registration.js b/client/src/routes/registration.js
index 7b2ca9116..3aff77a8e 100644
--- a/client/src/routes/registration.js
+++ b/client/src/routes/registration.js
@@ -1,6 +1,6 @@
import { Component } from 'preact'
import Form from '../components/form'
-import config from '../../../config/client'
+import config from '../config'
import 'linkstate/polyfill'
import withStyles from '../components/jss'
diff --git a/client/src/routes/scoreboard.js b/client/src/routes/scoreboard.js
index 2fef2de3b..c1516caee 100644
--- a/client/src/routes/scoreboard.js
+++ b/client/src/routes/scoreboard.js
@@ -1,5 +1,5 @@
import { useState, useEffect, useMemo, useCallback, useRef } from 'preact/hooks'
-import config from '../../../config/client'
+import config from '../config'
import withStyles from '../components/jss'
import Pagination from '../components/pagination'
import Graph from '../components/graph'
diff --git a/client/src/routes/sponsors.js b/client/src/routes/sponsors.js
index ba30fbe4d..f70da779a 100644
--- a/client/src/routes/sponsors.js
+++ b/client/src/routes/sponsors.js
@@ -1,5 +1,5 @@
import { Component } from 'preact'
-import config from '../../../config/client'
+import config from '../config'
import 'linkstate/polyfill'
import withStyles from '../components/jss'
diff --git a/client/src/routes/verify.js b/client/src/routes/verify.js
index 5ac490860..b249e17c9 100644
--- a/client/src/routes/verify.js
+++ b/client/src/routes/verify.js
@@ -1,5 +1,5 @@
import Error from './error'
-import config from '../../../config/client'
+import config from '../config'
import 'linkstate/polyfill'
import TokenPreview from '../components/tokenPreview'
diff --git a/client/src/util/ctftime.js b/client/src/util/ctftime.js
index 7425b59c2..ff292eafb 100644
--- a/client/src/util/ctftime.js
+++ b/client/src/util/ctftime.js
@@ -1,4 +1,4 @@
-import config from '../../../config/client'
+import config from '../config'
const openPopup = ({ url, title, w, h }) => {
const systemZoom = window.innerWidth / window.screen.availWidth
diff --git a/config/client.js.example b/config/client.js.example
index 4b562d914..016422894 100644
--- a/config/client.js.example
+++ b/config/client.js.example
@@ -1,8 +1,9 @@
-const ret = {
+const shared = require('./shared')
+
+module.exports = {
+ ...shared,
apiEndpoint: '/api/v1',
- staticEndpoint: '/static',
- ctfTitle: ' | yourCTF',
- ctfName: 'yourCTF',
+ ctfTitle: ' | ' + shared.ctfName,
meta: {
description: 'A description of your CTF',
imageUrl: ''
@@ -19,12 +20,6 @@ const ret = {
description: 'Brief description',
small: true
}
- ]
+ ],
+ ctftimeClientId: 0
}
-
-const shared = require('./shared')
-Object.entries(shared).forEach(([key, val]) => {
- if (ret[key] === undefined) ret[key] = val
-})
-
-module.exports = ret
diff --git a/config/server.js b/config/server.js
index a9c846273..b3239b122 100644
--- a/config/server.js
+++ b/config/server.js
@@ -1,4 +1,5 @@
-const ret = {
+const config = {
+ ...require('./shared'),
challengeProvider: {
name: 'challenges/rdeploy-blob',
options: {
@@ -18,7 +19,6 @@ const ret = {
verifyEmail: false,
removeDownloadHashes: true,
tokenKey: process.env.RCTF_TOKEN_KEY,
- ctfName: process.env.RCTF_NAME,
origin: process.env.RCTF_ORIGIN,
databaseUrl: process.env.RCTF_DATABASE_URL,
redisUrl: process.env.RCTF_REDIS_URL,
@@ -37,9 +37,4 @@ const ret = {
endTime: Date.now() + 24 * 60 * 60 * 1000
}
-const shared = require('./shared')
-Object.entries(shared).forEach(([key, val]) => {
- if (ret[key] === undefined) ret[key] = val
-})
-
-module.exports = ret
+module.exports = config
diff --git a/config/shared.js b/config/shared.js
index 26e16dd37..cf6e976ef 100644
--- a/config/shared.js
+++ b/config/shared.js
@@ -4,5 +4,6 @@ module.exports = {
College: 1,
Other: 2
},
- defaultDivision: 2
+ defaultDivision: 2,
+ ctfName: process.env.RCTF_NAME
}
diff --git a/preact.config.js b/preact.config.js
index c6b0cd19d..1e373aa57 100644
--- a/preact.config.js
+++ b/preact.config.js
@@ -1,5 +1,4 @@
require('dotenv').config()
-const appCfg = require('./config/client')
const glob = require('glob')
@@ -48,15 +47,6 @@ export default (config, env, helpers) => {
}
})
- const HtmlWebpackPluginWrapper = helpers.getPluginsByName(config, 'HtmlWebpackPlugin')[0]
- if (HtmlWebpackPluginWrapper !== undefined) {
- const HtmlWebpackPlugin = HtmlWebpackPluginWrapper.plugin
- HtmlWebpackPlugin.options.view = {
- ctfName: appCfg.ctfName,
- meta: appCfg.meta
- }
- }
-
const SizePluginWrapper = helpers.getPluginsByName(config, 'SizePlugin')[0]
if (SizePluginWrapper !== undefined) {
SizePluginWrapper.plugin.options = {
diff --git a/server/app.js b/server/app.js
index f538caecd..c68282213 100644
--- a/server/app.js
+++ b/server/app.js
@@ -1,7 +1,7 @@
const path = require('path')
const express = require('express')
const helmet = require('helmet')
-const { enableCORS, serveDownloads } = require('./util')
+const { enableCORS, serveIndex } = require('./util')
const uploadProvider = require('./uploads/index')
require('./leaderboard').startUpdater()
@@ -40,14 +40,13 @@ app.use(express.raw({
app.use('/api/v1', require('./api'))
const staticPath = path.join(__dirname, '../build')
+
+const indexRoute = serveIndex(path.join(staticPath, 'index.html'))
+
+// Override index.html in express.static
+app.get('/', indexRoute)
+app.get('/index.html', indexRoute)
app.use(express.static(staticPath, { extensions: ['html'] }))
-app.use(serveDownloads('/static/files'))
-app.use((req, res, next) => {
- if (req.method !== 'GET') {
- next()
- return
- }
- res.sendFile(path.join(staticPath, 'index.html'))
-})
+app.use(indexRoute)
module.exports = app
diff --git a/server/util/index.js b/server/util/index.js
index 6fe10a796..1c63d6954 100644
--- a/server/util/index.js
+++ b/server/util/index.js
@@ -1,7 +1,7 @@
const config = require('../../config/server')
-const path = require('path')
+const clientConfig = require('../../config/client')
const fs = require('fs')
-const contentDisposition = require('content-disposition')
+const mustache = require('mustache')
const { responses } = require('../responses')
const normalize = require('./normalize')
@@ -34,37 +34,22 @@ module.exports = {
next()
}
},
- serveDownloads: root => {
- if (!root.startsWith('/')) root = '/' + root
- if (!root.endsWith('/')) root = root + '/'
+ serveIndex: indexPath => {
+ const indexTemplate = fs.readFileSync(indexPath).toString()
- return (req, res, next) => {
- if (req.method !== 'GET') return next()
-
- if (req.path.startsWith(root)) {
- const filename = req.path.substring(root.length)
-
- const filepath = path.join(config.rDeployDirectory, config.rDeployFiles, filename)
-
- if (filepath.startsWith(path.join(config.rDeployDirectory, config.rDeployFiles))) {
- fs.access(filepath, fs.constants.R_OK, err => {
- if (err) return next()
+ const rendered = mustache.render(indexTemplate, {
+ config: JSON.stringify(clientConfig),
+ ctfName: clientConfig.ctfName,
+ meta: clientConfig.meta
+ })
- const cleanName = normalize.normalizeDownload(filename)
-
- return res.sendFile(filename, {
- root: path.join(config.rDeployDirectory, config.rDeployFiles),
- headers: {
- 'Content-Disposition': contentDisposition(cleanName)
- }
- })
- })
-
- return
- }
- // Something sketchy is happening...
+ return (req, res, next) => {
+ if (req.method !== 'GET') {
+ next()
+ return
}
- return next()
+ res.setHeader('Content-Type', 'text/html; charset=UTF-8')
+ res.send(rendered)
}
}
}