Merge pull request #24 from ClicksMinutePer/dependabot/npm_and_yarn/next-12.1.0
diff --git a/.eslintrc.json b/.eslintrc.json
index f0f3abe..c9aa306 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -1,6 +1,7 @@
{
"extends": "next/core-web-vitals",
"rules": {
- "@next/next/no-img-element": "off"
+ "@next/next/no-img-element": "off",
+ "@next/next/no-html-link-for-pages": "off"
}
}
diff --git a/Components/NavBar.js b/Components/NavBar.js
index 89c8fab..a9e5dbb 100644
--- a/Components/NavBar.js
+++ b/Components/NavBar.js
@@ -37,4 +37,4 @@
}
}
-export default NavBar;
\ No newline at end of file
+export default NavBar;
diff --git a/pages/01189998819991197253.js b/pages/01189998819991197253.js
new file mode 100644
index 0000000..7421556
--- /dev/null
+++ b/pages/01189998819991197253.js
@@ -0,0 +1,23 @@
+import Header from '../Components/Header'
+
+export default function Error() {
+ return (
+ <>
+ <Header
+ name="0118 999 881 999 119 7253"
+ subtext={<>
+ Dear Sir/Madam,<br />
+ Fire! Fire! Help me!<br />
+ 123 Cavendon Road.<br />
+ Looking forward to hearing from you,<br />
+ All the best, Maurice Moss
+ </>}
+ embedDescription="This is the internet"
+ gradient={["F27878", "D96B6B"]}
+ wave="web/waves/header/rsm"
+ buttons={[{color: "F27878", buttonText: "ffffff", text: "No that's too formal", link: "/#"}]}
+ fullscreen={true}
+ />
+ </>
+ )
+}
diff --git a/pages/api/nucleus/verify/complete.js b/pages/api/nucleus/verify/complete.js
new file mode 100644
index 0000000..1b58a04
--- /dev/null
+++ b/pages/api/nucleus/verify/complete.js
@@ -0,0 +1,22 @@
+import Axios from 'axios';
+import qs from 'querystring';
+
+const Complete = async (req, res) => {
+ const chk = await Axios.post('http://localhost:3000/api/nucleus/verify/verifyToken', qs.stringify({
+ tkn: req.body.tkn
+ }))
+ if ( !chk.data.success ) {
+ return res.status(200).send({success: false})
+ }
+ let secret = "slwu0rZV5W6WdmGtgI16du8Ar2tQGMr3Q9dE6u3poKiVODNV9SweaA3buawgkTmTuITXDWOUpBcTFA0qWrUvoshi1JB180WOFwA7"
+ try {
+ await Axios.post(`http://192.168.0.18:10000/verify/${req.body.code}`, {
+ secret: secret
+ });
+ } catch (e) {
+ return res.status(200).send({success: false})
+ }
+ return res.status(200).send({success: true});
+}
+
+export default Complete;
\ No newline at end of file
diff --git a/pages/api/nucleus/verify/fetch.js b/pages/api/nucleus/verify/fetch.js
new file mode 100644
index 0000000..ba7aa04
--- /dev/null
+++ b/pages/api/nucleus/verify/fetch.js
@@ -0,0 +1,22 @@
+import Axios from 'axios';
+
+const Validate = async (req, res) => {
+ try {
+ // var out = await Axios.get(`http://192.168.102.7:10000/verify/${req.body.code}`)
+ // out = out.data
+ // let props = {
+ // user: out.user,
+ // role: out.role,
+ // role_name: out.role_name,
+ // guild: out.guild,
+ // guild_name: out.guild_name,
+ // guild_icon_url: out.guild_icon_url,
+ // guild_size: out.guild_size
+ // }
+ return res.status(200).send(props)
+ } catch (err) {
+ return res.status(400).end()
+ }
+}
+
+export default Validate;
\ No newline at end of file
diff --git a/pages/api/nucleus/verify/verifyToken.js b/pages/api/nucleus/verify/verifyToken.js
new file mode 100644
index 0000000..b44624e
--- /dev/null
+++ b/pages/api/nucleus/verify/verifyToken.js
@@ -0,0 +1,15 @@
+import Axios from 'axios';
+import qs from 'querystring';
+
+const verifyToken = async (req, res) => {
+ const chk = await Axios.post('https://hcaptcha.com/siteverify', qs.stringify({
+ response: req.body.tkn,
+ secret: '0x19C699BFfce07b2a026121DE6702706BB2d51D6c',
+ sitekey: '85074411-fa13-4d9b-b901-53095c6d1fc6'
+ }))
+
+ // return res.send({ success: false });
+ return res.send({ success: chk.data.success });
+}
+
+export default verifyToken;
\ No newline at end of file
diff --git a/pages/api/rsmv/complete.js b/pages/api/rsmv/complete.js
index bc64d8a..002caee 100644
--- a/pages/api/rsmv/complete.js
+++ b/pages/api/rsmv/complete.js
@@ -1,7 +1,7 @@
import Axios from 'axios';
const Complete = async (req, res) => {
- let code = await Axios.post('http://localhost:3000/api/rsmv/validate', {code:req.body.code});
+ let code = await Axios.post('http://127.0.0.1:3000/api/rsmv/validate', {code:req.body.code});
if (code.status != 200) {
return res.send(404);
}
@@ -11,7 +11,7 @@
let secret = "slwu0rZV5W6WdmGtgI16du8Ar2tQGMr3Q9dE6u3poKiVODNV9SweaA3buawgkTmTuITXDWOUpBcTFA0qWrUvoshi1JB180WOFwA7"
let resp = await Axios.get(
- `http://192.168.102.7:10000/role/gid/${req.body.gid}/rid/${req.body.rid}/user/${req.body.uid}/secret/${secret}/code/${req.body.code}`
+ `http://localhost:10000/verify/${req.body.gid}/${req.body.rid}/${req.body.uid}/${secret}/${req.body.code}`
)
return res.send(resp.status);
}
diff --git a/pages/api/rsmv/validate.js b/pages/api/rsmv/validate.js
index d73c467..e0c4de1 100644
--- a/pages/api/rsmv/validate.js
+++ b/pages/api/rsmv/validate.js
@@ -2,7 +2,7 @@
const Validate = async (req, res) => {
try {
- var out = await Axios.get(`http://192.168.102.7:10000/verify/${req.body.code}`)
+ var out = await Axios.get(`http://localhost:10000/verify/${req.body.code}`)
out = out.data
let props = {
user: out.user,
diff --git a/pages/clicksforms.js b/pages/clicksforms.js
index e4d96dc..8da3441 100644
--- a/pages/clicksforms.js
+++ b/pages/clicksforms.js
@@ -2,7 +2,6 @@
import Header from '../Components/Header'
import { AutoLayout, Panel, Title, Subtitle, Text, Divider } from '../Components/Panels';
import { List, ListItem, Code } from '../Components/Texttools';
-import Link from 'next/link';
import React from 'react';
export default class Home extends React.Component {
@@ -54,7 +53,7 @@
<Title>Services</Title>
<Divider toHighlight={this.state.toHighlight} highlightColour="6576CC" name="services"/>
<Text>ClicksForms supports services such as <a href="https://docs.google.com/forms">Google Forms</a> through our Add-on.</Text>
- <Text>Our API is public. You can view it <Link href="/clicksforms/docs">here</Link>.</Text>
+ <Text>Our API is public. You can view it <a href="/clicksforms/docs">here</a>.</Text>
</Panel>
<Panel halfSize={true} id="privacy">
<Title>Privacy</Title>
diff --git a/pages/index.js b/pages/index.js
index f801b79..f84c7cd 100644
--- a/pages/index.js
+++ b/pages/index.js
@@ -7,7 +7,7 @@
<>
<Header
name="Clicks"
- subtext="// TODO: Fix this massive security issue"
+ subtext="Creating projects that click"
customImage="https://assets.clicks.codes/web/logos/clicks.svg"
embedImage="https://assets.clicks.codes/web/logos/clicks.png"
gradient={["6576CC", "4B5899"]}
diff --git a/pages/nucleus.js b/pages/nucleus.js
new file mode 100644
index 0000000..5155597
--- /dev/null
+++ b/pages/nucleus.js
@@ -0,0 +1,116 @@
+import { Card, CardRow } from '../Components/Card';
+import Header from '../Components/Header'
+import { AutoLayout, Panel, Title, Subtitle, Text, Divider } from '../Components/Panels';
+import { List, ListItem, Code } from '../Components/Texttools';
+import { useColorMode } from 'theme-ui';
+
+export default function Home() {
+ const [theme, setTheme] = useColorMode()
+
+ return (
+ <>
+ <Header
+ name="Nucleus"
+ customImage="https://assets.clicks.codes/web/logos/nucleus.svg"
+ embedImage="https://assets.clicks.codes/bots/nucleus/normal.png"
+ subtext="The core of your server"
+ gradient={["F27878", "D96B6B"]}
+ wave="web/waves/header/nucleus"
+ buttons={[
+ // {color: "424242", buttonText: "FFFFFF", link: "#features", text: "Features"},
+ {color: "424242", buttonText: "FFFFFF", link: "#commands", text: "Commands"},
+ {color: "424242", buttonText: "FFFFFF", link: "#privacy", text: "Privacy"},
+ {color: "F27878", buttonText: "FFFFFF", link: "#invite", text: "Invite"}
+ ]}
+ />
+ <AutoLayout>
+ <Panel halfSize={true} id="commands">
+ <Title>General Commands</Title>
+ <Divider />
+ <Text>Standard commands to use Nucleus</Text>
+ <List colour="F27878">
+ <ListItem><Code colour="F27878">/help</Code> Shows all commands and info.</ListItem>
+ <ListItem><Code colour="F27878">/settings</Code> Shows all settings and info.</ListItem>
+ <ListItem>Theres a lot more settings commands but they're subject to change before release.</ListItem>
+ <ListItem>Expect this list to be longer</ListItem>
+ </List>
+ </Panel>
+ <Panel halfSize={true}>
+ <Title>Moderation Commands</Title>
+ <Divider />
+ <Text>Commands to manage your users and channels</Text>
+ <List colour="F27878">
+ <ListItem><Code colour="F27878">/mod warn</Code> Warns a member.</ListItem>
+ <ListItem><Code colour="F27878">/mod kick</Code> Kicks a member.</ListItem>
+ <ListItem><Code colour="F27878">/mod softban</Code> Soft bans a member.</ListItem>
+ <ListItem><Code colour="F27878">/mod ban</Code> Bans a member.</ListItem>
+ <ListItem><Code colour="F27878">/mod unban</Code> Unbans a member.</ListItem>
+ <ListItem><Code colour="F27878">/mod purge</Code> Deletes messages in the channel.</ListItem>
+ <ListItem><Code colour="F27878">/mod mute</Code> Mutes a member.</ListItem>
+ <ListItem><Code colour="F27878">/mod unmute</Code> Unmutes a member.</ListItem>
+ <ListItem><Code colour="F27878">/mod nick</Code> Changes the nickname of a member.</ListItem>
+ <ListItem><Code colour="F27878">/mod lock</Code> Stops people from sending messages in a channel.</ListItem>
+ <ListItem><Code colour="F27878">/mod slowmode</Code> Edits the slowmode in a channel.</ListItem>
+ <ListItem><Code colour="F27878">/mod viewas</Code> Allows you to view the server as a member or role.</ListItem>
+ </List>
+ </Panel>
+ <Panel halfSize={true}>
+ <Title>Internal Commands</Title>
+ <Divider />
+ <Text>Commands to check the status of and information about Nucleus</Text>
+ <List colour="F27878">
+ <ListItem><Code colour="F27878">/nucleus guide</Code> Shows the setup guide and tips for setup.</ListItem>
+ <ListItem><Code colour="F27878">/nucleus invite</Code> Shows the invite link for Nucleus.</ListItem>
+ <ListItem><Code colour="F27878">/nucleus ping</Code> Shows the latency of the bot.</ListItem>
+ <ListItem><Code colour="F27878">/nucleus stats</Code> Shows the stats of the bot.</ListItem>
+ <ListItem><Code colour="F27878">/nucleus suggest</Code> Sends a feature request to the developers.</ListItem>
+ </List>
+ </Panel>
+ <Panel halfSize={true} id="server">
+ <Title>Server Management</Title>
+ <Divider />
+ <Text>Commands to manage your server and members</Text>
+ <List colour="F27878">
+ <ListItem><Code colour="F27878">/server about</Code> Shows the server information.</ListItem>
+ <ListItem><Code colour="F27878">/server rules</Code> Shows the server rules.</ListItem>
+ <ListItem><Code colour="F27878">/ticket create</Code> Creates a ticket.</ListItem>
+ <ListItem><Code colour="F27878">/ticket close</Code> Closes a ticket.</ListItem>
+ <ListItem><Code colour="F27878">/user about</Code> Shows the user information.</ListItem>
+ <ListItem><Code colour="F27878">/user avatar</Code> Shows the user avatar.</ListItem>
+ <ListItem><Code colour="F27878">/user track</Code> Allows you to move a user up and down a role track.</ListItem>
+ <ListItem><Code colour="F27878">/verify</Code> Verifies a member to give them access to the server.</ListItem>
+ </List>
+ </Panel>
+ <Panel halfSize={false} id="verify">
+ <Title>Verification</Title>
+ <Divider />
+ <Text>Verification ensures all members in your server are human, and prevents automated accounts from joining.</Text>
+ <Text>For more information, see the <a href="/nucleus/verify/about">about</a> page.</Text>
+ </Panel>
+ <Panel halfSize={true} id="privacy">
+ <Title>Privacy</Title>
+ <Divider />
+ <Text>You can run <Code colour="F27878">/privacy</Code> to view and manage all data stored about your server</Text>
+ <Text>You should always know what we know and store about you, so <a href="https://clicksminuteper.github.io/policies/nucleus">here</a> is the complete list.</Text>
+ </Panel>
+ <Panel halfSize={true} id="invite">
+ <Title>Invite</Title>
+ <Divider />
+ <CardRow>
+ <Card
+ wave="nucleus"
+ icon="bots/nucleus/circle"
+ buttonText={"FFFFFF"} gradient={["F27878", "D96B6B"]}
+ title="Nucleus"
+ subtext="Invite Nucleus to your server"
+ buttons={[
+ {color: "424242", link: "https://discord.com/api/oauth2/authorize?client_id=715989276382462053&permissions=121295465718&scope=bot%20applications.commands", text: "Invite"}
+ ]}
+ url="https://discord.com/api/oauth2/authorize?client_id=715989276382462053&permissions=121295465718&scope=bot%20applications.commands"
+ />
+ </CardRow>
+ </Panel>
+ </AutoLayout>
+ </>
+ )
+}
diff --git a/pages/nucleus/verify/about.js b/pages/nucleus/verify/about.js
new file mode 100644
index 0000000..08e7f00
--- /dev/null
+++ b/pages/nucleus/verify/about.js
@@ -0,0 +1,77 @@
+import React, { Component } from 'react'
+import Header from '../../../Components/Header'
+import { AutoLayout, Panel, Title, Subtitle, Text, Divider } from '../../../Components/Panels'
+import { Code } from '../../../Components/Texttools'
+import { Card, CardRow } from '../../../Components/Card'
+import HCaptcha from 'react-hcaptcha';
+import { useReward } from 'react-rewards';
+
+function About(props) {
+ const { reward, isAnimating } = useReward('confetti', 'confetti', {
+ elementSize: 12,
+ spread: 85,
+ position: "absolute",
+ colors: ["#F27878", "#E5AB71", "#E5DC71", "#A1CC65", "#68D49E", "#71AFE5", "#6576CC", "#8D58B2", "#BF5E9F"]
+ });
+
+ return (
+ <>
+ <Header
+ name="Nucleus Verification"
+ subtext="Remove automated accounts from your server"
+ customImage={"https://assets.clicks.codes/web/logos/nucleus.svg"}
+ embedImage={"https://assets.clicks.codes/bots/nucleus/normal.png"}
+ gradient={["F27878", "D96B6B"]}
+ wave="web/waves/header/nucleus"
+ buttons={[
+ {color: "424242", buttonText: "FFFFFF", link: "#about", text: "About"},
+ {color: "424242", buttonText: "FFFFFF", link: "#privacy", text: "Privacy"},
+ {color: "F27878", buttonText: "FFFFFF", link: "#invite", text: "Invite"}
+ ]}
+ />
+ <AutoLayout>
+ <Panel halfSize={false} id="about">
+ <Title>About Verification</Title>
+ <Divider />
+ <Text>Nucleus is designed to help keep your server safe. Verification is how we remove bots from your server.</Text>
+ <Text>Many bot accounts are designed to join and spam in servers, and verification can prevent this easily:</Text>
+ <HCaptcha
+ id="Captchas mitigate problems"
+ sitekey="85074411-fa13-4d9b-b901-53095c6d1fc6"
+ onVerify={reward}
+ theme="dark"
+ />
+ <Text>Users will need to run <Code colour="F27878">/verify</Code> when they join, and will be given a link to complete this check online.</Text>
+ <Text>It is completely free to use verification, and for users to verify.</Text>
+ <div id="confetti" />
+ </Panel>
+ <Panel halfSize={true} id="privacy">
+ <Title>Privacy</Title>
+ <Divider />
+ <Text>Verification stores the smallest amount of data required to function, and is deleted automatically.</Text>
+ <Text>This includes the user's ID, the server ID, role name and server icon.</Text>
+ <Text>The full list of data stored by Nucleus can be found <a href="https://clicksminuteper.github.io/policies/nucleus">here</a>.</Text>
+ </Panel>
+ <Panel halfSize={true} id="invite">
+ <Title>Invite</Title>
+ <Divider />
+ <CardRow>
+ <Card
+ wave="nucleus"
+ icon="bots/nucleus/circle"
+ buttonText={"FFFFFF"} gradient={["F27878", "D96B6B"]}
+ title="Nucleus"
+ subtext="Invite Nucleus to your server"
+ buttons={[
+ {color: "424242", link: "https://discord.com/api/oauth2/authorize?client_id=715989276382462053&permissions=121295465718&scope=bot%20applications.commands", text: "Invite"}
+ ]}
+ url="https://discord.com/api/oauth2/authorize?client_id=715989276382462053&permissions=121295465718&scope=bot%20applications.commands"
+ />
+ </CardRow>
+ </Panel>
+ </AutoLayout>
+ </>
+ )
+}
+
+export default About;
\ No newline at end of file
diff --git a/pages/nucleus/verify/alreadyVerified.js b/pages/nucleus/verify/alreadyVerified.js
new file mode 100644
index 0000000..c31290a
--- /dev/null
+++ b/pages/nucleus/verify/alreadyVerified.js
@@ -0,0 +1,24 @@
+import { Component } from 'react'
+import Header from '../../../Components/Header'
+
+class Failed extends Component {
+ constructor(props) {
+ super(props)
+ }
+
+ render() {
+ return (
+ <Header
+ name="Already verified"
+ subtext="You are already verified, and cannot verify again"
+ gradient={["65CC76", "60B258"]}
+ wave="web/waves/header/nucleus"
+ buttons={[]}
+ fullscreen={true}
+ />
+ )
+ }
+
+}
+
+export default Failed;
\ No newline at end of file
diff --git a/pages/nucleus/verify/failure.js b/pages/nucleus/verify/failure.js
new file mode 100644
index 0000000..61b58d0
--- /dev/null
+++ b/pages/nucleus/verify/failure.js
@@ -0,0 +1,24 @@
+import { Component } from 'react'
+import Header from '../../../Components/Header'
+
+class Failed extends Component {
+ constructor(props) {
+ super(props)
+ }
+
+ render() {
+ return (
+ <Header
+ name="Verification failed"
+ subtext={<p>Please try again, and if the error persists please contact us at <a href="mailto:verification@clicks.codes" target="_blank" rel="noopener noreferrer">verification@clicks.codes</a></p>}
+ gradient={["F27878", "D96B6B"]}
+ wave="web/waves/header/nucleus"
+ buttons={[]}
+ fullscreen={true}
+ />
+ )
+ }
+
+}
+
+export default Failed;
\ No newline at end of file
diff --git a/pages/nucleus/verify/index.js b/pages/nucleus/verify/index.js
new file mode 100644
index 0000000..796298a
--- /dev/null
+++ b/pages/nucleus/verify/index.js
@@ -0,0 +1,134 @@
+import HCaptcha from 'react-hcaptcha';
+import Axios from 'axios';
+import Router from 'next/router';
+import React from 'react';
+import Header from '../../../Components/Header'
+import { useReward } from 'react-rewards';
+import { Card, CardRow } from '../../../Components/Card';
+
+import { AutoLayout, Panel, Title, Text, Divider } from '../../../Components/Panels';
+import { List, ListItem } from '../../../Components/Texttools';
+import { useColorMode } from 'theme-ui';
+
+function Verify(props) {
+ const [clicked, setClicked] = React.useState(false);
+ const [theme, setTheme] = useColorMode()
+
+ if (clicked) {
+ Router.push('/nucleus/verify/alreadyVerified', '/nucleus/verify/success');
+ }
+
+ const { reward: reward, isAnimating: isAnimating } = useReward('confetti', 'confetti', {
+ elementSize: 10,
+ elementCount: 150,
+ startVelocity: 35,
+ lifetime: 300,
+ decay: 0.94,
+ spread: 170,
+ position: "absolute",
+ colors: ["#68D49E"]
+ });
+
+ async function submitForm(tkn) {
+ if ( clicked ) {
+ return
+ }
+ setClicked(true);
+ reward();
+ let code = await Axios.post('/api/nucleus/verify/complete', {
+ code: props.code,
+ tkn: tkn
+ });
+ setTimeout(() => {
+ if (code.data.success === true ) return Router.push('/nucleus/verify/success','/nucleus/verify')
+ else return Router.push('/nucleus/verify/failure','/nucleus/verify')
+ }, 2500);
+ }
+
+ return <>
+ <Header
+ name={props.guild_name}
+ customImage={props.guild_icon_url}
+ roundImage={true}
+ subtext={`${props.memberCount} members`}
+ gradient={["F27878", "D96B6B"]}
+ wave="web/waves/header/nucleus"
+ buttons={[]}
+ />
+ <AutoLayout>
+ <Panel>
+ <Title>Verify</Title>
+ <Divider name="commands"/>
+ <Text>Complete the check below to join {props.guild_name}</Text>
+ <div style={{height: "125px"}}>
+ <HCaptcha
+ id="Captchas mitigate problems"
+ sitekey="85074411-fa13-4d9b-b901-53095c6d1fc6"
+ onVerify={tkn => submitForm(tkn)}
+ theme="dark"
+ />
+ </div>
+ <List colour="F27878">
+ <ListItem>This is an automatic check performed by Nucleus.</ListItem>
+ <ListItem>By clicking Proceed, you will be given the <code>{props.role_name}</code> role in <code>{props.guild_name}</code>.</ListItem>
+ <ListItem>For the full list of data stored by Nucleus, please check <a href="https://clicksminuteper.github.io/policies/nucleus#verification">here</a></ListItem>
+ </List>
+ <div id="confetti" />
+ </Panel>
+ <Panel halfSize={false} id="invite">
+ <Title>Invite</Title>
+ <Divider />
+ <CardRow>
+ <Card
+ wave="nucleus"
+ icon="bots/nucleus/circle"
+ buttonText={"FFFFFF"} gradient={["F27878", "D96B6B"]}
+ title="Nucleus"
+ subtext="Invite Nucleus to your server"
+ buttons={[
+ {color: "424242", link: "https://discord.com/api/oauth2/authorize?client_id=715989276382462053&permissions=121295465718&scope=bot%20applications.commands", text: "Invite"}
+ ]}
+ url="https://discord.com/api/oauth2/authorize?client_id=715989276382462053&permissions=121295465718&scope=bot%20applications.commands"
+ />
+ </CardRow>
+ </Panel>
+ </AutoLayout>
+ </>
+}
+
+export default Verify;
+export async function getServerSideProps(ctx) {
+ if(!ctx.query.code) {
+ return {
+ redirect: {
+ destination: '/nucleus/verify/about',
+ permanent: true
+ }
+ }
+ }
+ let code;
+ try {
+ await Axios.patch(`http://localhost:10000/verify/${ctx.query.code}`);
+ code = await Axios.get(`http://localhost:10000/verify/${ctx.query.code}`, {code:ctx.query.code});
+ } catch (e) {
+ return {
+ redirect: {
+ destination: '/nucleus/verify/failure',
+ permanent: true
+ }
+ }
+ }
+ let headers = ctx.req.headers;
+ return {
+ props: {
+ uID: code.data.uID,
+ role_name: code.data.rName,
+ gID: code.data.gID,
+ guild_name: code.data.gName,
+ guild_icon_url: code.data.gIcon,
+ memberCount: code.data.mCount,
+ headers: headers,
+ code: ctx.query.code
+ }
+ }
+}
\ No newline at end of file
diff --git a/pages/nucleus/verify/success.js b/pages/nucleus/verify/success.js
new file mode 100644
index 0000000..de5b4d8
--- /dev/null
+++ b/pages/nucleus/verify/success.js
@@ -0,0 +1,24 @@
+import { Component } from 'react'
+import Header from '../../../Components/Header'
+
+class Success extends Component {
+ constructor(props) {
+ super(props)
+ }
+
+ render() {
+ return (
+ <Header
+ name="Verified"
+ subtext="You can now close this tab or window."
+ gradient={["65CC76", "60B258"]}
+ wave="web/waves/header/rsm"
+ buttons={[]}
+ fullscreen={true}
+ />
+ )
+ }
+
+}
+
+export default Success;
\ No newline at end of file
diff --git a/pages/nucleus/verify/testing.js b/pages/nucleus/verify/testing.js
new file mode 100644
index 0000000..42ac53d
--- /dev/null
+++ b/pages/nucleus/verify/testing.js
@@ -0,0 +1,95 @@
+import HCaptcha from 'react-hcaptcha';
+import Axios from 'axios';
+import Router from 'next/router';
+import React from 'react';
+import Header from '../../../Components/Header'
+import { useReward } from 'react-rewards';
+import { Card, CardRow } from '../../../Components/Card'
+
+import { AutoLayout, Panel, Title, Text, Divider } from '../../../Components/Panels';
+import { List, ListItem } from '../../../Components/Texttools';
+import { useColorMode } from 'theme-ui';
+
+function Verify(props) {
+ const [clicked, setClicked] = React.useState(false);
+ const [theme, setTheme] = useColorMode()
+
+ const { reward: reward, isAnimating: isAnimating } = useReward('confetti', 'confetti', {
+ elementSize: 10,
+ elementCount: 150,
+ startVelocity: 35,
+ lifetime: 300,
+ decay: 0.94,
+ spread: 170,
+ position: "absolute",
+ colors: ["#68D49E"]
+ });
+
+ async function submitForm(tkn) {
+ if ( clicked ) {
+ return
+ }
+ setClicked(true);
+ reward();
+ let code = await Axios.post('/api/nucleus/verify/complete', {
+ code:"TEST",
+ tkn: tkn
+ });
+ setTimeout(() => {
+ if (code.data.success === true ) return Router.push('/nucleus/verify/success','/nucleus/verify')
+ else return Router.push('/nucleus/verify/failure','/nucleus/verify')
+ }, 2500);
+ }
+
+ return <>
+ <Header
+ name="Clocks finite state machine"
+ customImage={"https://i1.sndcdn.com/artworks-000045941811-q634od-t500x500.jpg"}
+ roundImage={true}
+ subtext={`-5 members`}
+ gradient={["F27878", "D96B6B"]}
+ wave="web/waves/header/nucleus"
+ buttons={[]}
+ />
+ <AutoLayout>
+ <Panel>
+ <Title>Verify</Title>
+ <Divider name="commands"/>
+ <Text>Complete the check below to join ERROR</Text>
+ <div style={{height: "125px"}}>
+ <HCaptcha
+ id="Captchas mitigate problems"
+ sitekey="85074411-fa13-4d9b-b901-53095c6d1fc6"
+ onVerify={tkn => submitForm(tkn)}
+ theme="dark"
+ />
+ </div>
+ <List colour="F27878">
+ <ListItem>This is an automatic check performed by Nucleus.</ListItem>
+ <ListItem>By completing the CAPTCHA, you will be given the <code>MISSING</code> role in <code>ERROR</code>.</ListItem>
+ <ListItem>For the full list of data stored by Nucleus, please check <a href="https://clicksminuteper.github.io/policies/nucleus#verification">here</a></ListItem>
+ </List>
+ <div id="confetti" />
+ </Panel>
+ <Panel halfSize={false} id="invite">
+ <Title>Invite</Title>
+ <Divider />
+ <CardRow>
+ <Card
+ wave="nucleus"
+ icon="bots/nucleus/circle"
+ buttonText={"FFFFFF"} gradient={["F27878", "D96B6B"]}
+ title="Nucleus"
+ subtext="Invite Nucleus to your server"
+ buttons={[
+ {color: "424242", link: "https://discord.com/api/oauth2/authorize?client_id=715989276382462053&permissions=121295465718&scope=bot%20applications.commands", text: "Invite"}
+ ]}
+ url="https://discord.com/api/oauth2/authorize?client_id=715989276382462053&permissions=121295465718&scope=bot%20applications.commands"
+ />
+ </CardRow>
+ </Panel>
+ </AutoLayout>
+ </>
+}
+
+export default Verify;
diff --git a/pages/privacy.js b/pages/privacy.js
new file mode 100644
index 0000000..db621c5
--- /dev/null
+++ b/pages/privacy.js
@@ -0,0 +1,34 @@
+import Header from '../Components/Header'
+import { AutoLayout, Panel, Title, Subtitle, Text, Divider } from '../Components/Panels';
+import { List, ListItem, Code } from '../Components/Texttools';
+
+
+export default function Home() {
+ return (
+ <>
+ <Header
+ name="Privacy"
+ subtext="Privacy is a right - Here's how we handle it"
+ gradient={["71AFE5", "6576CC"]}
+ wave="web/waves/header/clicksforms"
+ buttons={[]}
+ />
+ <AutoLayout>
+ <Panel halfSize={true}>
+ <Title>Transparency</Title>
+ <Text>Everything we store about you and your Discord servers will be listed.</Text>
+ <List colour={"6576CC"}>
+ <ListItem><a href="https://clicksminuteper.github.io/policies/rsm">RSM</a></ListItem>
+ <ListItem><a href="https://clicksminuteper.github.io/policies/clicksforms">ClicksForms</a></ListItem>
+ <ListItem>GPS does not store any information</ListItem>
+ </List>
+ <Text>Have any questions or concerns? <a href="/support">Let us know</a> and we can investigate if you believe there are any mistakes</Text>
+ </Panel>
+ <Panel halfSize={true}>
+ <Title>Security</Title>
+ <Text>We will do everything we can to protect user data, including high security. You can <a href="/support">message us</a> if you would like to learn more about how we do this</Text>
+ </Panel>
+ </AutoLayout>
+ </>
+ )
+}
diff --git a/pages/rsmv/index.js b/pages/rsmv/index.js
index 175a271..f46c46e 100644
--- a/pages/rsmv/index.js
+++ b/pages/rsmv/index.js
@@ -4,7 +4,7 @@
import Axios from 'axios';
import Router from 'next/router';
import React from 'react';
-import Header from '../../Components/Header'
+import Header from '../../Components/Header';
import { AutoLayout, Panel, Title, Subtitle, Text, Divider } from '../../Components/Panels';
import { List, ListItem, Code } from '../../Components/Texttools';
diff --git a/styles/globals.module.css b/styles/globals.module.css
new file mode 100644
index 0000000..bed3151
--- /dev/null
+++ b/styles/globals.module.css
@@ -0,0 +1,19 @@
+.container {
+ position: fixed;
+ top: 42px;
+ height: calc(100vh - 42px);
+ width: 100%;
+ border-radius: 25px;
+ box-shadow: 0 0 0 100px black;
+ pointer-events: none;
+ background: transparent;
+}
+
+.container::-webkit-scrollbar {
+ display: none;
+}
+
+.container, .container * {
+ transform: rotateY(0);
+ -webkit-transform: rotateY(0);
+}
\ No newline at end of file
diff --git a/styles/nucleus/nucleus.module.css b/styles/nucleus/nucleus.module.css
new file mode 100644
index 0000000..391ddc0
--- /dev/null
+++ b/styles/nucleus/nucleus.module.css
@@ -0,0 +1,43 @@
+.center {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ flex-direction: column;
+ padding: 10px;
+}
+
+.center * {
+ margin-bottom: 20px;
+}
+
+.text {
+ color: var(--card-text-color);
+ font-size: 18px;
+ text-align: center;
+ padding-left: 10px;
+ padding-right: 10px;
+}
+
+.button {
+ border-radius: 5px;
+ background-color: var(--card-background-color);
+ color: var(--card-text-color);
+ border: 3px solid #F27878;
+ font-size: 20px;
+ padding-left: 10px;
+ padding-right: 10px;
+ margin-top: -40px;
+ transition: 0.3s;
+}
+
+.buttonComplete {
+ border: 3px solid #65CC76;
+}
+
+.button.clicked {
+ color: #F27878;
+}
+
+.buttonComplete.clicked {
+ color: #65CC76;
+}
diff --git a/todo/roles/about.js b/todo/roles/about.js
new file mode 100644
index 0000000..3c86b9a
--- /dev/null
+++ b/todo/roles/about.js
@@ -0,0 +1 @@
+export default function About(props) {}
\ No newline at end of file
diff --git a/todo/roles/failure.js b/todo/roles/failure.js
new file mode 100644
index 0000000..e188b06
--- /dev/null
+++ b/todo/roles/failure.js
@@ -0,0 +1 @@
+export default function Failure(props) {}
\ No newline at end of file
diff --git a/todo/roles/index.js b/todo/roles/index.js
new file mode 100644
index 0000000..8ddc9b8
--- /dev/null
+++ b/todo/roles/index.js
@@ -0,0 +1,92 @@
+import { Component } from 'react';
+import Styles from '../../../styles/nucleus/nucleus.module.css'
+import HCaptcha from 'react-hcaptcha';
+import Axios from 'axios';
+import Router from 'next/router';
+import React from 'react';
+import Header from '../../../Components/Header';
+
+import { AutoLayout, Panel, Title, Subtitle, Text, Divider } from '../../../Components/Panels';
+import { List, ListItem, Code } from '../../../Components/Texttools';
+
+class Verify extends Component {
+ constructor(props) {
+ super(props);
+ this.v = false;
+ this.state = {
+ captchaComplete: false,
+ clicked: false
+ }
+ }
+
+ async handleVerificationSuccess(cls, token) {
+ const chk = await Axios.put('/api/nucleus/verifyTkn', { tkn: token.toString() })
+ if(chk.data.success == true) {
+ this.setState({
+ captchaComplete: true
+ })
+ return cls.v = true;
+ } else {
+ return;
+ }
+ }
+
+ async submitForm(cls) {
+ if ( cls.state.clicked ) {
+ return
+ }
+ cls.setState({
+ clicked: true
+ })
+ if (!cls.v) {
+ return Router.push('/nucleus/verify/failure','/nucleus/verify/failure')
+ }
+ let code = await Axios.post('/api/nucleus/complete', {
+ uid:cls.props.uID,
+ rid:cls.props.rID,
+ gid:cls.props.gID,
+ code:cls.props.code
+ });
+ if (code.status === 200 ) return Router.push('/nucleus/verify/success','/nucleus/verify/success')
+ else return Router.push('/nucleus/verify/failure','/nucleus/verify/failure')
+ }
+
+ render() {
+ return <>
+ <Header
+ name={this.props.guild_name}
+ customImage={this.props.guild_icon_url}
+ roundImage={true}
+ subtext={`${this.props.memberCount} members`}
+ gradient={["F27878", "D96B6B"]}
+ wave="web/waves/header/nucleus"
+ buttons={[]}
+ />
+ <AutoLayout>
+ <Panel>
+ <Text>Complete the check below to join {this.props.guild_name}</Text>
+ <div style={{height: "125px"}}>
+ <HCaptcha
+ id="Captchas mitigate problems"
+ sitekey="85074411-fa13-4d9b-b901-53095c6d1fc6"
+ onVerify={token => this.handleVerificationSuccess(this, token)}
+ theme={this.theme ? "light" : "dark"}
+ />
+ </div>
+ <button type="button" className={Styles.button + " " + (this.state.captchaComplete ? Styles.buttonComplete : null)} onClick={(success) => this.submitForm(this)}>Proceed</button>
+ <List colour="F27878">
+ <ListItem>This is an automatic check performed by Nucleus.</ListItem>
+ <ListItem>By clicking Proceed, you will be given the <code>{this.props.role_name}</code> role in <code>{this.props.guild_name}</code>.</ListItem>
+ <ListItem>For the full list of data stored by Nucleus, please check <a href="https://clicksminuteper.github.io/policies/nucleus#verification">here</a></ListItem>
+ </List>
+ <Text>You can add Nucleus to your server by inviting it <a href="https://discord.com/api/oauth2/authorize?client_id=715989276382462053&permissions=121295465718&scope=bot%20applications.commands">here</a>.</Text>
+ <div id="confetti" />
+ </Panel>
+ </AutoLayout>
+ </>
+ }
+}
+
+export default Verify;
+export async function getServerSideProps(ctx) {
+}
\ No newline at end of file
diff --git a/todo/roles/success.js b/todo/roles/success.js
new file mode 100644
index 0000000..f7155ed
--- /dev/null
+++ b/todo/roles/success.js
@@ -0,0 +1 @@
+export default function Success(props) {}
\ No newline at end of file