Working auth system
This commit is contained in:
parent
b1c2264cc6
commit
2c91d6f100
|
|
@ -0,0 +1,45 @@
|
|||
{
|
||||
"ipmi_host": "192.168.5.191",
|
||||
"ipmi_username": "root",
|
||||
"ipmi_password": "calvin",
|
||||
"ipmi_port": 623,
|
||||
"ssh_enabled": false,
|
||||
"ssh_host": null,
|
||||
"ssh_username": null,
|
||||
"ssh_password": null,
|
||||
"ssh_use_key": false,
|
||||
"ssh_key_file": null,
|
||||
"ssh_port": 22,
|
||||
"enabled": true,
|
||||
"interval": 10,
|
||||
"min_speed": 10,
|
||||
"max_speed": 100,
|
||||
"fan_curve": [
|
||||
{
|
||||
"temp": 30,
|
||||
"speed": 15
|
||||
},
|
||||
{
|
||||
"temp": 40,
|
||||
"speed": 25
|
||||
},
|
||||
{
|
||||
"temp": 50,
|
||||
"speed": 40
|
||||
},
|
||||
{
|
||||
"temp": 60,
|
||||
"speed": 60
|
||||
},
|
||||
{
|
||||
"temp": 70,
|
||||
"speed": 80
|
||||
},
|
||||
{
|
||||
"temp": 80,
|
||||
"speed": 100
|
||||
}
|
||||
],
|
||||
"panic_temp": 85,
|
||||
"panic_speed": 100
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
{"users": {"admin": "ecd71870d1963316a97e3ac3408c9835ad8cf0f3c1bc703527c30265534f75ae"}}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Reset password for fan controller"""
|
||||
import json
|
||||
import hashlib
|
||||
import sys
|
||||
|
||||
USERS_FILE = "/home/devmatrix/projects/fan-controller-v2/data/users.json"
|
||||
|
||||
def hash_password(password):
|
||||
return hashlib.sha256(password.encode()).hexdigest()
|
||||
|
||||
if len(sys.argv) != 3:
|
||||
print("Usage: reset_password.py <username> <new_password>")
|
||||
sys.exit(1)
|
||||
|
||||
username = sys.argv[1]
|
||||
password = sys.argv[2]
|
||||
|
||||
try:
|
||||
with open(USERS_FILE) as f:
|
||||
data = json.load(f)
|
||||
|
||||
data["users"][username] = hash_password(password)
|
||||
|
||||
with open(USERS_FILE, 'w') as f:
|
||||
json.dump(data, f)
|
||||
|
||||
print(f"Password reset for user: {username}")
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
252
server.log
252
server.log
|
|
@ -1,7 +1,255 @@
|
|||
/home/devmatrix/projects/fan-controller-v2/web_server.py:49: PydanticDeprecatedSince20: Pydantic V1 style `@validator` validators are deprecated. You should migrate to Pydantic V2 style `@field_validator` validators, see the migration guide for more details. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.5/migration/
|
||||
@validator('new_password')
|
||||
INFO: Started server process [888347]
|
||||
INFO: Started server process [893663]
|
||||
INFO: Waiting for application startup.
|
||||
INFO: Application startup complete.
|
||||
INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
|
||||
INFO: 127.0.0.1:44244 - "GET /api/status HTTP/1.1" 401 Unauthorized
|
||||
INFO: 192.168.5.30:56770 - "GET /api/status HTTP/1.1" 401 Unauthorized
|
||||
INFO: 192.168.5.30:56770 - "GET /login HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:49736 - "POST /api/auth/login HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:34494 - "GET /api/status HTTP/1.1" 401 Unauthorized
|
||||
/home/devmatrix/projects/fan-controller-v2/web_server.py:141: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC).
|
||||
expiry = datetime.utcnow() + timedelta(days=7)
|
||||
INFO: 192.168.5.30:49736 - "POST /api/auth/login HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:49736 - "GET / HTTP/1.1" 200 OK
|
||||
/home/devmatrix/projects/fan-controller-v2/web_server.py:149: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC).
|
||||
if datetime.utcnow() > expiry:
|
||||
2026-02-20 15:37:16,554 - fan_controller - INFO - Loaded config from /home/devmatrix/projects/fan-controller-v2/data/config.json
|
||||
INFO: 192.168.5.30:49736 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:49736 - "GET /favicon.ico HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:49736 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:34498 - "POST /api/auth/login HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:34506 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:49736 - "GET /api/status HTTP/1.1" 200 OK
|
||||
2026-02-20 15:37:24,066 - fan_controller - INFO - Saved config to /home/devmatrix/projects/fan-controller-v2/data/config.json
|
||||
2026-02-20 15:37:24,068 - fan_controller - ERROR - IPMI command error: [Errno 2] No such file or directory: 'ipmitool'
|
||||
2026-02-20 15:37:24,069 - fan_controller - ERROR - Failed to connect to IPMI at 192.168.5.191
|
||||
INFO: 192.168.5.30:49736 - "POST /api/config/ipmi HTTP/1.1" 200 OK
|
||||
/home/devmatrix/projects/fan-controller-v2/web_server.py:149: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC).
|
||||
if datetime.utcnow() > expiry:
|
||||
INFO: 192.168.5.30:49736 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:49736 - "GET /favicon.ico HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:49736 - "GET /api/status HTTP/1.1" 200 OK
|
||||
2026-02-20 15:37:27,369 - fan_controller - INFO - Saved config to /home/devmatrix/projects/fan-controller-v2/data/config.json
|
||||
2026-02-20 15:37:27,370 - fan_controller - ERROR - IPMI command error: [Errno 2] No such file or directory: 'ipmitool'
|
||||
2026-02-20 15:37:27,371 - fan_controller - ERROR - Failed to connect to IPMI at 192.168.5.191
|
||||
2026-02-20 15:37:27,371 - fan_controller - ERROR - Cannot start service - IPMI connection failed
|
||||
INFO: 192.168.5.30:49736 - "POST /api/control/auto HTTP/1.1" 200 OK
|
||||
/home/devmatrix/projects/fan-controller-v2/web_server.py:149: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC).
|
||||
if datetime.utcnow() > expiry:
|
||||
INFO: 192.168.5.30:49736 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:49736 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:37104 - "GET / HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:37118 - "GET /login HTTP/1.1" 200 OK
|
||||
/home/devmatrix/projects/fan-controller-v2/web_server.py:141: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC).
|
||||
expiry = datetime.utcnow() + timedelta(days=7)
|
||||
INFO: 127.0.0.1:37130 - "POST /api/auth/login HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:49736 - "GET /api/status HTTP/1.1" 200 OK
|
||||
2026-02-20 15:37:33,643 - fan_controller - INFO - Saved config to /home/devmatrix/projects/fan-controller-v2/data/config.json
|
||||
INFO: 192.168.5.30:49736 - "POST /api/control/auto HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:49736 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:49736 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:49736 - "POST /api/control/manual HTTP/1.1" 500 Internal Server Error
|
||||
ERROR: Exception in ASGI application
|
||||
Traceback (most recent call last):
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/uvicorn/protocols/http/httptools_impl.py", line 419, in run_asgi
|
||||
result = await app( # type: ignore[func-returns-value]
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/uvicorn/middleware/proxy_headers.py", line 84, in __call__
|
||||
return await self.app(scope, receive, send)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/fastapi/applications.py", line 1054, in __call__
|
||||
await super().__call__(scope, receive, send)
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/applications.py", line 123, in __call__
|
||||
await self.middleware_stack(scope, receive, send)
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/middleware/errors.py", line 186, in __call__
|
||||
raise exc
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/middleware/errors.py", line 164, in __call__
|
||||
await self.app(scope, receive, _send)
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/middleware/cors.py", line 91, in __call__
|
||||
await self.simple_response(scope, receive, send, request_headers=headers)
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/middleware/cors.py", line 146, in simple_response
|
||||
await self.app(scope, receive, send)
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/middleware/exceptions.py", line 62, in __call__
|
||||
await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 64, in wrapped_app
|
||||
raise exc
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
|
||||
await app(scope, receive, sender)
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 762, in __call__
|
||||
await self.middleware_stack(scope, receive, send)
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 782, in app
|
||||
await route.handle(scope, receive, send)
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 297, in handle
|
||||
await self.app(scope, receive, send)
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 77, in app
|
||||
await wrap_app_handling_exceptions(app, request)(scope, receive, send)
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 64, in wrapped_app
|
||||
raise exc
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
|
||||
await app(scope, receive, sender)
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 72, in app
|
||||
response = await func(request)
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/fastapi/routing.py", line 299, in app
|
||||
raise e
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/fastapi/routing.py", line 294, in app
|
||||
raw_response = await run_endpoint_function(
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/fastapi/routing.py", line 191, in run_endpoint_function
|
||||
return await dependant.call(**values)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/devmatrix/projects/fan-controller-v2/web_server.py", line 1352, in api_control_manual
|
||||
if not service._init_controller():
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
AttributeError: 'FanControlService' object has no attribute '_init_controller'. Did you mean: '_init_ipmi_controller'?
|
||||
2026-02-20 15:37:36,531 - fan_controller - INFO - Saved config to /home/devmatrix/projects/fan-controller-v2/data/config.json
|
||||
2026-02-20 15:37:36,533 - fan_controller - ERROR - IPMI command error: [Errno 2] No such file or directory: 'ipmitool'
|
||||
2026-02-20 15:37:36,533 - fan_controller - ERROR - Failed to connect to IPMI at 192.168.5.191
|
||||
2026-02-20 15:37:36,533 - fan_controller - ERROR - Cannot start service - IPMI connection failed
|
||||
INFO: 192.168.5.30:62376 - "POST /api/control/auto HTTP/1.1" 200 OK
|
||||
/home/devmatrix/projects/fan-controller-v2/web_server.py:149: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC).
|
||||
if datetime.utcnow() > expiry:
|
||||
INFO: 192.168.5.30:62376 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:62376 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:62376 - "POST /api/control/manual HTTP/1.1" 500 Internal Server Error
|
||||
ERROR: Exception in ASGI application
|
||||
Traceback (most recent call last):
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/uvicorn/protocols/http/httptools_impl.py", line 419, in run_asgi
|
||||
result = await app( # type: ignore[func-returns-value]
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/uvicorn/middleware/proxy_headers.py", line 84, in __call__
|
||||
return await self.app(scope, receive, send)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/fastapi/applications.py", line 1054, in __call__
|
||||
await super().__call__(scope, receive, send)
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/applications.py", line 123, in __call__
|
||||
await self.middleware_stack(scope, receive, send)
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/middleware/errors.py", line 186, in __call__
|
||||
raise exc
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/middleware/errors.py", line 164, in __call__
|
||||
await self.app(scope, receive, _send)
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/middleware/cors.py", line 91, in __call__
|
||||
await self.simple_response(scope, receive, send, request_headers=headers)
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/middleware/cors.py", line 146, in simple_response
|
||||
await self.app(scope, receive, send)
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/middleware/exceptions.py", line 62, in __call__
|
||||
await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 64, in wrapped_app
|
||||
raise exc
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
|
||||
await app(scope, receive, sender)
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 762, in __call__
|
||||
await self.middleware_stack(scope, receive, send)
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 782, in app
|
||||
await route.handle(scope, receive, send)
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 297, in handle
|
||||
await self.app(scope, receive, send)
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 77, in app
|
||||
await wrap_app_handling_exceptions(app, request)(scope, receive, send)
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 64, in wrapped_app
|
||||
raise exc
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
|
||||
await app(scope, receive, sender)
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 72, in app
|
||||
response = await func(request)
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/fastapi/routing.py", line 299, in app
|
||||
raise e
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/fastapi/routing.py", line 294, in app
|
||||
raw_response = await run_endpoint_function(
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/fastapi/routing.py", line 191, in run_endpoint_function
|
||||
return await dependant.call(**values)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/devmatrix/projects/fan-controller-v2/web_server.py", line 1352, in api_control_manual
|
||||
if not service._init_controller():
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
AttributeError: 'FanControlService' object has no attribute '_init_controller'. Did you mean: '_init_ipmi_controller'?
|
||||
INFO: 192.168.5.30:55640 - "POST /api/test HTTP/1.1" 500 Internal Server Error
|
||||
ERROR: Exception in ASGI application
|
||||
Traceback (most recent call last):
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/uvicorn/protocols/http/httptools_impl.py", line 419, in run_asgi
|
||||
result = await app( # type: ignore[func-returns-value]
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/uvicorn/middleware/proxy_headers.py", line 84, in __call__
|
||||
return await self.app(scope, receive, send)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/fastapi/applications.py", line 1054, in __call__
|
||||
await super().__call__(scope, receive, send)
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/applications.py", line 123, in __call__
|
||||
await self.middleware_stack(scope, receive, send)
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/middleware/errors.py", line 186, in __call__
|
||||
raise exc
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/middleware/errors.py", line 164, in __call__
|
||||
await self.app(scope, receive, _send)
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/middleware/cors.py", line 91, in __call__
|
||||
await self.simple_response(scope, receive, send, request_headers=headers)
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/middleware/cors.py", line 146, in simple_response
|
||||
await self.app(scope, receive, send)
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/middleware/exceptions.py", line 62, in __call__
|
||||
await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 64, in wrapped_app
|
||||
raise exc
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
|
||||
await app(scope, receive, sender)
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 762, in __call__
|
||||
await self.middleware_stack(scope, receive, send)
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 782, in app
|
||||
await route.handle(scope, receive, send)
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 297, in handle
|
||||
await self.app(scope, receive, send)
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 77, in app
|
||||
await wrap_app_handling_exceptions(app, request)(scope, receive, send)
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 64, in wrapped_app
|
||||
raise exc
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
|
||||
await app(scope, receive, sender)
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 72, in app
|
||||
response = await func(request)
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/fastapi/routing.py", line 299, in app
|
||||
raise e
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/fastapi/routing.py", line 294, in app
|
||||
raw_response = await run_endpoint_function(
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/devmatrix/.local/lib/python3.12/site-packages/fastapi/routing.py", line 191, in run_endpoint_function
|
||||
return await dependant.call(**values)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/devmatrix/projects/fan-controller-v2/web_server.py", line 1323, in api_test
|
||||
if not service._init_controller():
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
AttributeError: 'FanControlService' object has no attribute '_init_controller'. Did you mean: '_init_ipmi_controller'?
|
||||
INFO: 192.168.5.30:61984 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:61984 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:61984 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:61984 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:61984 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:61984 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:61984 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:61984 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:61984 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:61984 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:61984 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:61984 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:61984 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:63389 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:63389 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:63389 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:63389 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:63389 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:63389 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:63389 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:63389 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:63389 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:63389 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:63389 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:63389 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:63389 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:63389 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:63389 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:63389 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:63389 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:63389 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:63389 - "GET /api/status HTTP/1.1" 200 OK
|
||||
INFO: 192.168.5.30:63389 - "GET /api/status HTTP/1.1" 200 OK
|
||||
|
|
|
|||
|
|
@ -171,6 +171,7 @@ LOGIN_HTML = '''<!DOCTYPE html>
|
|||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="icon" type="image/png" href="/favicon.ico">
|
||||
<title>Login - IPMI Fan Controller</title>
|
||||
<style>
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
|
|
@ -251,26 +252,36 @@ LOGIN_HTML = '''<!DOCTYPE html>
|
|||
const errorEl = document.getElementById('error');
|
||||
errorEl.style.display = 'none';
|
||||
|
||||
const username = document.getElementById('username').value;
|
||||
const password = document.getElementById('password').value;
|
||||
|
||||
console.log('Attempting login for:', username);
|
||||
|
||||
try {
|
||||
const res = await fetch('/api/auth/login', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({
|
||||
username: document.getElementById('username').value,
|
||||
password: document.getElementById('password').value
|
||||
})
|
||||
body: JSON.stringify({username, password})
|
||||
});
|
||||
const data = await res.json();
|
||||
|
||||
if (data.success) {
|
||||
console.log('Response status:', res.status);
|
||||
|
||||
const data = await res.json();
|
||||
console.log('Response data:', data);
|
||||
|
||||
if (data.success && data.token) {
|
||||
console.log('Login successful, storing token');
|
||||
localStorage.setItem('token', data.token);
|
||||
console.log('Token stored, redirecting...');
|
||||
window.location.href = '/';
|
||||
} else {
|
||||
console.log('Login failed:', data.error);
|
||||
errorEl.textContent = data.error || 'Login failed';
|
||||
errorEl.style.display = 'block';
|
||||
}
|
||||
} catch (e) {
|
||||
errorEl.textContent = 'Connection error';
|
||||
console.error('Login error:', e);
|
||||
errorEl.textContent = 'Connection error: ' + e.message;
|
||||
errorEl.style.display = 'block';
|
||||
}
|
||||
});
|
||||
|
|
@ -283,6 +294,7 @@ SETUP_HTML = '''<!DOCTYPE html>
|
|||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="icon" type="image/png" href="/favicon.ico">
|
||||
<title>Setup - IPMI Fan Controller</title>
|
||||
<style>
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
|
|
@ -453,6 +465,7 @@ DASHBOARD_HTML = '''<!DOCTYPE html>
|
|||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="icon" type="image/png" href="/favicon.ico">
|
||||
<title>IPMI Fan Controller v2</title>
|
||||
<style>
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
|
|
@ -862,6 +875,11 @@ DASHBOARD_HTML = '''<!DOCTYPE html>
|
|||
</div>
|
||||
|
||||
<script>
|
||||
// Check auth on page load
|
||||
if (!localStorage.getItem('token')) {
|
||||
window.location.replace('/login');
|
||||
}
|
||||
|
||||
let currentStatus = {};
|
||||
let currentConfig = {};
|
||||
|
||||
|
|
@ -1214,18 +1232,32 @@ app.add_middleware(
|
|||
)
|
||||
|
||||
# Routes
|
||||
@app.get("/favicon.ico")
|
||||
async def favicon():
|
||||
"""Return a simple favicon to prevent 404 errors."""
|
||||
# Return a transparent 1x1 PNG
|
||||
transparent_png = bytes([
|
||||
0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, # PNG signature
|
||||
0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, # IHDR chunk
|
||||
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, # 1x1 pixel
|
||||
0x08, 0x06, 0x00, 0x00, 0x00, 0x1F, 0x15, 0xC4, 0x89,
|
||||
0x00, 0x00, 0x00, 0x0D, 0x49, 0x44, 0x41, 0x54, # IDAT chunk (transparent)
|
||||
0x08, 0xD7, 0x63, 0x60, 0x60, 0x60, 0x00, 0x00, 0x00,
|
||||
0x02, 0x00, 0x01, 0xE2, 0x21, 0xBC, 0x33,
|
||||
0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, # IEND chunk
|
||||
0xAE, 0x42, 0x60, 0x82
|
||||
])
|
||||
from fastapi.responses import Response
|
||||
return Response(content=transparent_png, media_type="image/png")
|
||||
|
||||
@app.get("/")
|
||||
async def root(request: Request):
|
||||
"""Main dashboard or redirect to setup/login."""
|
||||
"""Main dashboard - always returns dashboard HTML, JS handles auth."""
|
||||
# Check if setup is needed
|
||||
if not user_manager.is_setup_complete():
|
||||
return HTMLResponse(content=SETUP_HTML)
|
||||
|
||||
# Check auth
|
||||
token = request.cookies.get("token") or request.headers.get("authorization", "").replace("Bearer ", "")
|
||||
if not token or not user_manager.verify_token(token):
|
||||
return HTMLResponse(content=LOGIN_HTML)
|
||||
|
||||
# Always return dashboard - JavaScript will check token and redirect if needed
|
||||
return HTMLResponse(content=DASHBOARD_HTML)
|
||||
|
||||
@app.get("/login")
|
||||
|
|
|
|||
Loading…
Reference in New Issue