Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
13 changes: 3 additions & 10 deletions src/ui/auth/AuthProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,9 @@
import React, { createContext, useContext, useState, useEffect } from 'react';
import { getUserInfo } from '../services/auth';

// Interface for when we convert to TypeScript
// interface AuthContextType {
// user: any;
// setUser: (user: any) => void;
// refreshUser: () => Promise<void>;
// isLoading: boolean;
// }
import { UserData } from '../../types/models';

interface AuthContextType {
user: any;
user: UserData | null;
setUser: React.Dispatch<any>;
refreshUser: () => Promise<void>;
isLoading: boolean;
Expand All @@ -19,7 +12,7 @@ interface AuthContextType {
const AuthContext = createContext<AuthContextType | undefined>(undefined);

export const AuthProvider: React.FC<React.PropsWithChildren<object>> = ({ children }) => {
const [user, setUser] = useState<any>(null);
const [user, setUser] = useState<UserData | null>(null);
const [isLoading, setIsLoading] = useState(true);

const refreshUser = async () => {
Expand Down
22 changes: 7 additions & 15 deletions src/ui/components/RouteGuard/RouteGuard.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,15 @@
import React, { useEffect, useState } from 'react';
import { Navigate } from 'react-router-dom';
import { useAuth } from '../../auth/AuthProvider';
import { getUIRouteAuth } from '../../services/config';
import { setUIRouteAuthData } from '../../services/config';
import { UIRouteAuth } from '../../../config/generated/config';
import CircularProgress from '@material-ui/core/CircularProgress';

interface RouteGuardProps {
component: React.ComponentType<any>;
fullRoutePath: string;
}

interface UIRouteAuth {
enabled: boolean;
rules: {
pattern: string;
adminOnly: boolean;
loginRequired: boolean;
}[];
}

const RouteGuard = ({ component: Component, fullRoutePath }: RouteGuardProps) => {
const { user, isLoading } = useAuth();

Expand All @@ -26,14 +18,14 @@ const RouteGuard = ({ component: Component, fullRoutePath }: RouteGuardProps) =>
const [authChecked, setAuthChecked] = useState(false);

useEffect(() => {
getUIRouteAuth((uiRouteAuth: UIRouteAuth) => {
setUIRouteAuthData((uiRouteAuth: UIRouteAuth) => {
if (uiRouteAuth?.enabled) {
for (const rule of uiRouteAuth.rules) {
if (new RegExp(rule.pattern).test(fullRoutePath)) {
for (const rule of uiRouteAuth.rules ?? []) {
if (new RegExp(rule.pattern ?? '').test(fullRoutePath)) {
// Allow multiple rules to be applied according to route precedence
// Ex: /dashboard/admin/* will override /dashboard/*
setLoginRequired(loginRequired || rule.loginRequired);
setAdminOnly(adminOnly || rule.adminOnly);
setLoginRequired(loginRequired || rule.loginRequired || false);
setAdminOnly(adminOnly || rule.adminOnly || false);
}
}
}
Expand Down
29 changes: 15 additions & 14 deletions src/ui/services/auth.js → src/ui/services/auth.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
import { getCookie } from '../utils';
import { UserData } from '../../types/models';
import { API_BASE } from '../apiBase';
import { AxiosError } from 'axios';

const baseUrl = import.meta.env.VITE_API_URI
? `${import.meta.env.VITE_API_URI}`
: `${location.origin}`;
interface AxiosConfig {
withCredentials: boolean;
headers: {
'X-CSRF-TOKEN': string;
Authorization?: string;
};
}

/**
* Gets the current user's information
* @return {Promise<Object>} The user's information
*/
export const getUserInfo = async () => {
export const getUserInfo = async (): Promise<UserData | null> => {
try {
const response = await fetch(`${baseUrl}/api/auth/me`, {
const response = await fetch(`${API_BASE}/api/auth/me`, {
credentials: 'include', // Sends cookies
});

if (!response.ok) throw new Error(`Failed to fetch user info: ${response.statusText}`);

return await response.json();
} catch (error) {
console.error('Error fetching user info:', error);
Expand All @@ -25,9 +29,8 @@ export const getUserInfo = async () => {

/**
* Gets the Axios config for the UI
* @return {Object} The Axios config
*/
export const getAxiosConfig = () => {
export const getAxiosConfig = (): AxiosConfig => {
const jwtToken = localStorage.getItem('ui_jwt_token');
return {
withCredentials: true,
Expand All @@ -40,11 +43,9 @@ export const getAxiosConfig = () => {

/**
* Processes authentication errors and returns a user-friendly error message
* @param {Object} error - The error object
* @return {string} The error message
*/
export const processAuthError = (error, jwtAuthEnabled = false) => {
let errorMessage = `Failed to authorize user: ${error.response.data.trim()}. `;
export const processAuthError = (error: AxiosError<any>, jwtAuthEnabled = false): string => {
let errorMessage = `Failed to authorize user: ${error.response?.data?.trim() ?? ''}. `;
if (jwtAuthEnabled && !localStorage.getItem('ui_jwt_token')) {
errorMessage +=
'Set your JWT token in the settings page or disable JWT auth in your app configuration.';
Expand Down
35 changes: 0 additions & 35 deletions src/ui/services/config.js

This file was deleted.

36 changes: 36 additions & 0 deletions src/ui/services/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import axios from 'axios';
import { API_BASE } from '../apiBase';
import { FormQuestion } from '../views/PushDetails/components/AttestationForm';
import { UIRouteAuth } from '../../config/generated/config';

const API_V1_BASE = `${API_BASE}/api/v1`;

const setAttestationConfigData = async (setData: (data: FormQuestion[]) => void) => {
const url = new URL(`${API_V1_BASE}/config/attestation`);
await axios(url.toString()).then((response) => {
setData(response.data.questions);
});
};

const setURLShortenerData = async (setData: (data: string) => void) => {
const url = new URL(`${API_V1_BASE}/config/urlShortener`);
await axios(url.toString()).then((response) => {
setData(response.data);
});
};

const setEmailContactData = async (setData: (data: string) => void) => {
const url = new URL(`${API_V1_BASE}/config/contactEmail`);
await axios(url.toString()).then((response) => {
setData(response.data);
});
};

const setUIRouteAuthData = async (setData: (data: UIRouteAuth) => void) => {
const url = new URL(`${API_V1_BASE}/config/uiRouteAuth`);
await axios(url.toString()).then((response) => {
setData(response.data);
});
};

export { setAttestationConfigData, setURLShortenerData, setEmailContactData, setUIRouteAuthData };
110 changes: 0 additions & 110 deletions src/ui/services/git-push.js

This file was deleted.

Loading
Loading