diff --git a/client/src/App.css b/client/src/App.css index e81208c2..b5ffaf7f 100644 --- a/client/src/App.css +++ b/client/src/App.css @@ -88,4 +88,8 @@ .ant-table { background:rgba(0, 0, 0, 0.5) !important; +} + +.ant-table-container { + overflow: auto; } \ No newline at end of file diff --git a/client/src/App.js b/client/src/App.js index 7f5c97ff..c6ac2d74 100644 --- a/client/src/App.js +++ b/client/src/App.js @@ -68,6 +68,8 @@ class App extends React.Component { previousPage = page } + message.config({maxCount: 2}) + // Handles "remember me" logins if (!this.state.token) { const token = localStorage.getItem("IRSCTF-token") @@ -263,7 +265,7 @@ class App extends React.Component {
-

Sieberrsec CTF Platform 0.6.1 Contribute

+

Sieberrsec CTF Platform 0.6.5 Contribute

diff --git a/client/src/adminChallenges.js b/client/src/adminChallenges.js index 2956b732..b0bb78b3 100644 --- a/client/src/adminChallenges.js +++ b/client/src/adminChallenges.js @@ -8,7 +8,8 @@ import { EditOutlined, FileUnknownTwoTone, EyeOutlined, - EyeInvisibleOutlined + EyeInvisibleOutlined, + RedoOutlined } from '@ant-design/icons'; import './App.css'; import AdminChallengeCreate from "./adminChallengeCreate.js"; @@ -36,19 +37,20 @@ class AdminChallenges extends React.Component { selectedKeys: [], targetKeys: [], allCat: [], - transferDisabled: false + transferDisabled: false, + refreshLoading: false } } - componentDidUpdate(prevProps) { - // Handle any page changes - if (this.state.editChallenge && this.props.location.pathname !== "/Admin/Challenges/Edit") { - this.setState({ editChallenge: false }) - } - else if (this.state.challengeCreate && this.props.location.pathname !== "/Admin/Challenges/Create") { - this.setState({ challengeCreate: false }) + componentDidUpdate(prevProps) { + // Handle any page changes + if (this.state.editChallenge && this.props.location.pathname !== "/Admin/Challenges/Edit") { + this.setState({ editChallenge: false }) + } + else if (this.state.challengeCreate && this.props.location.pathname !== "/Admin/Challenges/Create") { + this.setState({ challengeCreate: false }) + } } - } componentDidMount = async () => { @@ -60,38 +62,36 @@ class AdminChallenges extends React.Component { message.warn("Please select a challenge from the table to edit") await this.props.history.push("/Admin/Challenges") } - this.fillTableData() - this.handleCategoryData() + this.handleRefresh() } - handleCategoryData() { + handleCategoryData = async () => { this.setState({ transferDisabled: true }) let visibleCat = [] let allCat = [] - const getInfo = async () => { - fetch(window.ipAddress + "/v1/challenge/list_categories", { - method: 'get', - headers: { 'Content-Type': 'application/json', "Authorization": localStorage.getItem("IRSCTF-token") }, - }).then((results) => { - return results.json(); //return data in JSON (since its JSON data) - }).then((data) => { + await Promise.all([fetch(window.ipAddress + "/v1/challenge/list_categories", { + method: 'get', + headers: { 'Content-Type': 'application/json', "Authorization": localStorage.getItem("IRSCTF-token") }, + }).then((results) => { + return results.json(); //return data in JSON (since its JSON data) + }).then((data) => { - if (data.success === true) { - visibleCat = data.categories - } - else { - message.error({ content: "Oops. Unknown error" }) - } + if (data.success === true) { + visibleCat = data.categories + } + else { + message.error({ content: "Oops. Unknown error" }) + } - }).catch((error) => { - console.log(error) - message.error({ content: "Oops. There was an issue connecting with the server" }); - }) + }).catch((error) => { + console.log(error) + message.error({ content: "Oops. There was an issue connecting with the server" }); + }) - await fetch(window.ipAddress + "/v1/challenge/list_all_categories", { + , fetch(window.ipAddress + "/v1/challenge/list_all_categories", { method: 'get', headers: { 'Content-Type': 'application/json', "Authorization": localStorage.getItem("IRSCTF-token") }, }).then((results) => { @@ -110,22 +110,17 @@ class AdminChallenges extends React.Component { console.log(error) message.error({ content: "Oops. There was an issue connecting with the server" }); }) + ]) + let invisible = difference(allCat, visibleCat) + /*console.log(invisible) + console.log(allCat) + console.log(visibleCat)*/ + for (let i = 0; i < allCat.length; i++) { + allCat[i] = { "key": allCat[i] } } - - (async () => { - await getInfo() - let invisible = difference(allCat, visibleCat) - /*console.log(invisible) - console.log(allCat) - console.log(visibleCat)*/ - - for (let i = 0; i < allCat.length; i++) { - allCat[i] = { "key": allCat[i] } - } - this.setState({ targetKeys: invisible, allCat: allCat, transferDisabled: false }) - })() + this.setState({ targetKeys: invisible, allCat: allCat, transferDisabled: false }) } handleChange = (nextTargetKeys, direction, moveKeys) => { @@ -172,9 +167,9 @@ class AdminChallenges extends React.Component { }) } - fillTableData = () => { + fillTableData = async () => { this.setState({ loading: true }) - fetch(window.ipAddress + "/v1/challenge/list_all", { + await fetch(window.ipAddress + "/v1/challenge/list_all", { method: 'get', headers: { 'Content-Type': 'application/json', "Authorization": localStorage.getItem("IRSCTF-token") }, }).then((results) => { @@ -191,6 +186,7 @@ class AdminChallenges extends React.Component { } } this.setState({ dataSource: data.challenges, loading: false }) + } else { message.error({ content: "Oops. Unknown error" }) @@ -217,8 +213,7 @@ class AdminChallenges extends React.Component { //console.log(data) if (data.success === true) { message.success({ content: "Deleted challenge \"" + challengeName + "\" successfully" }) - this.fillTableData() - this.handleCategoryData() + this.handleRefresh() } else { @@ -249,15 +244,17 @@ class AdminChallenges extends React.Component { handleCreateBack() { this.props.history.push("/Admin/Challenges") this.setState({ challengeCreate: false }) - this.fillTableData() - this.handleCategoryData() + this.handleRefresh() } handleEditChallBack() { this.props.history.push("/Admin/Challenges") this.setState({ editChallenge: false }) - this.fillTableData() - this.handleCategoryData() + this.handleRefresh() + } + + handleRefresh = async () => { + await Promise.all([this.fillTableData(), this.handleCategoryData()]) } @@ -269,24 +266,26 @@ class AdminChallenges extends React.Component { - {this.state.loading && ( -
- -
- )} - {!this.state.loading && ( -
- - {!this.state.challengeCreate && !this.state.editChallenge && ( -
- + {!this.state.challengeCreate && !this.state.editChallenge && ( +
+
+ +
+ {this.state.loading && ( +
+ +
+ )} + {!this.state.loading && ( +
-

There are no challenges created.

+

No Challenges Have Been Created.

) }}> @@ -329,35 +328,37 @@ class AdminChallenges extends React.Component { )} />
- -

Category Management {this.state.transferDisabled && ()}

- - item.key} - pagination - disabled={this.state.transferDisabled} - /> - -
)} - - } /> - } /> + +

