Skip to content

Commit

Permalink
feat: add basic 2fa support to admin panel
Browse files Browse the repository at this point in the history
  • Loading branch information
cooperj committed Feb 3, 2025
1 parent 2e97bcf commit a0fd2b2
Show file tree
Hide file tree
Showing 9 changed files with 1,018 additions and 1,032 deletions.
2,014 changes: 991 additions & 1,023 deletions admin/package-lock.json

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions admin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@
},
"dependencies": {
"@astrojs/check": "^0.9.4",
"@astrojs/node": "^8.3.4",
"@astrojs/react": "^3.6.2",
"@astrojs/tailwind": "^5.1.1",
"@astrojs/node": "^9.0.2",
"@astrojs/react": "^4.2.0",
"@astrojs/tailwind": "^6.0.0",
"@hookform/resolvers": "^3.6.0",
"@radix-ui/react-avatar": "^1.0.4",
"@radix-ui/react-checkbox": "^1.0.4",
Expand All @@ -40,7 +40,7 @@
"@tanstack/react-table": "^8.17.3",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"astro": "^4.15.11",
"astro": "^5.2.3",
"astro-icon": "^1.1.0",
"axios": "^1.7.2",
"class-variance-authority": "^0.7.0",
Expand Down
9 changes: 8 additions & 1 deletion admin/src/components/auth/loginForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export default function LoginForm() {
const handleLogin = (event: React.FormEvent<HTMLFormElement>): void => {
// Prevent page reload
event.preventDefault();
const { username, password } = document.forms[0];
const { username, password, totp } = document.forms[0];
const queryParameters = new URLSearchParams(window.location.search);
const redirect = queryParameters.get("redirect");

Expand All @@ -21,6 +21,7 @@ export default function LoginForm() {
{
username: username.value,
password: password.value,
totp: totp.value
},
{
timeout: 15000, // 15 seconds timeout
Expand Down Expand Up @@ -61,6 +62,12 @@ export default function LoginForm() {
autoComplete="current-password"
name="password"
/>
<Input
type="text"
placeholder="2FA Code"
autoComplete="username"
name="totp"
/>
<div className="flex w-full flex-col">
<Button type="submit" variant={"primaryOutline"}>
Login
Expand Down
3 changes: 3 additions & 0 deletions admin/src/components/users/userPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,9 @@ export function UserPage(props: Props) {
<h2 className="font-medium text 3xl">
{user.role} - Joined{" "}
{new Date(user.creationDate).toLocaleDateString()}
<p className="text-green-600">
{user.totpEnabled ? "2FA Enabled" : ""}
</p>
</h2>
</div>
</div>
Expand Down
1 change: 1 addition & 0 deletions admin/src/components/users/userSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@ export default function UserSettings() {
<h2 className="font-medium text 3xl">
{user.role} - Joined{" "}
{new Date(user.creationDate).toLocaleDateString()}
<p className="text-green-600">{user.totpEnabled ? "2FA Enabled" : ""}</p>
</h2>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion admin/src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export const API_URL = import.meta.env.PUBLIC_API_URL || "https://asgard.socstech.support";
export const API_URL = import.meta.env.PUBLIC_API_URL || "http://localhost:3000";
export const Y2_URL = import.meta.env.PUBLIC_Y2_URL || "https://yggdrasil.socstech.support";
export const PUBLIC_ROUTES = [ "/login", "/forgot-password", "/change-password" ]

Expand Down
2 changes: 2 additions & 0 deletions admin/src/interfaces/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ export interface IUser {
creationDate: Date;
profilePictureUrl?: string;
isDeleted: boolean;
totpEnabled: boolean;
totpSecret: string;
}

export const UserRoles = [
Expand Down
4 changes: 4 additions & 0 deletions api/src/controllers/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,10 @@ const disableTotp = async (req: Request, res: Response, next: NextFunction) => {
return
}

const updatedUser = await db.update(userSchema)
.set({ totpSecret: "", totpEnabled: false })
.where(eq(userSchema.id, user[0].id));

res.status(201).json({ "message": "2FA has been disabled for your account.", "username": user[0].username, "userId": user[0].id })
}

Expand Down
7 changes: 4 additions & 3 deletions api/src/utils/users.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { db } from "@/db";
import {users as userSchema } from '@/db/schema';
import { users as userSchema } from '@/db/schema';
import { eq, and } from 'drizzle-orm';
const crypto = require("crypto");

Expand All @@ -14,7 +14,8 @@ export const simplifiedUser = {
email: userSchema.email,
creationDate: userSchema.creationDate,
profilePictureUrl: userSchema.profilePictureUrl,
isDeleted: userSchema.isDeleted
isDeleted: userSchema.isDeleted,
totpEnabled: userSchema.totpEnabled
};

// // Schema of New User
Expand All @@ -39,6 +40,6 @@ export const isUserATechnician = async (userId: string): Promise<boolean> => {
eq(userSchema.isDeleted, false))
);

if (admin[0].role === "TECHNICIAN") { return true}
if (admin[0].role === "TECHNICIAN") { return true }
else { return false }
};

0 comments on commit a0fd2b2

Please sign in to comment.