from flask import Blueprint, request, jsonify, session from app.services.nextcloud import NextcloudClient from app.services import tech_users from config import Config import base64 bp = Blueprint('auth', __name__, url_prefix='/api/auth') def _encrypt_password(password: str) -> str: """Simple base64 encoding for password storage in session.""" return base64.b64encode(password.encode()).decode() def _decrypt_password(encrypted: str) -> str: """Decode base64 encoded password from session.""" return base64.b64decode(encrypted.encode()).decode() @bp.route('/login', methods=['POST']) def login(): """Authenticate admin user against Nextcloud.""" data = request.get_json() if not data or 'username' not in data or 'password' not in data: return jsonify({'error': 'Username and password required'}), 400 username = data['username'].strip() password = data['password'] if not username or not password: return jsonify({'error': 'Username and password cannot be empty'}), 400 try: nc_client = NextcloudClient(Config.NEXTCLOUD_URL, username, password) if not nc_client.verify_credentials(): return jsonify({'error': 'Invalid username or password'}), 401 is_admin = nc_client.check_admin() if not is_admin: return jsonify({'error': 'Admin credentials required. Tech users must use the Tech login.'}), 403 session['username'] = username session['password'] = _encrypt_password(password) session['is_admin'] = True session['user_type'] = 'admin' return jsonify({ 'success': True, 'username': username, 'is_admin': True, 'user_type': 'admin', }), 200 except Exception as e: return jsonify({'error': f'Authentication failed: {str(e)}'}), 500 @bp.route('/login/tech', methods=['POST']) def login_tech(): """Authenticate tech user with username + PIN.""" data = request.get_json() if not data or 'username' not in data or 'pin' not in data: return jsonify({'error': 'Username and PIN required'}), 400 username = data['username'].strip() pin = data['pin'] if not username or not pin: return jsonify({'error': 'Username and PIN cannot be empty'}), 400 user = tech_users.verify_pin(username, pin) if not user: return jsonify({'error': 'Invalid username or PIN'}), 401 # Store the generated NC password so API calls work transparently session['username'] = username session['password'] = _encrypt_password(user['nc_password']) session['is_admin'] = False session['user_type'] = 'tech' return jsonify({ 'success': True, 'username': username, 'is_admin': False, 'user_type': 'tech', }), 200 @bp.route('/logout', methods=['POST']) def logout(): """Clear user session.""" session.clear() return jsonify({'success': True}), 200 @bp.route('/status', methods=['GET']) def status(): """Check current authentication status.""" if 'username' in session: return jsonify({ 'authenticated': True, 'username': session['username'], 'is_admin': session.get('is_admin', False), 'user_type': session.get('user_type', 'admin'), }), 200 else: return jsonify({ 'authenticated': False }), 200