Category Management {this.state.transferDisabled && ()}

+ + item.key} + pagination + disabled={this.state.transferDisabled} + /> -
+
)} + + + } /> + } /> + + + ); } diff --git a/client/src/adminSubmissions.js b/client/src/adminSubmissions.js index 63a45213..6337a827 100644 --- a/client/src/adminSubmissions.js +++ b/client/src/adminSubmissions.js @@ -1,7 +1,8 @@ import React from 'react'; -import { Layout, Table, message } from 'antd'; +import { Layout, Table, message, Button } from 'antd'; import { FileUnknownTwoTone, + RedoOutlined } from '@ant-design/icons'; import { orderBy } from "lodash"; import { Ellipsis } from 'react-spinners-css'; @@ -25,9 +26,9 @@ class AdminSubmissions extends React.Component { this.fillTableData() } - fillTableData = () => { + fillTableData = async () => { this.setState({ loading: true }) - fetch(window.ipAddress + "/v1/submissions", { + await fetch(window.ipAddress + "/v1/submissions", { method: 'get', headers: { 'Content-Type': 'application/json', "Authorization": localStorage.getItem("IRSCTF-token") }, }).then((results) => { @@ -69,6 +70,10 @@ class AdminSubmissions extends React.Component { +
+
+ {this.state.loading && (
@@ -95,7 +100,7 @@ class AdminSubmissions extends React.Component { )} - + ); } } diff --git a/client/src/adminUsers.js b/client/src/adminUsers.js index bdd2d50f..07fb6b5c 100644 --- a/client/src/adminUsers.js +++ b/client/src/adminUsers.js @@ -7,7 +7,8 @@ import { ClusterOutlined, UserOutlined, MailOutlined, - LockOutlined + LockOutlined, + RedoOutlined } from '@ant-design/icons'; import { Link } from 'react-router-dom'; import { Ellipsis } from 'react-spinners-css'; @@ -109,9 +110,9 @@ class AdminUsers extends React.Component { this.fillTableData() } - fillTableData = () => { + fillTableData = async () => { this.setState({ loading: true }) - fetch(window.ipAddress + "/v1/account/list", { + await fetch(window.ipAddress + "/v1/account/list", { method: 'get', headers: { 'Content-Type': 'application/json', "Authorization": localStorage.getItem("IRSCTF-token") }, }).then((results) => { @@ -172,7 +173,7 @@ class AdminUsers extends React.Component { }).then((data) => { //console.log(data) if (data.success === true) { - + message.success({ content: "User \"" + username + "\" deleted successfully" }) this.fillTableData() } @@ -241,98 +242,97 @@ class AdminUsers extends React.Component {
)} - + Change User Permissions } + visible={this.state.permissionModal} + onOk={this.changePermissions} + onCancel={() => { this.setState({ permissionModal: false }) }} + confirmLoading={this.state.modalLoading} + > + +
+
+ +
    +
  • 0 - Normal User: Has access to the basic functions and nothing else
  • +
  • 1 - Challenge Creator User: Has the additional power of submitting new challenges, but not modifying existing ones
  • +
  • 2 - Admin User: Has full access to the platform via the admin panel.
  • +
+
+ + { this.setState({ createUserModal: false }) }} + confirmLoading={this.state.modalLoading} + > + + + + + +
+ +
{!this.state.loading && ( -
- Change User Permissions } - visible={this.state.permissionModal} - onOk={this.changePermissions} - onCancel={() => { this.setState({ permissionModal: false }) }} - confirmLoading={this.state.modalLoading} - > - -
-
- -
    -
  • 0 - Normal User: Has access to the basic functions and nothing else
  • -
  • 1 - Challenge Creator User: Has the additional power of submitting new challenges, but not modifying existing ones
  • -
  • 2 - Admin User: Has full access to the platform via the admin panel.
  • -
-
- - { this.setState({ createUserModal: false }) }} - confirmLoading={this.state.modalLoading} - > - - - - - - - - - - -

There are no users created

- - ) - }}> - { - return {text}; - }} - /> - - - - ( - - { - this.setState({ permissionModal: true, username: record.username, permissionChangeTo: record.type.toString() }) - }}> - - Change Permissions - - - - { - confirm({ - title: 'Are you sure you want to delete the user \"' + record.username + '\"? This action is irreversible.', - icon: , - onOk: (close) => { this.deleteAccount(close.bind(this), record.username) }, - onCancel: () => { }, - }); - }}> - - Delete Account - - - - } placement="bottomCenter"> - - - )} - /> -
-
+ + +

