yangdx commited on
Commit
382e628
·
1 Parent(s): 030c42e

Fix linting

Browse files
lightrag/api/auth.py CHANGED
@@ -17,18 +17,26 @@ class AuthHandler:
17
  self.secret = os.getenv("TOKEN_SECRET", "4f85ds4f56dsf46")
18
  self.algorithm = "HS256"
19
  self.expire_hours = int(os.getenv("TOKEN_EXPIRE_HOURS", 4))
20
- self.guest_expire_hours = int(os.getenv("GUEST_TOKEN_EXPIRE_HOURS", 2)) # Guest token default expiration time
 
 
21
 
22
- def create_token(self, username: str, role: str = "user", custom_expire_hours: int = None, metadata: dict = None) -> str:
 
 
 
 
 
 
23
  """
24
  Create JWT token
25
-
26
  Args:
27
  username: Username
28
  role: User role, default is "user", guest is "guest"
29
  custom_expire_hours: Custom expiration time (hours), if None use default value
30
  metadata: Additional metadata
31
-
32
  Returns:
33
  str: Encoded JWT token
34
  """
@@ -40,29 +48,26 @@ class AuthHandler:
40
  expire_hours = self.expire_hours
41
  else:
42
  expire_hours = custom_expire_hours
43
-
44
  expire = datetime.utcnow() + timedelta(hours=expire_hours)
45
-
46
  # Create payload
47
  payload = TokenPayload(
48
- sub=username,
49
- exp=expire,
50
- role=role,
51
- metadata=metadata or {}
52
  )
53
-
54
  return jwt.encode(payload.dict(), self.secret, algorithm=self.algorithm)
55
 
56
  def validate_token(self, token: str) -> dict:
57
  """
58
  Validate JWT token
59
-
60
  Args:
61
  token: JWT token
62
-
63
  Returns:
64
  dict: Dictionary containing user information
65
-
66
  Raises:
67
  HTTPException: If token is invalid or expired
68
  """
@@ -75,13 +80,13 @@ class AuthHandler:
75
  raise HTTPException(
76
  status_code=status.HTTP_401_UNAUTHORIZED, detail="Token expired"
77
  )
78
-
79
  # Return complete payload instead of just username
80
  return {
81
  "username": payload["sub"],
82
  "role": payload.get("role", "user"),
83
  "metadata": payload.get("metadata", {}),
84
- "exp": expire_time
85
  }
86
  except jwt.PyJWTError:
87
  raise HTTPException(
 
17
  self.secret = os.getenv("TOKEN_SECRET", "4f85ds4f56dsf46")
18
  self.algorithm = "HS256"
19
  self.expire_hours = int(os.getenv("TOKEN_EXPIRE_HOURS", 4))
20
+ self.guest_expire_hours = int(
21
+ os.getenv("GUEST_TOKEN_EXPIRE_HOURS", 2)
22
+ ) # Guest token default expiration time
23
 
24
+ def create_token(
25
+ self,
26
+ username: str,
27
+ role: str = "user",
28
+ custom_expire_hours: int = None,
29
+ metadata: dict = None,
30
+ ) -> str:
31
  """
32
  Create JWT token
33
+
34
  Args:
35
  username: Username
36
  role: User role, default is "user", guest is "guest"
37
  custom_expire_hours: Custom expiration time (hours), if None use default value
38
  metadata: Additional metadata
39
+
40
  Returns:
41
  str: Encoded JWT token
42
  """
 
48
  expire_hours = self.expire_hours
49
  else:
50
  expire_hours = custom_expire_hours
51
+
52
  expire = datetime.utcnow() + timedelta(hours=expire_hours)
53
+
54
  # Create payload
55
  payload = TokenPayload(
56
+ sub=username, exp=expire, role=role, metadata=metadata or {}
 
 
 
57
  )
58
+
59
  return jwt.encode(payload.dict(), self.secret, algorithm=self.algorithm)
60
 
61
  def validate_token(self, token: str) -> dict:
62
  """
63
  Validate JWT token
64
+
65
  Args:
66
  token: JWT token
67
+
68
  Returns:
69
  dict: Dictionary containing user information
70
+
71
  Raises:
72
  HTTPException: If token is invalid or expired
73
  """
 
80
  raise HTTPException(
81
  status_code=status.HTTP_401_UNAUTHORIZED, detail="Token expired"
82
  )
83
+
84
  # Return complete payload instead of just username
85
  return {
86
  "username": payload["sub"],
87
  "role": payload.get("role", "user"),
88
  "metadata": payload.get("metadata", {}),
89
+ "exp": expire_time,
90
  }
91
  except jwt.PyJWTError:
92
  raise HTTPException(
lightrag/api/lightrag_server.py CHANGED
@@ -350,22 +350,17 @@ def create_app(args):
350
  if not (username and password):
351
  # Authentication not configured, return guest token
352
  guest_token = auth_handler.create_token(
353
- username="guest",
354
- role="guest",
355
- metadata={"auth_mode": "disabled"}
356
  )
357
  return {
358
  "auth_configured": False,
359
  "access_token": guest_token,
360
  "token_type": "bearer",
361
  "auth_mode": "disabled",
362
- "message": "Authentication is disabled. Using guest access."
363
  }
364
-
365
- return {
366
- "auth_configured": True,
367
- "auth_mode": "enabled"
368
- }
369
 
370
  @app.post("/login", dependencies=[Depends(optional_api_key)])
371
  async def login(form_data: OAuth2PasswordRequestForm = Depends()):
@@ -375,15 +370,13 @@ def create_app(args):
375
  if not (username and password):
376
  # Authentication not configured, return guest token
377
  guest_token = auth_handler.create_token(
378
- username="guest",
379
- role="guest",
380
- metadata={"auth_mode": "disabled"}
381
  )
382
  return {
383
  "access_token": guest_token,
384
  "token_type": "bearer",
385
  "auth_mode": "disabled",
386
- "message": "Authentication is disabled. Using guest access."
387
  }
388
 
389
  if form_data.username != username or form_data.password != password:
@@ -393,14 +386,12 @@ def create_app(args):
393
 
394
  # Regular user login
395
  user_token = auth_handler.create_token(
396
- username=username,
397
- role="user",
398
- metadata={"auth_mode": "enabled"}
399
  )
400
  return {
401
  "access_token": user_token,
402
  "token_type": "bearer",
403
- "auth_mode": "enabled"
404
  }
405
 
406
  @app.get("/health", dependencies=[Depends(optional_api_key)])
 
350
  if not (username and password):
351
  # Authentication not configured, return guest token
352
  guest_token = auth_handler.create_token(
353
+ username="guest", role="guest", metadata={"auth_mode": "disabled"}
 
 
354
  )
355
  return {
356
  "auth_configured": False,
357
  "access_token": guest_token,
358
  "token_type": "bearer",
359
  "auth_mode": "disabled",
360
+ "message": "Authentication is disabled. Using guest access.",
361
  }
362
+
363
+ return {"auth_configured": True, "auth_mode": "enabled"}
 
 
 
364
 
365
  @app.post("/login", dependencies=[Depends(optional_api_key)])
366
  async def login(form_data: OAuth2PasswordRequestForm = Depends()):
 
370
  if not (username and password):
371
  # Authentication not configured, return guest token
372
  guest_token = auth_handler.create_token(
373
+ username="guest", role="guest", metadata={"auth_mode": "disabled"}
 
 
374
  )
375
  return {
376
  "access_token": guest_token,
377
  "token_type": "bearer",
378
  "auth_mode": "disabled",
379
+ "message": "Authentication is disabled. Using guest access.",
380
  }
381
 
382
  if form_data.username != username or form_data.password != password:
 
386
 
387
  # Regular user login
388
  user_token = auth_handler.create_token(
389
+ username=username, role="user", metadata={"auth_mode": "enabled"}
 
 
390
  )
391
  return {
392
  "access_token": user_token,
393
  "token_type": "bearer",
394
+ "auth_mode": "enabled",
395
  }
396
 
397
  @app.get("/health", dependencies=[Depends(optional_api_key)])
lightrag/api/utils_api.py CHANGED
@@ -46,8 +46,10 @@ def get_auth_dependency():
46
  return
47
 
48
  # Check if authentication is configured
49
- auth_configured = bool(os.getenv("AUTH_USERNAME") and os.getenv("AUTH_PASSWORD"))
50
-
 
 
51
  # If authentication is not configured, accept any token including guest tokens
52
  if not auth_configured:
53
  if token: # If token is provided, still validate it
@@ -62,22 +64,22 @@ def get_auth_dependency():
62
  # Ignore validation errors but log them
63
  print(f"Token validation error (ignored): {str(e)}")
64
  return
65
-
66
  # If authentication is configured, validate the token and reject guest tokens
67
  if not token:
68
  raise HTTPException(
69
  status_code=status.HTTP_401_UNAUTHORIZED, detail="Token required"
70
  )
71
-
72
  token_info = auth_handler.validate_token(token)
73
-
74
  # Reject guest tokens when authentication is configured
75
  if token_info.get("role") == "guest":
76
  raise HTTPException(
77
- status_code=status.HTTP_401_UNAUTHORIZED,
78
- detail="Authentication required. Guest access not allowed when authentication is configured."
79
  )
80
-
81
  # At this point, we have a valid non-guest token
82
  return
83
 
 
46
  return
47
 
48
  # Check if authentication is configured
49
+ auth_configured = bool(
50
+ os.getenv("AUTH_USERNAME") and os.getenv("AUTH_PASSWORD")
51
+ )
52
+
53
  # If authentication is not configured, accept any token including guest tokens
54
  if not auth_configured:
55
  if token: # If token is provided, still validate it
 
64
  # Ignore validation errors but log them
65
  print(f"Token validation error (ignored): {str(e)}")
66
  return
67
+
68
  # If authentication is configured, validate the token and reject guest tokens
69
  if not token:
70
  raise HTTPException(
71
  status_code=status.HTTP_401_UNAUTHORIZED, detail="Token required"
72
  )
73
+
74
  token_info = auth_handler.validate_token(token)
75
+
76
  # Reject guest tokens when authentication is configured
77
  if token_info.get("role") == "guest":
78
  raise HTTPException(
79
+ status_code=status.HTTP_401_UNAUTHORIZED,
80
+ detail="Authentication required. Guest access not allowed when authentication is configured.",
81
  )
82
+
83
  # At this point, we have a valid non-guest token
84
  return
85
 
lightrag_webui/src/AppRouter.tsx CHANGED
@@ -18,7 +18,7 @@ const ProtectedRoute = ({ children }: ProtectedRouteProps) => {
18
 
19
  useEffect(() => {
20
  let isMounted = true; // Flag to prevent state updates after unmount
21
-
22
  // This effect will run when the component mounts
23
  // and will check if authentication is required
24
  const checkAuthStatus = async () => {
@@ -28,12 +28,12 @@ const ProtectedRoute = ({ children }: ProtectedRouteProps) => {
28
  if (isMounted) setIsChecking(false);
29
  return;
30
  }
31
-
32
  const status = await getAuthStatus()
33
-
34
  // Only proceed if component is still mounted
35
  if (!isMounted) return;
36
-
37
  if (!status.auth_configured && status.access_token) {
38
  // If auth is not configured, use the guest token
39
  useAuthStore.getState().login(status.access_token, true)
@@ -53,7 +53,7 @@ const ProtectedRoute = ({ children }: ProtectedRouteProps) => {
53
 
54
  // Execute immediately
55
  checkAuthStatus()
56
-
57
  // Cleanup function to prevent state updates after unmount
58
  return () => {
59
  isMounted = false;
@@ -80,23 +80,23 @@ const AppRouter = () => {
80
  // Check token validity and auth configuration on app initialization
81
  useEffect(() => {
82
  let isMounted = true; // Flag to prevent state updates after unmount
83
-
84
  const checkAuth = async () => {
85
  try {
86
  const token = localStorage.getItem('LIGHTRAG-API-TOKEN')
87
-
88
  // If we have a token, we're already authenticated
89
  if (token && isAuthenticated) {
90
  if (isMounted) setInitializing(false);
91
  return;
92
  }
93
-
94
  // If no token or not authenticated, check if auth is configured
95
  const status = await getAuthStatus()
96
-
97
  // Only proceed if component is still mounted
98
  if (!isMounted) return;
99
-
100
  if (!status.auth_configured && status.access_token) {
101
  // If auth is not configured, use the guest token
102
  useAuthStore.getState().login(status.access_token, true)
@@ -122,7 +122,7 @@ const AppRouter = () => {
122
 
123
  // Execute immediately
124
  checkAuth()
125
-
126
  // Cleanup function to prevent state updates after unmount
127
  return () => {
128
  isMounted = false;
 
18
 
19
  useEffect(() => {
20
  let isMounted = true; // Flag to prevent state updates after unmount
21
+
22
  // This effect will run when the component mounts
23
  // and will check if authentication is required
24
  const checkAuthStatus = async () => {
 
28
  if (isMounted) setIsChecking(false);
29
  return;
30
  }
31
+
32
  const status = await getAuthStatus()
33
+
34
  // Only proceed if component is still mounted
35
  if (!isMounted) return;
36
+
37
  if (!status.auth_configured && status.access_token) {
38
  // If auth is not configured, use the guest token
39
  useAuthStore.getState().login(status.access_token, true)
 
53
 
54
  // Execute immediately
55
  checkAuthStatus()
56
+
57
  // Cleanup function to prevent state updates after unmount
58
  return () => {
59
  isMounted = false;
 
80
  // Check token validity and auth configuration on app initialization
81
  useEffect(() => {
82
  let isMounted = true; // Flag to prevent state updates after unmount
83
+
84
  const checkAuth = async () => {
85
  try {
86
  const token = localStorage.getItem('LIGHTRAG-API-TOKEN')
87
+
88
  // If we have a token, we're already authenticated
89
  if (token && isAuthenticated) {
90
  if (isMounted) setInitializing(false);
91
  return;
92
  }
93
+
94
  // If no token or not authenticated, check if auth is configured
95
  const status = await getAuthStatus()
96
+
97
  // Only proceed if component is still mounted
98
  if (!isMounted) return;
99
+
100
  if (!status.auth_configured && status.access_token) {
101
  // If auth is not configured, use the guest token
102
  useAuthStore.getState().login(status.access_token, true)
 
122
 
123
  // Execute immediately
124
  checkAuth()
125
+
126
  // Cleanup function to prevent state updates after unmount
127
  return () => {
128
  isMounted = false;
lightrag_webui/src/api/lightrag.ts CHANGED
@@ -375,7 +375,7 @@ export const getAuthStatus = async (): Promise<AuthStatusResponse> => {
375
  'Accept': 'application/json' // Explicitly request JSON
376
  }
377
  });
378
-
379
  // Check if response is HTML (which indicates a redirect or wrong endpoint)
380
  const contentType = response.headers['content-type'] || '';
381
  if (contentType.includes('text/html')) {
@@ -385,13 +385,13 @@ export const getAuthStatus = async (): Promise<AuthStatusResponse> => {
385
  auth_mode: 'enabled'
386
  };
387
  }
388
-
389
  // Strict validation of the response data
390
- if (response.data &&
391
  typeof response.data === 'object' &&
392
  'auth_configured' in response.data &&
393
  typeof response.data.auth_configured === 'boolean') {
394
-
395
  // For unconfigured auth, ensure we have an access token
396
  if (!response.data.auth_configured) {
397
  if (response.data.access_token && typeof response.data.access_token === 'string') {
@@ -404,10 +404,10 @@ export const getAuthStatus = async (): Promise<AuthStatusResponse> => {
404
  return response.data;
405
  }
406
  }
407
-
408
  // If response data is invalid but we got a response, log it
409
  console.warn('Received invalid auth status response:', response.data);
410
-
411
  // Default to auth configured if response is invalid
412
  return {
413
  auth_configured: true,
 
375
  'Accept': 'application/json' // Explicitly request JSON
376
  }
377
  });
378
+
379
  // Check if response is HTML (which indicates a redirect or wrong endpoint)
380
  const contentType = response.headers['content-type'] || '';
381
  if (contentType.includes('text/html')) {
 
385
  auth_mode: 'enabled'
386
  };
387
  }
388
+
389
  // Strict validation of the response data
390
+ if (response.data &&
391
  typeof response.data === 'object' &&
392
  'auth_configured' in response.data &&
393
  typeof response.data.auth_configured === 'boolean') {
394
+
395
  // For unconfigured auth, ensure we have an access token
396
  if (!response.data.auth_configured) {
397
  if (response.data.access_token && typeof response.data.access_token === 'string') {
 
404
  return response.data;
405
  }
406
  }
407
+
408
  // If response data is invalid but we got a response, log it
409
  console.warn('Received invalid auth status response:', response.data);
410
+
411
  // Default to auth configured if response is invalid
412
  return {
413
  auth_configured: true,
lightrag_webui/src/features/LoginPage.tsx CHANGED
@@ -23,7 +23,7 @@ const LoginPage = () => {
23
  // Check if authentication is configured
24
  useEffect(() => {
25
  let isMounted = true; // Flag to prevent state updates after unmount
26
-
27
  const checkAuthConfig = async () => {
28
  try {
29
  // If already authenticated, redirect to home
@@ -34,10 +34,10 @@ const LoginPage = () => {
34
 
35
  // Check auth status
36
  const status = await getAuthStatus()
37
-
38
  // Only proceed if component is still mounted
39
  if (!isMounted) return;
40
-
41
  if (!status.auth_configured && status.access_token) {
42
  // If auth is not configured, use the guest token and redirect
43
  login(status.access_token, true)
@@ -59,7 +59,7 @@ const LoginPage = () => {
59
 
60
  // Execute immediately
61
  checkAuthConfig()
62
-
63
  // Cleanup function to prevent state updates after unmount
64
  return () => {
65
  isMounted = false;
@@ -81,18 +81,18 @@ const LoginPage = () => {
81
  try {
82
  setLoading(true)
83
  const response = await loginToServer(username, password)
84
-
85
  // Check authentication mode
86
  const isGuestMode = response.auth_mode === 'disabled'
87
  login(response.access_token, isGuestMode)
88
-
89
  if (isGuestMode) {
90
  // Show authentication disabled notification
91
  toast.info(response.message || t('login.authDisabled', 'Authentication is disabled. Using guest access.'))
92
  } else {
93
  toast.success(t('login.successMessage'))
94
  }
95
-
96
  navigate('/')
97
  } catch (error) {
98
  console.error('Login failed...', error)
 
23
  // Check if authentication is configured
24
  useEffect(() => {
25
  let isMounted = true; // Flag to prevent state updates after unmount
26
+
27
  const checkAuthConfig = async () => {
28
  try {
29
  // If already authenticated, redirect to home
 
34
 
35
  // Check auth status
36
  const status = await getAuthStatus()
37
+
38
  // Only proceed if component is still mounted
39
  if (!isMounted) return;
40
+
41
  if (!status.auth_configured && status.access_token) {
42
  // If auth is not configured, use the guest token and redirect
43
  login(status.access_token, true)
 
59
 
60
  // Execute immediately
61
  checkAuthConfig()
62
+
63
  // Cleanup function to prevent state updates after unmount
64
  return () => {
65
  isMounted = false;
 
81
  try {
82
  setLoading(true)
83
  const response = await loginToServer(username, password)
84
+
85
  // Check authentication mode
86
  const isGuestMode = response.auth_mode === 'disabled'
87
  login(response.access_token, isGuestMode)
88
+
89
  if (isGuestMode) {
90
  // Show authentication disabled notification
91
  toast.info(response.message || t('login.authDisabled', 'Authentication is disabled. Using guest access.'))
92
  } else {
93
  toast.success(t('login.successMessage'))
94
  }
95
+
96
  navigate('/')
97
  } catch (error) {
98
  console.error('Login failed...', error)
lightrag_webui/src/locales/en.json CHANGED
@@ -29,8 +29,8 @@
29
  "successMessage": "Login succeeded",
30
  "errorEmptyFields": "Please enter your username and password",
31
  "errorInvalidCredentials": "Login failed, please check username and password",
32
- "authDisabled": "Authentication is disabled. Using guest access.",
33
- "guestMode": "Guest Mode"
34
  },
35
  "documentPanel": {
36
  "clearDocuments": {
 
29
  "successMessage": "Login succeeded",
30
  "errorEmptyFields": "Please enter your username and password",
31
  "errorInvalidCredentials": "Login failed, please check username and password",
32
+ "authDisabled": "Authentication is disabled. Using login free mode.",
33
+ "guestMode": "Login Free"
34
  },
35
  "documentPanel": {
36
  "clearDocuments": {
lightrag_webui/src/locales/zh.json CHANGED
@@ -29,8 +29,8 @@
29
  "successMessage": "登录成功",
30
  "errorEmptyFields": "请输入您的用户名和密码",
31
  "errorInvalidCredentials": "登录失败,请检查用户名和密码",
32
- "authDisabled": "认证已禁用,使用访客访问模式。",
33
- "guestMode": "访客模式"
34
  },
35
  "documentPanel": {
36
  "clearDocuments": {
 
29
  "successMessage": "登录成功",
30
  "errorEmptyFields": "请输入您的用户名和密码",
31
  "errorInvalidCredentials": "登录失败,请检查用户名和密码",
32
+ "authDisabled": "认证已禁用,使用无需登陆模式。",
33
+ "guestMode": "无需登陆"
34
  },
35
  "documentPanel": {
36
  "clearDocuments": {
lightrag_webui/src/stores/state.ts CHANGED
@@ -73,10 +73,10 @@ const isGuestToken = (token: string): boolean => {
73
  // JWT tokens are in the format: header.payload.signature
74
  const parts = token.split('.');
75
  if (parts.length !== 3) return false;
76
-
77
  // Decode the payload (second part)
78
  const payload = JSON.parse(atob(parts[1]));
79
-
80
  // Check if the token has a role field with value "guest"
81
  return payload.role === 'guest';
82
  } catch (e) {
@@ -91,9 +91,9 @@ const initAuthState = (): { isAuthenticated: boolean; isGuestMode: boolean } =>
91
  if (!token) {
92
  return { isAuthenticated: false, isGuestMode: false };
93
  }
94
-
95
- return {
96
- isAuthenticated: true,
97
  isGuestMode: isGuestToken(token)
98
  };
99
  };
@@ -101,29 +101,29 @@ const initAuthState = (): { isAuthenticated: boolean; isGuestMode: boolean } =>
101
  export const useAuthStore = create<AuthState>(set => {
102
  // Get initial state from localStorage
103
  const initialState = initAuthState();
104
-
105
  return {
106
  isAuthenticated: initialState.isAuthenticated,
107
  showLoginModal: false,
108
  isGuestMode: initialState.isGuestMode,
109
-
110
  login: (token, isGuest = false) => {
111
  localStorage.setItem('LIGHTRAG-API-TOKEN', token);
112
- set({
113
- isAuthenticated: true,
114
  showLoginModal: false,
115
  isGuestMode: isGuest
116
  });
117
  },
118
-
119
  logout: () => {
120
  localStorage.removeItem('LIGHTRAG-API-TOKEN');
121
- set({
122
  isAuthenticated: false,
123
  isGuestMode: false
124
  });
125
  },
126
-
127
  setShowLoginModal: (show) => set({ showLoginModal: show })
128
  };
129
  });
 
73
  // JWT tokens are in the format: header.payload.signature
74
  const parts = token.split('.');
75
  if (parts.length !== 3) return false;
76
+
77
  // Decode the payload (second part)
78
  const payload = JSON.parse(atob(parts[1]));
79
+
80
  // Check if the token has a role field with value "guest"
81
  return payload.role === 'guest';
82
  } catch (e) {
 
91
  if (!token) {
92
  return { isAuthenticated: false, isGuestMode: false };
93
  }
94
+
95
+ return {
96
+ isAuthenticated: true,
97
  isGuestMode: isGuestToken(token)
98
  };
99
  };
 
101
  export const useAuthStore = create<AuthState>(set => {
102
  // Get initial state from localStorage
103
  const initialState = initAuthState();
104
+
105
  return {
106
  isAuthenticated: initialState.isAuthenticated,
107
  showLoginModal: false,
108
  isGuestMode: initialState.isGuestMode,
109
+
110
  login: (token, isGuest = false) => {
111
  localStorage.setItem('LIGHTRAG-API-TOKEN', token);
112
+ set({
113
+ isAuthenticated: true,
114
  showLoginModal: false,
115
  isGuestMode: isGuest
116
  });
117
  },
118
+
119
  logout: () => {
120
  localStorage.removeItem('LIGHTRAG-API-TOKEN');
121
+ set({
122
  isAuthenticated: false,
123
  isGuestMode: false
124
  });
125
  },
126
+
127
  setShowLoginModal: (show) => set({ showLoginModal: show })
128
  };
129
  });