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) } } }