Skip to content

Commit bb3e222

Browse files
committed
refac: clean null bytes on load
1 parent 4af7cc8 commit bb3e222

File tree

1 file changed

+62
-12
lines changed

1 file changed

+62
-12
lines changed

backend/open_webui/models/chats.py

Lines changed: 62 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -127,30 +127,67 @@ class ChatTitleIdResponse(BaseModel):
127127

128128

129129
class ChatTable:
130+
def _clean_null_bytes(self, obj):
131+
"""
132+
Recursively remove actual null bytes (\x00) and unicode escape \\u0000
133+
from strings inside dict/list structures.
134+
Safe for JSON objects.
135+
"""
136+
if isinstance(obj, str):
137+
return obj.replace("\x00", "").replace("\u0000", "")
138+
elif isinstance(obj, dict):
139+
return {k: self._clean_null_bytes(v) for k, v in obj.items()}
140+
elif isinstance(obj, list):
141+
return [self._clean_null_bytes(v) for v in obj]
142+
return obj
143+
144+
def _sanitize_chat_row(self, chat_item):
145+
"""
146+
Clean a Chat SQLAlchemy model's title + chat JSON,
147+
and return True if anything changed.
148+
"""
149+
changed = False
150+
151+
# Clean title
152+
if chat_item.title:
153+
cleaned = self._clean_null_bytes(chat_item.title)
154+
if cleaned != chat_item.title:
155+
chat_item.title = cleaned
156+
changed = True
157+
158+
# Clean JSON
159+
if chat_item.chat:
160+
cleaned = self._clean_null_bytes(chat_item.chat)
161+
if cleaned != chat_item.chat:
162+
chat_item.chat = cleaned
163+
changed = True
164+
165+
return changed
166+
130167
def insert_new_chat(self, user_id: str, form_data: ChatForm) -> Optional[ChatModel]:
131168
with get_db() as db:
132169
id = str(uuid.uuid4())
133170
chat = ChatModel(
134171
**{
135172
"id": id,
136173
"user_id": user_id,
137-
"title": (
174+
"title": self._clean_null_bytes(
138175
form_data.chat["title"]
139176
if "title" in form_data.chat
140177
else "New Chat"
141178
),
142-
"chat": form_data.chat,
179+
"chat": self._clean_null_bytes(form_data.chat),
143180
"folder_id": form_data.folder_id,
144181
"created_at": int(time.time()),
145182
"updated_at": int(time.time()),
146183
}
147184
)
148185

149-
result = Chat(**chat.model_dump())
150-
db.add(result)
186+
chat_item = Chat(**chat.model_dump())
187+
db.add(chat_item)
151188
db.commit()
152-
db.refresh(result)
153-
return ChatModel.model_validate(result) if result else None
189+
db.refresh(chat_item)
190+
return ChatModel.model_validate(chat_item) if chat_item else None
154191

155192
def _chat_import_form_to_chat_model(
156193
self, user_id: str, form_data: ChatImportForm
@@ -160,10 +197,10 @@ def _chat_import_form_to_chat_model(
160197
**{
161198
"id": id,
162199
"user_id": user_id,
163-
"title": (
200+
"title": self._clean_null_bytes(
164201
form_data.chat["title"] if "title" in form_data.chat else "New Chat"
165202
),
166-
"chat": form_data.chat,
203+
"chat": self._clean_null_bytes(form_data.chat),
167204
"meta": form_data.meta,
168205
"pinned": form_data.pinned,
169206
"folder_id": form_data.folder_id,
@@ -195,9 +232,15 @@ def update_chat_by_id(self, id: str, chat: dict) -> Optional[ChatModel]:
195232
try:
196233
with get_db() as db:
197234
chat_item = db.get(Chat, id)
198-
chat_item.chat = chat
199-
chat_item.title = chat["title"] if "title" in chat else "New Chat"
235+
chat_item.chat = self._clean_null_bytes(chat)
236+
chat_item.title = (
237+
self._clean_null_bytes(chat["title"])
238+
if "title" in chat
239+
else "New Chat"
240+
)
241+
200242
chat_item.updated_at = int(time.time())
243+
201244
db.commit()
202245
db.refresh(chat_item)
203246

@@ -588,8 +631,15 @@ def get_chat_list_by_chat_ids(
588631
def get_chat_by_id(self, id: str) -> Optional[ChatModel]:
589632
try:
590633
with get_db() as db:
591-
chat = db.get(Chat, id)
592-
return ChatModel.model_validate(chat)
634+
chat_item = db.get(Chat, id)
635+
if chat_item is None:
636+
return None
637+
638+
if self._sanitize_chat_row(chat_item):
639+
db.commit()
640+
db.refresh(chat_item)
641+
642+
return ChatModel.model_validate(chat_item)
593643
except Exception:
594644
return None
595645

0 commit comments

Comments
 (0)