Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 6 additions & 12 deletions server/core/hook_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@
from models.area import Area
from services import get_all_services
from core.reaction_executor import reaction_executor
from services.notification_service import send_push_notification


logger = logging.getLogger("AREA-App")
logger = logging.getLogger("AREA-API")

def check_hooks(app=None):
ctx = app.app_context() if app else current_app.app_context()
Expand All @@ -34,22 +32,18 @@ def check_hooks(app=None):
last_run = area.last_run.replace(tzinfo=timezone.utc)
if (now - last_run) < timedelta(seconds=area.frequency):
continue

params = area.params or {}
data = act_srv.check_action(user, area.action, params=params)

if data:
logger.info(f"[check_hooks] AREA {area.id} triggered")
logger.info(params)
area.set_params(params)
area.last_run = now
db.session.commit()

reaction_executor(user, rea_srv, area.reaction, params=params, data=data)
titre = "Workflows from area is running"
description = area.name
send_push_notification(user, description, titre)

except Exception as e:
logger.exception(f"[check_hooks] Error AREA {area.id}: {e}")



logger.exception(f"[check_hooks] Error AREA {area.id}: {e}")
10 changes: 8 additions & 2 deletions server/models/area.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from extensions import db
from sqlalchemy.dialects.postgresql import JSON
from sqlalchemy.ext.mutable import MutableDict
from utils.crypto_manager import crypto

class Area(db.Model):
Expand All @@ -14,7 +15,7 @@ class Area(db.Model):
reaction = db.Column(db.String(80), nullable=False)
frequency = db.Column(db.Integer, default=3600)
last_run = db.Column(db.DateTime, default=None)
params = db.Column(db.JSON, nullable=True)
params = db.Column(MutableDict.as_mutable(db.JSON), nullable=True)
enabled = db.Column(db.Boolean, default=True)
public = db.Column(db.Boolean, default=False)

Expand All @@ -25,12 +26,17 @@ def set_params(self, params: dict):

safe = {}
for k, v in (params or {}).items():
if "password" in k.lower():
if isinstance(v, dict):
safe[k] = {sub_k: crypto.encrypt(sub_v) if "password" in sub_k.lower() else sub_v
for sub_k, sub_v in v.items()}
elif "password" in k.lower():
safe[k] = crypto.encrypt(v)
else:
safe[k] = v

self.params = safe


def get_params(self) -> dict:

safe = {}
Expand Down
1 change: 0 additions & 1 deletion server/oui.txt

This file was deleted.

16 changes: 0 additions & 16 deletions server/requirements.txt

This file was deleted.

4 changes: 3 additions & 1 deletion server/routes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from .service import bp as service_bp
from .spotify import bp as spotify_bp
from .github_service import bp as github_service_bp
from .ip_manager import bp as ip_manager_bp

def register_routes(app):
app.register_blueprint(users_bp)
Expand All @@ -15,4 +16,5 @@ def register_routes(app):
app.register_blueprint(area_bp)
app.register_blueprint(json_bp)
app.register_blueprint(spotify_bp)
app.register_blueprint(github_service_bp)
app.register_blueprint(github_service_bp)
app.register_blueprint(ip_manager_bp)
28 changes: 22 additions & 6 deletions server/routes/github_service.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from flask import Blueprint, jsonify, redirect, request
import requests, urllib.parse, os
from .ip_manager import decode_ip
import json

bp = Blueprint("github_service", __name__, url_prefix="/git")

Expand All @@ -15,11 +17,20 @@ def github_login():
"""
Redirige l'utilisateur vers GitHub pour autorisation OAuth
"""
# with open("oui.txt", "w") as f:
# print(REDIRECT_URI, file=f)

frontend = request.args.get("frontend", "web")
encoded_ip = request.args.get("ip", None)

if not encoded_ip:
return jsonify({"error": "Missing 'ip' parameter"}), 400

ip = decode_ip(encoded_ip)

scope = "repo user"
state = f"frontend:{frontend}"
state = json.dumps({
"frontend": frontend,
"ip": ip
})