There are no users created

+ + ) + }}> + { + return {text}; + }} + /> + + + + ( + + { + this.setState({ permissionModal: true, username: record.username, permissionChangeTo: record.type.toString() }) + }}> + + Change Permissions + + + + { + confirm({ + title: 'Are you sure you want to delete the user \"' + record.username + '\"? This action is irreversible.', + icon: , + onOk: (close) => { this.deleteAccount(close.bind(this), record.username) }, + onCancel: () => { }, + }); + }}> + + Delete Account + + + + } placement="bottomCenter"> + + + )} + /> +
)} +
); } diff --git a/client/src/challenges.js b/client/src/challenges.js index 9feac3df..2e869292 100644 --- a/client/src/challenges.js +++ b/client/src/challenges.js @@ -92,7 +92,7 @@ class Challenges extends React.Component { const category = this.props.match.params.category; if (typeof category !== "undefined") { - await this.setState({ challengeCategory: true, currentCategory: decodeURIComponent(category), currentCategoryChallenges: this.state.originalData[decodeURIComponent(category)] }) + await this.setState({ currentCategory: decodeURIComponent(category), currentCategoryChallenges: this.state.originalData[decodeURIComponent(category)] }) this.sortDifferent({ target: { value: "Type" } }) } diff --git a/client/src/challengesCategory.js b/client/src/challengesCategory.js index b95dc5e7..2b3addcf 100644 --- a/client/src/challengesCategory.js +++ b/client/src/challengesCategory.js @@ -1,5 +1,5 @@ -import React from 'react'; -import { Layout, Card, List, message, Modal, Tag, Input, Button, Tabs, Avatar, Form, notification, Tooltip } from 'antd'; +import React, { useEffect, useRef } from 'react'; +import { Layout, Card, List, message, Modal, Tag, Input, Button, Tabs, Avatar, Form, notification, Tooltip, Popover } from 'antd'; import { LoadingOutlined, UnlockOutlined, @@ -9,7 +9,8 @@ import { FileUnknownTwoTone, EyeInvisibleOutlined, ExclamationCircleOutlined, - SolutionOutlined + SolutionOutlined, + LinkOutlined } from '@ant-design/icons'; import './App.css'; import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; @@ -46,6 +47,20 @@ const SubmitFlagForm = (props) => { ); } +const CopyLinkInput = (props) => { + const copyInput = useRef(null) + + useEffect(() => { + copyInput.current.select() + document.execCommand('copy') + message.success('Challenge link copied to clipboard.') + }) + + return ( + + ) +} + class ChallengesCategory extends React.Component { constructor(props) { @@ -385,7 +400,7 @@ class ChallengesCategory extends React.Component { tab={ Challenge} key="challenge" > - {this.state.challengeWriteup !== "" && this.state.challengeWriteup !== "CompleteFirst" ( + {this.state.challengeWriteup !== "" && this.state.challengeWriteup !== "CompleteFirst"(