Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(login): integrated login form component #47

Merged
merged 32 commits into from
Oct 30, 2023
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
2a0f5d9
created API route, custom options
connordoman Oct 23, 2023
7eb1093
begin login form
connordoman Oct 24, 2023
15992e2
login form built
connordoman Oct 24, 2023
9d241d9
login form improved
connordoman Oct 24, 2023
10e4bbf
login form functional
connordoman Oct 24, 2023
17a0732
login page works
connordoman Oct 24, 2023
fbf661c
created API route, custom options
connordoman Oct 23, 2023
6f32656
begin login form
connordoman Oct 24, 2023
3bc9165
login form built
connordoman Oct 24, 2023
2372a70
general styling almost completed
linhnnk Oct 29, 2023
fcb2021
added assets folder
linhnnk Oct 30, 2023
13e6367
breakout header and footer
connordoman Oct 30, 2023
8d9a98a
improve generated env
connordoman Oct 30, 2023
bb8775c
theme colors
connordoman Oct 30, 2023
bc5ac6a
login form is now card
connordoman Oct 30, 2023
5cca6ef
update gitignore
connordoman Oct 30, 2023
c071ab5
incorporate styles
connordoman Oct 30, 2023
cb992f5
auth pulls directly from json
connordoman Oct 30, 2023
daca6a5
feat(auth): redirect after login
connordoman Oct 30, 2023
7bcf860
fix(auth): change redirect to /video-upload
connordoman Oct 30, 2023
ebdcf15
fix(nextjs): dependency resolution
connordoman Oct 30, 2023
4fe6d0c
fix(tests): refactored tests, passing
connordoman Oct 30, 2023
56d1de7
fix(git): track only front end images
connordoman Oct 30, 2023
b1210ba
fix(review): dev port, root gitignore
connordoman Oct 30, 2023
fdd8e86
tweak(nextjs): improved .env generator script
connordoman Oct 30, 2023
7498e3b
fix(docs): better explain bcrypt hash
connordoman Oct 30, 2023
bae5b70
fix(docs): swap btoa and atob
connordoman Oct 30, 2023
3aba078
tweak(auth): transmit password as base64
connordoman Oct 30, 2023
05537b7
fix(review): do not transmit in base64
connordoman Oct 30, 2023
cebab63
tweak(nextjs): improve .env generator
connordoman Oct 30, 2023
5c8dbb9
tweak(layout): simplify homepage layout
connordoman Oct 30, 2023
a1c1c60
fix(tests): update homepage tests
connordoman Oct 30, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions app/front-end/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,7 @@ next-env.d.ts

# Logs
*.log

