From 0309638909fe5b107366ff8e288ca25352221677 Mon Sep 17 00:00:00 2001
From: Hassan Abouelela <47495861+HassanAbouelela@users.noreply.github.com>
Date: Sat, 13 Feb 2021 00:26:45 +0300
Subject: Adds Basic Auth Functionality
Moves all authorization functionality to a new file, and adds a helper
to send discord OAuth code to the backend, and set JWT. Adds a library
to read and set cookies.
Signed-off-by: Hassan Abouelela <47495861+HassanAbouelela@users.noreply.github.com>
---
src/pages/CallbackPage.tsx | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
(limited to 'src/pages')
diff --git a/src/pages/CallbackPage.tsx b/src/pages/CallbackPage.tsx
index fab2086..00feb76 100644
--- a/src/pages/CallbackPage.tsx
+++ b/src/pages/CallbackPage.tsx
@@ -7,11 +7,12 @@ export default function CallbackPage(): JSX.Element {
const params = new URLSearchParams(location.search);
const code = params.get("code");
+ const state = params.get("state");
if (!hasSent) {
setHasSent(true);
- window.opener.postMessage(code);
+ window.opener.postMessage({code: code, state: state});
}
- return
Code is {code}
;
+ return ;
}
--
cgit v1.2.3
From edcdc9b18dddb30f2726da282efcf77ab5ad3c1a Mon Sep 17 00:00:00 2001
From: Hassan Abouelela <47495861+HassanAbouelela@users.noreply.github.com>
Date: Sat, 13 Feb 2021 00:27:03 +0300
Subject: Cleans Up OAuth Button
Removes OAuth button from home page, and redesigns it. Uses new
authorization functionality in auth.
Signed-off-by: Hassan Abouelela <47495861+HassanAbouelela@users.noreply.github.com>
---
src/components/OAuth2Button.tsx | 91 +++++++-----------------------
src/pages/LandingPage.tsx | 11 +---
src/tests/components/OAuth2Button.test.tsx | 2 +-
3 files changed, 23 insertions(+), 81 deletions(-)
(limited to 'src/pages')
diff --git a/src/components/OAuth2Button.tsx b/src/components/OAuth2Button.tsx
index 4fa3f61..231e560 100644
--- a/src/components/OAuth2Button.tsx
+++ b/src/components/OAuth2Button.tsx
@@ -1,88 +1,39 @@
/** @jsx jsx */
import { css, jsx } from "@emotion/react";
+import { useState } from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faDiscord } from "@fortawesome/free-brands-svg-icons";
-import colors from "../colors";
-import { useState } from "react";
-
-const OAUTH2_CLIENT_ID = process.env.REACT_APP_OAUTH2_CLIENT_ID;
+import authenticate, { OAuthScopes } from "../api/auth";
-const buttonStyling = css`
-display: flex;
-background-color: ${colors.blurple};
-border: none;
-color: white;
-font-family: "Hind", "Helvetica", "Arial", sans-serif;
-border-radius: 5px;
-padding-top: 10px;
-padding-bottom: 10px;
-padding-right: 20px;
-padding-left: 20px;
-outline: none;
-transition: filter 100ms;
-font-size: 1.2em;
-align-items: center;
-
-span {
- vertical-align: middle;
-}
-&:hover:enabled {
- filter: brightness(110%);
- cursor: pointer;
+interface OAuth2ButtonProps {
+ scopes?: OAuthScopes[],
+ path?: string
}
-&:disabled {
- background-color: ${colors.greyple};
-}
+const iconStyles = css`
+ position: relative;
+ top: 0.3rem;
+ padding-left: 0.65rem;
+ font-size: 1.2em;
`;
-function doLogin(disableFunction: (newState: boolean) => void) {
- disableFunction(true);
-
- const redirectURI = encodeURIComponent(document.location.protocol + "//" + document.location.host + "/callback");
-
- const windowRef = window.open(
- `https://discord.com/api/oauth2/authorize?client_id=${OAUTH2_CLIENT_ID}&response_type=code&scope=identify&redirect_uri=${redirectURI}&prompt=none`,
- "Discord_OAuth2",
- "height=700,width=500,location=no,menubar=no,resizable=no,status=no,titlebar=no,left=300,top=300"
- );
-
- const interval = setInterval(() => {
- if (windowRef?.closed) {
- clearInterval(interval);
- disableFunction(false);
- }
- }, 500);
-
- window.onmessage = (code: MessageEvent) => {
- if (code.data.source) {
- // React DevTools has a habit of sending messages, ignore them.
- return;
- }
-
- if (code.isTrusted) {
- windowRef?.close();
-
- console.log("Code received:", code.data);
-
- disableFunction(false);
- clearInterval(interval);
-
- window.onmessage = null;
- }
- };
-}
+const textStyles = css`
+ display: inline-block;
+ padding: 0.5rem 0.75rem 0.5rem 0.5rem;
+`;
-function OAuth2Button(): JSX.Element {
+function OAuth2Button(props: OAuth2ButtonProps): JSX.Element {
const [disabled, setDisabled] = useState(false);
- return ;
+ return (
+
+ );
}
export default OAuth2Button;
diff --git a/src/pages/LandingPage.tsx b/src/pages/LandingPage.tsx
index 06fef46..efb3f05 100644
--- a/src/pages/LandingPage.tsx
+++ b/src/pages/LandingPage.tsx
@@ -4,7 +4,6 @@ import { useEffect, useState } from "react";
import HeaderBar from "../components/HeaderBar";
import FormListing from "../components/FormListing";
-import OAuth2Button from "../components/OAuth2Button";
import Loading from "../components/Loading";
import ScrollToTop from "../components/ScrollToTop";
@@ -28,16 +27,8 @@ function LandingPage(): JSX.Element {
-
+
Available Forms
-
-
-
-
{forms.map(form => (
))}
diff --git a/src/tests/components/OAuth2Button.test.tsx b/src/tests/components/OAuth2Button.test.tsx
index f05159f..a773686 100644
--- a/src/tests/components/OAuth2Button.test.tsx
+++ b/src/tests/components/OAuth2Button.test.tsx
@@ -4,7 +4,7 @@ import OAuth2Button from "../../components/OAuth2Button";
test("renders oauth2 sign in button text", () => {
const { getByText } = render();
- const button = getByText(/Sign in with Discord/i);
+ const button = getByText(/Discord Login/i);
expect(button).toBeInTheDocument();
});
--
cgit v1.2.3
From 451c825c77cd68eafeb262eb1ea5cbfc21dce550 Mon Sep 17 00:00:00 2001
From: Hassan Abouelela <47495861+HassanAbouelela@users.noreply.github.com>
Date: Sat, 13 Feb 2021 01:21:36 +0300
Subject: Dynamically Show Discord OAuth Button
Dynamically displays an auth button in place of the submit button if
needed, and adds full authorization flow.
Signed-off-by: Hassan Abouelela <47495861+HassanAbouelela@users.noreply.github.com>
---
src/commonStyles.tsx | 32 ++++++++++++++++++++
src/components/OAuth2Button.tsx | 14 +++++++--
src/pages/FormPage.tsx | 65 ++++++++++++++++++++---------------------
3 files changed, 74 insertions(+), 37 deletions(-)
(limited to 'src/pages')
diff --git a/src/commonStyles.tsx b/src/commonStyles.tsx
index 89a2746..eb3e319 100644
--- a/src/commonStyles.tsx
+++ b/src/commonStyles.tsx
@@ -1,4 +1,5 @@
import { css } from "@emotion/react";
+import colors from "./colors";
const selectable = css`
-moz-user-select: text;
@@ -50,6 +51,36 @@ const textInputs = css`
border-radius: 8px;
`;
+const submitStyles = css`
+ text-align: right;
+
+ button:disabled {
+ background-color: ${colors.greyple};
+ cursor: default;
+ }
+
+ button {
+ cursor: pointer;
+
+ border: none;
+ border-radius: 8px;
+
+ color: white;
+ font: inherit;
+
+ background-color: ${colors.blurple};
+ transition: background-color 300ms;
+ }
+
+ button[type="submit"] {
+ padding: 0.55rem 4.25rem;
+ }
+
+ button:enabled:hover {
+ background-color: ${colors.darkerBlurple};
+ }
+`;
+
export {
selectable,
@@ -57,4 +88,5 @@ export {
hiddenInput,
multiSelectInput,
textInputs,
+ submitStyles
};
diff --git a/src/components/OAuth2Button.tsx b/src/components/OAuth2Button.tsx
index 231e560..90a25fa 100644
--- a/src/components/OAuth2Button.tsx
+++ b/src/components/OAuth2Button.tsx
@@ -5,12 +5,13 @@ import { useState } from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faDiscord } from "@fortawesome/free-brands-svg-icons";
-import authenticate, { OAuthScopes } from "../api/auth";
+import authenticate, {checkScopes, OAuthScopes} from "../api/auth";
interface OAuth2ButtonProps {
scopes?: OAuthScopes[],
- path?: string
+ path?: string,
+ rerender: () => void
}
const iconStyles = css`
@@ -27,9 +28,16 @@ const textStyles = css`
function OAuth2Button(props: OAuth2ButtonProps): JSX.Element {
const [disabled, setDisabled] = useState(false);
+ async function login() {
+ await authenticate(props.scopes, setDisabled, props.path);
+
+ if (checkScopes(props.scopes, props.path)) {
+ props.rerender();
+ }
+ }
return (
-
- { submit }
+
{ submit }
);
}
@@ -146,7 +136,7 @@ const closedHeaderStyles = css`
font-size: 1.5rem;
background-color: ${colors.error};
-
+
@media (max-width: 500px) {
padding: 1rem 1.5rem;
}
@@ -186,6 +176,13 @@ function FormPage(): JSX.Element {
}
const open: boolean = form.features.includes(FormFeatures.Open);
+ const require_auth: boolean = form.features.includes(FormFeatures.RequiresLogin);
+
+ const scopes = [];
+ if (require_auth) {
+ scopes.push(OAuthScopes.Identify);
+ if (form.features.includes(FormFeatures.CollectEmail)) { scopes.push(OAuthScopes.Email); }
+ }
let closed_header = null;
if (!open) {
@@ -201,7 +198,7 @@ function FormPage(): JSX.Element {
{ closed_header }
{ questions }
-
+
--
cgit v1.2.3
From fba316f235a3871743427f37b3bbd07bea6d77bd Mon Sep 17 00:00:00 2001
From: Hassan Abouelela <47495861+HassanAbouelela@users.noreply.github.com>
Date: Wed, 17 Feb 2021 09:30:47 +0300
Subject: Removes Path From Auth
Signed-off-by: Hassan Abouelela <47495861+HassanAbouelela@users.noreply.github.com>
---
src/api/auth.ts | 23 +++++++++++------------
src/components/OAuth2Button.tsx | 5 ++---
src/pages/FormPage.tsx | 6 ++----
3 files changed, 15 insertions(+), 19 deletions(-)
(limited to 'src/pages')
diff --git a/src/api/auth.ts b/src/api/auth.ts
index ad97e67..cfaa563 100644
--- a/src/api/auth.ts
+++ b/src/api/auth.ts
@@ -91,11 +91,11 @@ function ensureMinimumScopes(scopes: unknown, expected: OAuthScopes | OAuthScope
/**
* Return true if the program has the requested scopes or higher.
*/
-export function checkScopes(scopes?: OAuthScopes[], path = ""): boolean {
+export function checkScopes(scopes?: OAuthScopes[]): boolean {
const cleanedScopes = ensureMinimumScopes(scopes, OAuthScopes.Identify);
// Get Active Scopes And Ensure Type
- const cookies = new Cookies().get(CookieNames.Scopes + path);
+ const cookies = new Cookies().get(CookieNames.Scopes);
if (!cookies || !Array.isArray(cookies)) {
return false;
}
@@ -169,7 +169,7 @@ export async function getDiscordCode(scopes: OAuthScopes[]): Promise<{code: stri
}
/**
- * Sends a discord code from a given path to the backend,
+ * Sends a discord code to the backend,
* and returns the resultant JWT and expiry date.
*
* @throws { APIErrors } On error, the APIErrors.Message is set, and an APIErrors object is thrown.
@@ -218,27 +218,26 @@ export async function requestBackendJWT(code: string): Promise {
}
/**
- * Handle a full authorization flow. Sets a token for the specified path with the JWT and scopes.
+ * Handle a full authorization flow. Sets a cookie with the JWT and scopes.
*
* @param scopes The scopes that should be authorized for the application.
* @param disableFunction An optional function that can disable a component while processing.
- * @param path The site path to save the token under.
*
* @throws { APIErrors } See documentation on { requestBackendJWT }.
*/
-export default async function authorize(scopes: OAuthScopes[] = [], disableFunction?: (newState: boolean) => void, path = "/"): Promise {
- if (!checkScopes(scopes, path)) {
+export default async function authorize(scopes: OAuthScopes[] = [], disableFunction?: (newState: boolean) => void): Promise {
+ if (!checkScopes(scopes)) {
const cookies = new Cookies;
- cookies.remove(CookieNames.Token + path);
- cookies.remove(CookieNames.Scopes + path);
+ cookies.remove(CookieNames.Token);
+ cookies.remove(CookieNames.Scopes);
if (disableFunction) { disableFunction(true); }
await getDiscordCode(scopes).then(async discord_response =>{
await requestBackendJWT(discord_response.code).then(backend_response => {
- const options: CookieSetOptions = {sameSite: "strict", expires: backend_response.Expiry, secure: PRODUCTION, path: path};
+ const options: CookieSetOptions = {sameSite: "strict", expires: backend_response.Expiry, secure: PRODUCTION};
- cookies.set(CookieNames.Token + path, backend_response.JWT, options);
- cookies.set(CookieNames.Scopes + path, discord_response.cleanedScopes, options);
+ cookies.set(CookieNames.Token, backend_response.JWT, options);
+ cookies.set(CookieNames.Scopes, discord_response.cleanedScopes, options);
});
}).finally(() => {
if (disableFunction) { disableFunction(false); }
diff --git a/src/components/OAuth2Button.tsx b/src/components/OAuth2Button.tsx
index 1ee456c..25c5871 100644
--- a/src/components/OAuth2Button.tsx
+++ b/src/components/OAuth2Button.tsx
@@ -11,7 +11,6 @@ import { selectable } from "../commonStyles";
interface OAuth2ButtonProps {
scopes?: OAuthScopes[],
- path?: string,
rerender: () => void
}
@@ -47,7 +46,7 @@ const errorStyles = css`
`;
async function login(props: OAuth2ButtonProps, errorDialog: React.RefObject, setDisabled: (newState: boolean) => void) {
- await authenticate(props.scopes, setDisabled, props.path).catch((reason: APIErrors) => {
+ await authenticate(props.scopes, setDisabled).catch((reason: APIErrors) => {
// Display Error Message
if (errorDialog.current) {
errorDialog.current.style.visibility = "visible";
@@ -60,7 +59,7 @@ async function login(props: OAuth2ButtonProps, errorDialog: React.RefObject {
- PAGE_PATH = "/form"
-
containerStyles = css`
margin: auto;
width: 50%;
@@ -97,9 +95,9 @@ class Navigation extends React.Component {
let submit = null;
if (this.props.form_state) {
- if (this.props.scopes.includes(OAuthScopes.Identify) && !checkScopes(this.props.scopes, this.PAGE_PATH)) {
+ if (this.props.scopes.includes(OAuthScopes.Identify) && !checkScopes(this.props.scopes)) {
// Render OAuth button if login is required, and the scopes needed are not available
- submit = this.setState({"logged_in": true})}/>;
+ submit = this.setState({"logged_in": true})}/>;
} else {
submit = Submit;
}
--
cgit v1.2.3
From 9f04d5f5effd07534c9eb5b9f8886c8f970d0dc6 Mon Sep 17 00:00:00 2001
From: Hassan Abouelela <47495861+HassanAbouelela@users.noreply.github.com>
Date: Sun, 7 Mar 2021 00:46:47 +0300
Subject: Fixes Return Home Button Centering
Fixes the centering of the return home button on closed forms, by
removing the style wrapper.
Signed-off-by: Hassan Abouelela <47495861+HassanAbouelela@users.noreply.github.com>
---
src/components/OAuth2Button.tsx | 6 +++---
src/pages/FormPage.tsx | 8 +++++---
2 files changed, 8 insertions(+), 6 deletions(-)
(limited to 'src/pages')
diff --git a/src/components/OAuth2Button.tsx b/src/components/OAuth2Button.tsx
index 25c5871..885c080 100644
--- a/src/components/OAuth2Button.tsx
+++ b/src/components/OAuth2Button.tsx
@@ -31,16 +31,16 @@ const errorStyles = css`
visibility: hidden;
width: 100%;
left: 0;
-
+
text-align: center;
white-space: normal;
box-sizing: border-box;
-
+
padding: 0 15rem;
@media (max-width: 750px) {
padding: 0 5rem;
}
-
+
color: red;
margin-top: 2.5rem;
`;
diff --git a/src/pages/FormPage.tsx b/src/pages/FormPage.tsx
index fa63282..8852ac5 100644
--- a/src/pages/FormPage.tsx
+++ b/src/pages/FormPage.tsx
@@ -96,12 +96,14 @@ class Navigation extends React.Component {
let submit = null;
if (this.props.form_state) {
+ let inner_submit;
if (this.props.scopes.includes(OAuthScopes.Identify) && !checkScopes(this.props.scopes)) {
// Render OAuth button if login is required, and the scopes needed are not available
- submit = this.setState({"logged_in": true})}/>;
+ inner_submit = this.setState({"logged_in": true})}/>;
} else {
- submit = Submit;
+ inner_submit = Submit;
}
+ submit = { inner_submit }
;
}
return (
@@ -110,7 +112,7 @@ class Navigation extends React.Component {
Return Home
- { submit }
+ { submit }
);
}
--
cgit v1.2.3