fixes - allowed hosts, image get folders, extensions after termination

frdel committed Jan 20, 2026 at 16:40 UTC 08693c22f01a6765a225d30ea3894813be65342a
5 files changed +30 -16
agent.py
+6 -4
@@ -487,9 +487,10 @@ class Agent:
487
488 finally:
489 # call message_loop_end extensions
490 - await self.call_extensions(
491 - "message_loop_end", loop_data=self.loop_data
492 - )
490 + if self.context.task and self.context.task.is_alive(): # don't call extensions post mortem
491 + await self.call_extensions(
492 + "message_loop_end", loop_data=self.loop_data
493 + )
494
495 # exceptions outside message loop:
496 except InterventionException as e:
@@ -503,7 +504,8 @@ class Agent:
504 finally:
505 self.context.streaming_agent = None # unset current streamer
506 # call monologue_end extensions
506 - await self.call_extensions("monologue_end", loop_data=self.loop_data) # type: ignore
507 + if self.context.task and self.context.task.is_alive(): # don't call extensions post mortem
508 + await self.call_extensions("monologue_end", loop_data=self.loop_data) # type: ignore
509
510 async def prepare_prompt(self, loop_data: LoopData) -> list[BaseMessage]:
511 self.context.log.set_progress("Building prompt")
python/api/csrf_token.py
+12 -6
@@ -70,7 +70,6 @@ class GetCsrfToken(ApiHandler):
70 )
71 return {"ok": match, "origin": origin, "allowed_origins": allowed_origins}
72
73 -
73 def get_origin_from_request(self, request: Request):
74 # get from origin
75 r = request.headers.get("Origin") or request.environ.get("HTTP_ORIGIN")
@@ -93,7 +92,9 @@ class GetCsrfToken(ApiHandler):
92 # get the allowed origins from the environment
93 allowed_origins = [
94 origin.strip()
96 - for origin in (dotenv.get_dotenv_value(ALLOWED_ORIGINS_KEY) or "").split(",")
95 + for origin in (dotenv.get_dotenv_value(ALLOWED_ORIGINS_KEY) or "").split(
96 + ","
97 + )
98 if origin.strip()
99 ]
100
@@ -114,12 +115,19 @@ class GetCsrfToken(ApiHandler):
115 return allowed_origins
116
117 def get_default_allowed_origins(self) -> list[str]:
117 - return ["*://localhost:*", "*://127.0.0.1:*", "*://0.0.0.0:*"]
118 + return [
119 + "*://localhost",
120 + "*://localhost:*",
121 + "*://127.0.0.1",
122 + "*://127.0.0.1:*",
123 + "*://0.0.0.0",
124 + "*://0.0.0.0:*",
125 + ]
126
127 def initialize_allowed_origins(self, request: Request):
128 """
129 If A0 is hosted on a server, add the first visit origin to ALLOWED_ORIGINS.
122 - This simplifies deployment process as users can access their new instance without
130 + This simplifies deployment process as users can access their new instance without
131 additional setup while keeping it secure.
132 """
133 # dotenv value is already set, do nothing
@@ -144,5 +152,3 @@ class GetCsrfToken(ApiHandler):
152 # if not, add it to the allowed origins
153 allowed_origins.append(req_origin)
154 dotenv.save_dotenv_value(ALLOWED_ORIGINS_KEY, ",".join(allowed_origins))
147 -
148 -
\ No newline at end of file
python/api/image_get.py
+1 -1
@@ -28,7 +28,7 @@ class ImageGet(ApiHandler):
28 in_base = files.is_in_base_dir(files.fix_dev_path(path))
29 else:
30 in_base = files.is_in_base_dir(path)
31 - if not in_base:
31 + if not in_base and not files.is_in_dir(path, "/root"):
32 raise ValueError("Path is outside of allowed directory")
33
34 # get file extension and info
python/helpers/files.py
+7 -5
@@ -505,12 +505,14 @@ def dirname(path: str):
505
506
507 def is_in_base_dir(path: str):
508 - # check if the given path is within the base directory
509 - base_dir = get_base_dir()
510 - # normalize paths to handle relative paths and symlinks
508 + return is_in_dir(path,get_base_dir())
509 +
510 +
511 +def is_in_dir(path:str,dir:str):
512 + # check if the given path is within the directory
513 abs_path = os.path.abspath(path)
512 - # check if the absolute path starts with the base directory
513 - return os.path.commonpath([abs_path, base_dir]) == base_dir
514 + abs_dir = os.path.abspath(dir)
515 + return os.path.commonpath([abs_path, abs_dir]) == abs_dir
516
517
518 def get_subdirectories(
webui/components/sidebar/chats/chats-list.html
+4
@@ -129,6 +129,10 @@
129 margin-right: 8px;
130 }
131
132 + .chat-container:hover{
133 + background-color: var(--color-background-hover);
134 + }
135 +
136 .device-pointer .chat-container .chat-list-action-btn {
137 opacity: 0;
138 visibility: hidden;