# preserve front end images
!./**/*.png
!./**/*.jpg
29 changes: 1 addition & 28 deletions app/front-end/__tests__/__snapshots__/index.test.tsx.snap
Original file line number Diff line number Diff line change
@@ -1,37 +1,10 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Home homepage is unchanged from snapshot 1`] = `
exports[`Home Page homepage is unchanged from snapshot 1`] = `
<div>
<main
class="column"
>
<div
class="masthead"
>
<h1
class="heading"
>
PrivacyPal
</h1>
<h2
class="subheading"
>
COSC 499 Capstone Team 1
</h2>
</div>
<p>
Here is a patternfly example component:
</p>
<button
aria-disabled="false"
class="pf-v5-c-button pf-m-primary example-button"
data-ouia-component-id="PatternflyExampleComponentPrimaryButton"
data-ouia-component-type="PF5/Button"
data-ouia-safe="true"
type="button"
>
Patternfly Button
</button>
<h2
class="subheading"
>
Expand Down
22 changes: 22 additions & 0 deletions app/front-end/__tests__/base64.lib.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Created on Mon Oct 30 2023
* Author: Connor Doman
*/

import { base64ToUtf8, utf8ToBase64 } from "@lib/base64";

describe("base64ToUtf8", () => {
it("should convert base64 to utf8", () => {
const base64 = "SGVsbG8gV29ybGQ=";
const utf8 = "Hello World";
expect(base64ToUtf8(base64)).toBe(utf8);
});
});

describe("utf8ToBase64", () => {
it("should convert utf8 to base64", () => {
const base64 = "SGVsbG8gV29ybGQ=";
const utf8 = "Hello World";
expect(utf8ToBase64(utf8)).toBe(base64);
});
});
35 changes: 0 additions & 35 deletions app/front-end/__tests__/config.lib.test.ts

This file was deleted.

18 changes: 15 additions & 3 deletions app/front-end/__tests__/dummy-authenticator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@
* Author: Connor Doman
*/

import { extractConfigFile } from "@lib/config";
import { utf8ToBase64 } from "@lib/base64";
import { DummyAuthenticator } from "@lib/dummy-authenticator";

describe("Dummy Authenticator", () => {
it("works for valid credentials", async () => {
const dummyAuthenticator = new DummyAuthenticator();
const credentials = { email: "johnny@example.com", password: "password" };
DummyAuthenticator.configDirectory = "./conf/";
const user = await dummyAuthenticator.authorize(credentials, {} as any);
expect(user).toEqual({
id: "1",
Expand All @@ -21,7 +20,6 @@ describe("Dummy Authenticator", () => {
it("fails for invalid credentials", async () => {
const dummyAuthenticator = new DummyAuthenticator();
const credentials = { email: "johnny@example.com", password: "wrongpassword" };
DummyAuthenticator.configDirectory = "./conf/";
const user = await dummyAuthenticator.authorize(credentials, {} as any);
expect(user).toEqual(null);
});
Expand All @@ -38,4 +36,18 @@ describe("Dummy Authenticator", () => {
password: { label: "Password", type: "password" },
});
});

it("authentication fails if hashedPassword is empty", async () => {
const dummyAuthenticator = new DummyAuthenticator();
const credentials = { email: "badatpasswords@example.com", password: "password" };
const user = await dummyAuthenticator.authorize(credentials, {} as any);
expect(user).toEqual(null);
});

it("authentication fails if empty password is provided", async () => {
const dummyAuthenticator = new DummyAuthenticator();
const credentials = { email: "johnny@example.com", password: "" };
const user = await dummyAuthenticator.authorize(credentials, {} as any);
expect(user).toEqual(null);
});
});
10 changes: 5 additions & 5 deletions app/front-end/__tests__/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ import Home from "../src/app/page";
import "@testing-library/jest-dom";

/* Example Test: Does the page at `/` render a header? (Should FAIL) */
describe("Home", () => {
it("page has 'PrivacyPal' semantic heading", () => {
render(<Home useAuth={false} />);
expect(screen.getByRole("heading", { name: "PrivacyPal" })).toBeInTheDocument();
describe("Home Page", () => {
it("page has 'Test Login' render properly semantic heading", () => {
render(<Home />);
expect(screen.getByRole("heading", { name: "Test Login" })).toBeInTheDocument();
});

it("homepage is unchanged from snapshot", () => {
const { container } = render(<Home useAuth={false} />);
const { container } = render(<Home />);
expect(container).toMatchSnapshot();
});
});
12 changes: 10 additions & 2 deletions app/front-end/conf/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,15 @@ interface PrivacyPalUserProperties {
Where `password` is a base64 encoded `bcrypt` hash of the user's password:

```typescript
const password = btoa(await bcrypt.hash(userPassword, 10));
const password: string = utf8ToBase64(await bcrypt.hash(userPassword, 10));
```

The sample file features a user with the email `johnny@example.com` and password `password`.
In this case, `10` is the number of salt rounds used by `bcrypt`. When comparing passwords for authentication, `bcrypt` will use the salt stored in the hash to generate a new hash and compare the two hashes. If the hashes match, the passwords match.

This means it is necessary to use `bcrypt.compare()` as such:

```typescript
const passwordMatches: boolean = await bcrypt.compare(userPassword, base64ToUtf8(storedPassword));
```

The sample file features a user with the email `johnny@example.com` and password `password` and another user whose email is `badatpasswords@example.com` and has no password.
7 changes: 6 additions & 1 deletion app/front-end/conf/user.properties.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@
{
"id": "1",
"email": "johnny@example.com",
"hashedPassword": "JDJiJDEwJDQwR0psSWo3Q08zcEhTVkpTVTNhbU9QQmZlYWl1dk1SL2dTMlZCclAuOGIuMjdiZFJTYjVp"
"hashedPassword": "JDJhJDEwJFV2ZnpHekFrbEtvZlljenNYZHZHR2VjaGRVY29BdHM1SjhBWU51a1RUQzdTQXZOT0VDVHVT"
},
{
"id": "2",
"email": "badatpasswords@example.com",
"hashedPassword": ""
}
]
}
10 changes: 10 additions & 0 deletions app/front-end/generate_dev_env.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash

# Create `.env.local` file for development environment
{
echo NEXTAUTH_SECRET="$(openssl rand -base64 32)"
echo NEXTAUTH_URL="http://localhost:${PORT:-8081}"
echo PRIVACYPAL_INPUT_VIDEO_DIR="../back-end/video-processing/input"
tthvo marked this conversation as resolved.
Show resolved Hide resolved
echo PRIVACYPAL_OUTPUT_VIDEO_DIR="../back-end/video-processing/output"
echo PRIVACYPAL_CONFIG_DIR="./conf"
} > .env.local
6 changes: 3 additions & 3 deletions app/front-end/next.config.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
// https://nextjs.org/docs/pages/api-reference/next-config-js/output#automatically-copying-traced-files
output: 'standalone',
}
output: "standalone",
};

module.exports = nextConfig
module.exports = nextConfig;
Loading
Loading