mirror of
https://github.com/tiennm99/DocsGPT.git
synced 2026-10-18 10:14:24 +00:00
fix: more mini connector hardening
This commit is contained in:
1 parent
08e8de7370
commit
e8305ef137
4 files changed
+134
-23
No files matched your search
@@ -24,6 +24,7 @@ from docsgpt.core.settings import settings
|
||||
from docsgpt.parser.connectors.connector_creator import ConnectorCreator
|
||||
from docsgpt.storage.db.repositories.connector_sessions import (
|
||||
ConnectorSessionsRepository,
|
||||
owns_connector_session,
|
||||
)
|
||||
from docsgpt.storage.db.repositories.sources import SourcesRepository
|
||||
from docsgpt.storage.db.session import db_readonly, db_session
|
||||
@@ -102,8 +103,16 @@ def _render_callback_page(
|
||||
):
|
||||
"""Popup page that reports an OAuth result to the opener on allowed origins only."""
|
||||
status = status if status in ("success", "error", "cancelled") else "error"
|
||||
# Without a token there is no result to report, so post to no one.
|
||||
target_origins = connector_allowed_origins(request.host_url) if session_token else []
|
||||
# The script only carries server-side values: the provider key comes from the
|
||||
# supported-connector list rather than the request, and nothing posts without a token.
|
||||
provider_key = next(
|
||||
(key for key in ConnectorCreator.get_supported_connectors() if key == provider_raw.lower()), None,
|
||||
)
|
||||
payload = (
|
||||
{"type": f"{provider_key}_auth_success", "session_token": session_token, "user_email": user_email}
|
||||
if status == "success" and session_token and provider_key else None
|
||||
)
|
||||
target_origins = connector_allowed_origins(request.host_url) if payload else []
|
||||
provider = html.escape(provider_raw.replace("_", " ").title())
|
||||
connected_as = (
|
||||
f"<p>Connected as: {html.escape(user_email)}</p>" if status == "success" and user_email else ""
|
||||
@@ -126,26 +135,15 @@ def _render_callback_page(
|
||||
</style>
|
||||
<script>
|
||||
window.onload = function() {{
|
||||
const status = {_js_literal(status)};
|
||||
const sessionToken = {_js_literal(session_token)};
|
||||
const userEmail = {_js_literal(user_email)};
|
||||
const providerType = {_js_literal(provider_raw)};
|
||||
const payload = {_js_literal(payload)};
|
||||
const targetOrigins = {_js_literal(target_origins)};
|
||||
|
||||
if (status === "success" && window.opener) {{
|
||||
const payload = {{
|
||||
type: providerType + '_auth_success',
|
||||
session_token: sessionToken,
|
||||
user_email: userEmail
|
||||
}};
|
||||
if (payload && window.opener) {{
|
||||
targetOrigins.forEach(function(origin) {{
|
||||
window.opener.postMessage(payload, origin);
|
||||
}});
|
||||
|
||||
setTimeout(() => window.close(), 3000);
|
||||
}} else if (status === "cancelled" || status === "error") {{
|
||||
setTimeout(() => window.close(), 3000);
|
||||
}}
|
||||
setTimeout(() => window.close(), 3000);
|
||||
}};
|
||||
</script>
|
||||
</head>
|
||||
@@ -357,7 +355,7 @@ class ConnectorFiles(Resource):
|
||||
session = ConnectorSessionsRepository(conn).get_by_session_token(
|
||||
session_token,
|
||||
)
|
||||
if not session or session.get("user_id") != user:
|
||||
if not owns_connector_session(session, user, provider):
|
||||
return make_response(jsonify({"success": False, "error": "Invalid or unauthorized session"}), 401)
|
||||
|
||||
loader = ConnectorCreator.create_connector(provider, session_token)
|
||||
@@ -426,7 +424,7 @@ class ConnectorValidateSession(Resource):
|
||||
session = ConnectorSessionsRepository(conn).get_by_session_token(
|
||||
session_token,
|
||||
)
|
||||
if not session or session.get("user_id") != user or not session.get("token_info"):
|
||||
if not owns_connector_session(session, user, provider) or not session.get("token_info"):
|
||||
return make_response(jsonify({"success": False, "error": "Invalid or expired session"}), 401)
|
||||
|
||||
token_info = session["token_info"]
|
||||
@@ -563,7 +561,7 @@ class ConnectorSync(Resource):
|
||||
|
||||
with db_readonly() as conn:
|
||||
session = ConnectorSessionsRepository(conn).get_by_session_token(session_token)
|
||||
if not session or session.get("user_id") != user_id:
|
||||
if not owns_connector_session(session, user_id, source_type):
|
||||
return make_response(
|
||||
jsonify({"success": False, "error": "Invalid or unauthorized session"}),
|
||||
401,
|
||||
|
||||
@@ -24,7 +24,10 @@ from docsgpt.security.zip_archive import (
|
||||
ZipExtractionError,
|
||||
ZipExtractionLimits,
|
||||
)
|
||||
from docsgpt.storage.db.repositories.connector_sessions import ConnectorSessionsRepository
|
||||
from docsgpt.storage.db.repositories.connector_sessions import (
|
||||
ConnectorSessionsRepository,
|
||||
owns_connector_session,
|
||||
)
|
||||
from docsgpt.storage.db.repositories.idempotency import IdempotencyRepository
|
||||
from docsgpt.storage.db.repositories.sources import SourcesRepository
|
||||
from docsgpt.storage.db.source_config import SourceConfig
|
||||
@@ -499,7 +502,7 @@ class UploadRemote(Resource):
|
||||
)
|
||||
with db_readonly() as conn:
|
||||
connector_session = ConnectorSessionsRepository(conn).get_by_session_token(session_token)
|
||||
if not connector_session or connector_session.get("user_id") != user:
|
||||
if not owns_connector_session(connector_session, user, data["source"]):
|
||||
if scoped_key:
|
||||
_release_claim(scoped_key)
|
||||
return make_response(
|
||||
|
||||
Reference in new issue
Block a user