mirror of
https://github.com/wasrusgen/wasrusgen1-crm.git
synced 2026-06-03 19:44:47 +00:00
security(crm): закрыть операторские роуты + авто-токен на все вызовы CRM
- gate /api/project/crm|tasks|approve|delete под is_operator() (только crm.html их зовёт) - crm.html: обёртка window.fetch — X-Operator-Token на все /api/ вызовы оператора
This commit is contained in:
parent
a3fc1b6d9d
commit
7c79cd305a
@ -994,6 +994,8 @@ def build_spec_client():
|
|||||||
|
|
||||||
@app.route("/api/project/crm", methods=["POST"])
|
@app.route("/api/project/crm", methods=["POST"])
|
||||||
def update_crm():
|
def update_crm():
|
||||||
|
if not is_operator():
|
||||||
|
return jsonify({"error": "unauthorized"}), 401
|
||||||
data = request.get_json(force=True) or {}
|
data = request.get_json(force=True) or {}
|
||||||
proj = get_project(data.get("token"))
|
proj = get_project(data.get("token"))
|
||||||
if not proj:
|
if not proj:
|
||||||
@ -1409,6 +1411,8 @@ def payment_webhook():
|
|||||||
|
|
||||||
@app.route("/api/project/delete", methods=["POST"])
|
@app.route("/api/project/delete", methods=["POST"])
|
||||||
def delete_project():
|
def delete_project():
|
||||||
|
if not is_operator():
|
||||||
|
return jsonify({"error": "unauthorized"}), 401
|
||||||
data = request.get_json(force=True) or {}
|
data = request.get_json(force=True) or {}
|
||||||
proj = get_project(data.get("token"))
|
proj = get_project(data.get("token"))
|
||||||
if not proj:
|
if not proj:
|
||||||
@ -1429,6 +1433,8 @@ def delete_project():
|
|||||||
|
|
||||||
@app.route("/api/project/tasks", methods=["POST"])
|
@app.route("/api/project/tasks", methods=["POST"])
|
||||||
def update_tasks():
|
def update_tasks():
|
||||||
|
if not is_operator():
|
||||||
|
return jsonify({"error": "unauthorized"}), 401
|
||||||
data = request.get_json(force=True) or {}
|
data = request.get_json(force=True) or {}
|
||||||
proj = get_project(data.get("token"))
|
proj = get_project(data.get("token"))
|
||||||
if not proj:
|
if not proj:
|
||||||
@ -1439,6 +1445,8 @@ def update_tasks():
|
|||||||
|
|
||||||
@app.route("/api/project/approve", methods=["POST"])
|
@app.route("/api/project/approve", methods=["POST"])
|
||||||
def approve_stage():
|
def approve_stage():
|
||||||
|
if not is_operator():
|
||||||
|
return jsonify({"error": "unauthorized"}), 401
|
||||||
data = request.get_json(force=True) or {}
|
data = request.get_json(force=True) or {}
|
||||||
proj = get_project(data.get("token"))
|
proj = get_project(data.get("token"))
|
||||||
if not proj:
|
if not proj:
|
||||||
|
|||||||
@ -215,6 +215,14 @@ function chips(cur,opts,fn){return opts.map(([k,n])=>`<button class="fchip ${cur
|
|||||||
// ── Операторская авторизация ──
|
// ── Операторская авторизация ──
|
||||||
let OP_TOKEN=localStorage.getItem('op_token')||'';
|
let OP_TOKEN=localStorage.getItem('op_token')||'';
|
||||||
function opHeaders(extra){return Object.assign({'X-Operator-Token':OP_TOKEN||''},extra||{});}
|
function opHeaders(extra){return Object.assign({'X-Operator-Token':OP_TOKEN||''},extra||{});}
|
||||||
|
// Все вызовы оператора несут X-Operator-Token (crm.html — операторский контекст)
|
||||||
|
const _origFetch=window.fetch.bind(window);
|
||||||
|
window.fetch=function(url,opts){
|
||||||
|
opts=opts||{};
|
||||||
|
const u=typeof url==='string'?url:((url&&url.url)||'');
|
||||||
|
if(u.indexOf('/api/')>=0){opts.headers=Object.assign({},opts.headers||{},{'X-Operator-Token':OP_TOKEN||''});}
|
||||||
|
return _origFetch(url,opts);
|
||||||
|
};
|
||||||
async function loadProjects(){
|
async function loadProjects(){
|
||||||
const r=await fetch(`${API}/api/projects`,{headers:opHeaders()});
|
const r=await fetch(`${API}/api/projects`,{headers:opHeaders()});
|
||||||
if(r.status===401){return false;}
|
if(r.status===401){return false;}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user