params = {
"client_id": CLIENT_ID,
Expand All @@ -39,15 +50,20 @@ def github_callback():
return jsonify({"error": request.args["error"]}), 400

code = request.args.get("code")
state = request.args.get("state", "frontend:web")
state_str = request.args.get("state", '{"frontend":"web"}')

clean = state_str.replace('+', '')
data = json.loads(clean)

frontend = data.get("frontend")
ip = data.get("ip")

if not code:
return jsonify({"error": "Missing authorization code"}), 400

frontend = state.split(":")[1]

if frontend == "mobile":
mobile_redirect_uri = "exp://10.18.208.5:8081"
mobile_redirect_uri = f"exp://{ip}:8083"
return redirect(f"{mobile_redirect_uri}?code={code}")

data = {
Expand Down
67 changes: 67 additions & 0 deletions server/routes/ip_manager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
from flask import request, jsonify, Blueprint
from itsdangerous import URLSafeSerializer, BadSignature
import os
import re
import ipaddress

bp = Blueprint("ip_manager", __name__, url_prefix="/ip")

SECRET_KEY = os.getenv("IP_SECRET_KEY", "default_secret_key")
SALT = os.getenv("IP_SALT", "ip_salt")

serializer = URLSafeSerializer(SECRET_KEY, salt=SALT)

def extract_ip(exp_url: str) -> str | None:
"""
Extrait l'IP d'une URL Expo (exp://IP:PORT)
"""
pattern = r"exp://([\d\.]+):\d+"
match = re.match(pattern, exp_url)
if match:
return match.group(1)
return None

def validate_ip(ip_str):
try:
ipaddress.ip_address(ip_str)
return True
except ValueError:
return False



def decode_ip(ip_encoded):
"""
Attendu JSON: { "encoded": "<string>" }
Réponse JSON: { "ip": "1.2.3.4" } ou erreur 400/401
"""
data = ip_encoded
if not ip_encoded:
return None

try:
ip = serializer.loads(data)
except BadSignature:
return None
except Exception:
return None

if not validate_ip(ip):
return None

return ip

@bp.route("/encode", methods=["POST"])
def encode_ip():
data = request.get_json(force=True, silent=True)
if not data or "ip" not in data:
return jsonify({"error": "Missing 'ip' in request body"}), 400

url = str(data["ip"]).strip()
ip = extract_ip(url)
with open("oui.txt", "w") as f:
print(f"Encoding IP: {ip}", file=f)
if not validate_ip(ip):
return jsonify({"error": "Invalid IP address format"}), 400
token = serializer.dumps(ip)
return jsonify({"encoded": token}), 200
27 changes: 23 additions & 4 deletions server/routes/spotify.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
import urllib.parse
import os
from datetime import datetime
from .ip_manager import decode_ip
import json
import re


bp = Blueprint("spotify_auth", __name__)

Expand All @@ -15,8 +19,19 @@
@bp.route("/spotify/login", methods=["GET"])
def spotify_login():
frontend = request.args.get("frontend", "web")
encoded_ip = request.args.get("ip", None)

if not encoded_ip:
return jsonify({"error": "Missing 'ip' parameter"}), 400

ip = decode_ip(encoded_ip)
if not ip:
return jsonify({"error": "Invalid or tampered 'ip' parameter"}), 400
scope = "user-read-currently-playing user-read-playback-state"
state = f"frontend:{frontend}"
state = json.dumps({
"frontend": frontend,
"ip": ip
})

params = {
"client_id": CLIENT_ID,
Expand All @@ -34,15 +49,19 @@ def spotify_login():
@bp.route("/spotify/callback")
def spotify_callback():
code = request.args.get("code")
state = request.args.get("state", "frontend:web")
state_str = request.args.get("state", '{"frontend":"web"}')

frontend = state.split(":")[1]
clean = state_str.replace('+', '')
data = json.loads(clean)

frontend = data.get("frontend")
ip = data.get("ip")

if not code:
return jsonify({"error": "Missing authorization code"}), 400

if frontend == "mobile":
mobile_redirect_uri = f"exp://10.18.208.5:8081?code={code}"
mobile_redirect_uri = f"exp://{ip}:8083?code={code}"
print(f"Redirecting to mobile app: {mobile_redirect_uri}")
return redirect(mobile_redirect_uri)

Expand Down
Loading