feat(capture_server): auth Bearer + bind localhost + anti-path-traversal
- Token obligatoire (RPA_API_TOKEN) sur /capture et /file-action - Bind 127.0.0.1 par défaut, 0.0.0.0 exige token (fail-closed) - /health reste public pour monitoring - VWB backend injecte le Bearer pour les proxys distants - hmac.compare_digest pour comparaison temps constant Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -136,8 +136,18 @@ def capture_windows():
|
||||
agent_port = int(os.environ.get('RPA_WINDOWS_AGENT_PORT', '5006'))
|
||||
agent_url = f'http://{agent_host}:{agent_port}/capture'
|
||||
|
||||
# Auth : l'agent exige un Bearer token (meme RPA_API_TOKEN que le streaming)
|
||||
api_token = os.environ.get('RPA_API_TOKEN', '')
|
||||
headers = {'Authorization': f'Bearer {api_token}'} if api_token else {}
|
||||
|
||||
try:
|
||||
resp = http_client.get(agent_url, timeout=10)
|
||||
resp = http_client.get(agent_url, headers=headers, timeout=10)
|
||||
if resp.status_code == 401:
|
||||
return jsonify({
|
||||
'error': 'Agent Windows : authentification refusee',
|
||||
'hint': 'Verifiez que RPA_API_TOKEN est defini et identique '
|
||||
'cote backend VWB et cote agent Windows.',
|
||||
}), 401
|
||||
if resp.ok:
|
||||
return jsonify(resp.json())
|
||||
return jsonify({
|
||||
|
||||
@@ -359,7 +359,7 @@ def _execute_db_foreach(
|
||||
|
||||
# 3. Pour chaque ligne, injecter et exécuter
|
||||
iteration_results = []
|
||||
model = executor_kwargs.get("model", "qwen3-vl:8b")
|
||||
model = executor_kwargs.get("model", os.environ.get("RPA_VLM_MODEL", os.environ.get("VLM_MODEL", "gemma4:e4b")))
|
||||
ollama_endpoint = executor_kwargs.get("ollama_endpoint", "http://localhost:11434")
|
||||
timeout = executor_kwargs.get("timeout", 300)
|
||||
|
||||
@@ -514,7 +514,7 @@ def execute_dag(workflow_id: str):
|
||||
|
||||
# Paramètres optionnels
|
||||
timeout = data.get("timeout", 300)
|
||||
model = data.get("model", "qwen3-vl:8b")
|
||||
model = data.get("model", os.environ.get("RPA_VLM_MODEL", os.environ.get("VLM_MODEL", "gemma4:e4b")))
|
||||
ollama_endpoint = data.get("ollama_endpoint", "http://localhost:11434")
|
||||
|
||||
executor_kwargs = {
|
||||
@@ -1000,21 +1000,34 @@ def execute_windows():
|
||||
file_actions = [a for a in data['actions'] if a.get('type', '') in _FILE_ACTION_TYPES]
|
||||
if file_actions:
|
||||
# Exécuter les actions fichiers via l'agent Windows
|
||||
# Auth : Bearer token obligatoire (capture_server.py exige RPA_API_TOKEN)
|
||||
_agent_host = os.environ.get('RPA_WINDOWS_AGENT_HOST', '192.168.1.11')
|
||||
_agent_port = int(os.environ.get('RPA_WINDOWS_AGENT_PORT', '5006'))
|
||||
_agent_url = f'http://{_agent_host}:{_agent_port}/file-action'
|
||||
_api_token = os.environ.get('RPA_API_TOKEN', '')
|
||||
_file_headers = {'Authorization': f'Bearer {_api_token}'} if _api_token else {}
|
||||
|
||||
file_results = []
|
||||
for fa in file_actions:
|
||||
try:
|
||||
fa_resp = req.post(
|
||||
'http://192.168.1.11:5006/file-action',
|
||||
_agent_url,
|
||||
json={
|
||||
'action': fa['type'],
|
||||
'params': fa.get('parameters', {}),
|
||||
},
|
||||
headers=_file_headers,
|
||||
timeout=30,
|
||||
)
|
||||
file_results.append(fa_resp.json())
|
||||
if fa_resp.status_code == 401:
|
||||
file_results.append({
|
||||
'error': "Agent Windows : auth refusee (verifier RPA_API_TOKEN)",
|
||||
})
|
||||
else:
|
||||
file_results.append(fa_resp.json())
|
||||
except req.ConnectionError:
|
||||
file_results.append({
|
||||
'error': "Agent Windows (port 5006) non disponible pour l'action fichier"
|
||||
'error': f"Agent Windows ({_agent_host}:{_agent_port}) non disponible pour l'action fichier"
|
||||
})
|
||||
except Exception as e:
|
||||
file_results.append({'error': str(e)})
|
||||
|
||||
Reference in New Issue
Block a user