/** * Descomplicar® Crescimento Digital * https://descomplicar.pt */ output->set_content_type('application/json'); // Load required libraries $this->load->library('desk_moloni/moloni_api_client'); $this->load->library('desk_moloni/client_sync_service'); // Load required models $this->load->model('desk_moloni/desk_moloni_config_model', 'config_model'); $this->load->model('desk_moloni/desk_moloni_sync_log_model', 'sync_log_model'); $this->load->model('clients_model', 'client_model'); $this->load->model('invoices_model', 'invoice_model'); // Validate client session (required) $this->validate_client_session(); } /** * Validate CSRF token for POST/PUT/DELETE requests */ private function validate_csrf_token() { $method = $this->input->method(); if (in_array($method, ['POST', 'PUT', 'DELETE'])) { $tokenName = $this->security->get_csrf_token_name(); $token = $this->input->get_post($tokenName); $hash = $this->security->get_csrf_hash(); if (!$token || !$hash || !hash_equals($hash, $token)) { $this->set_error_response('CSRF token validation failed', 403); return false; } } return true; } /** * Validate client data access permissions */ private function validate_data_access($requested_client_id = null) { // If specific client ID requested, validate access if ($requested_client_id !== null) { if (!$this->client_id || $this->client_id != $requested_client_id) { $this->set_error_response('Access denied - You can only access your own data', 403); return false; } } return true; } /** * Validate input data with sanitization and rate limiting */ private function validate_and_sanitize($data, $rules = []) { // Rate limiting check (simplified) $this->check_rate_limit(); $sanitized = []; foreach ($data as $key => $value) { if ($value === null) { $sanitized[$key] = null; continue; } // Basic XSS protection $sanitized[$key] = $this->security->xss_clean($value); // Apply validation rules if (isset($rules[$key])) { $rule = $rules[$key]; if (isset($rule['required']) && $rule['required'] && empty($sanitized[$key])) { throw new Exception("Field {$key} is required"); } if (!empty($sanitized[$key]) && isset($rule['type'])) { switch ($rule['type']) { case 'email': if (!filter_var($sanitized[$key], FILTER_VALIDATE_EMAIL)) { throw new Exception("Invalid email format"); } break; case 'int': if (!filter_var($sanitized[$key], FILTER_VALIDATE_INT)) { throw new Exception("Invalid number format"); } $sanitized[$key] = (int) $sanitized[$key]; break; } } if (isset($rule['max_length']) && strlen($sanitized[$key]) > $rule['max_length']) { throw new Exception("Input too long"); } } } return $sanitized; } /** * Simple rate limiting check */ private function check_rate_limit() { $client_ip = $this->input->ip_address(); $cache_key = 'rate_limit_' . md5($client_ip . '_' . ($this->client_id ?? 'anonymous')); // Allow 60 requests per minute per client $current_requests = $this->cache->get($cache_key) ?? 0; if ($current_requests >= 60) { $this->set_error_response('Rate limit exceeded. Please try again later.', 429); exit; } $this->cache->save($cache_key, $current_requests + 1, 60); } // ======================================================================= // Authentication & Session Endpoints // ======================================================================= /** * Client authentication endpoint * POST /client_portal/desk_moloni/client_login */ public function client_login() { if ($this->input->method() !== 'POST') { $this->set_error_response('Method not allowed', 405); return; } // Validate CSRF token if (!$this->validate_csrf_token()) { return; } try { // Validate and sanitize input $input_data = [ 'email' => $this->input->post('email', true), 'password' => $this->input->post('password', true) ]; $validation_rules = [ 'email' => ['required' => true, 'type' => 'email', 'max_length' => 255], 'password' => ['required' => true, 'max_length' => 255] ]; $sanitized = $this->validate_and_sanitize($input_data, $validation_rules); // Log login attempt log_message('info', 'Client login attempt for email: ' . $sanitized['email']); // Authentication logic would go here $this->set_success_response([ 'message' => 'Client login endpoint - implementation in progress', 'authenticated' => false ]); } catch (Exception $e) { // Log failed login attempt with IP $error_context = [ 'method' => __METHOD__, 'ip_address' => $this->input->ip_address(), 'user_agent' => $this->input->user_agent(), 'error' => $e->getMessage() ]; log_message('error', 'Client login error: ' . json_encode($error_context)); $this->set_error_response('Authentication failed', 401); } } /** * Client logout endpoint * POST /client_portal/desk_moloni/client_logout */ public function client_logout() { if ($this->input->method() !== 'POST') { $this->set_error_response('Method not allowed', 405); return; } $this->set_success_response(['message' => 'Client logout endpoint - implementation in progress']); } /** * Session validation endpoint * GET /client_portal/desk_moloni/client_session_check */ public function client_session_check() { if ($this->input->method() !== 'GET') { $this->set_error_response('Method not allowed', 405); return; } $this->set_success_response(['message' => 'Session check endpoint - implementation in progress']); } /** * Password reset endpoint * POST /client_portal/desk_moloni/client_password_reset */ public function client_password_reset() { if ($this->input->method() !== 'POST') { $this->set_error_response('Method not allowed', 405); return; } $this->set_success_response(['message' => 'Password reset endpoint - implementation in progress']); } // ======================================================================= // Dashboard & Overview Endpoints // ======================================================================= /** * Client dashboard data * GET /client_portal/desk_moloni/dashboard */ public function dashboard() { if ($this->input->method() !== 'GET') { $this->set_error_response('Method not allowed', 405); return; } $this->set_success_response(['message' => 'Dashboard endpoint - implementation in progress']); } /** * Current sync status for client * GET /client_portal/desk_moloni/sync_status */ public function sync_status() { if ($this->input->method() !== 'GET') { $this->set_error_response('Method not allowed', 405); return; } $this->set_success_response(['message' => 'Sync status endpoint - implementation in progress']); } /** * Recent sync activity log * GET /client_portal/desk_moloni/recent_activity */ public function recent_activity() { if ($this->input->method() !== 'GET') { $this->set_error_response('Method not allowed', 405); return; } $this->set_success_response(['message' => 'Recent activity endpoint - implementation in progress']); } /** * Summary of sync errors * GET /client_portal/desk_moloni/error_summary */ public function error_summary() { if ($this->input->method() !== 'GET') { $this->set_error_response('Method not allowed', 405); return; } $this->set_success_response(['message' => 'Error summary endpoint - implementation in progress']); } // ======================================================================= // Invoice Management Endpoints // ======================================================================= /** * Get client invoices list * GET /client_portal/desk_moloni/get_invoices */ public function get_invoices() { if ($this->input->method() !== 'GET') { $this->set_error_response('Method not allowed', 405); return; } $this->set_success_response(['message' => 'Get invoices endpoint - implementation in progress']); } /** * Get specific invoice details * GET /client_portal/desk_moloni/get_invoice_details */ public function get_invoice_details() { if ($this->input->method() !== 'GET') { $this->set_error_response('Method not allowed', 405); return; } $this->set_success_response(['message' => 'Invoice details endpoint - implementation in progress']); } /** * Download invoice PDF * GET /client_portal/desk_moloni/download_invoice */ public function download_invoice() { if ($this->input->method() !== 'GET') { $this->set_error_response('Method not allowed', 405); return; } $this->set_success_response(['message' => 'Download invoice endpoint - implementation in progress']); } /** * Manual invoice sync trigger * POST /client_portal/desk_moloni/sync_invoice */ public function sync_invoice() { if ($this->input->method() !== 'POST') { $this->set_error_response('Method not allowed', 405); return; } $this->set_success_response(['message' => 'Sync invoice endpoint - implementation in progress']); } // ======================================================================= // Client Data Management Endpoints // ======================================================================= /** * Get client profile data * GET /client_portal/desk_moloni/get_client_data */ public function get_client_data() { if ($this->input->method() !== 'GET') { $this->set_error_response('Method not allowed', 405); return; } $this->set_success_response(['message' => 'Get client data endpoint - implementation in progress']); } /** * Update client information * PUT /client_portal/desk_moloni/update_client_data */ public function update_client_data() { if ($this->input->method() !== 'PUT') { $this->set_error_response('Method not allowed', 405); return; } $this->set_success_response(['message' => 'Update client data endpoint - implementation in progress']); } /** * Get sync preferences * GET /client_portal/desk_moloni/get_sync_preferences */ public function get_sync_preferences() { if ($this->input->method() !== 'GET') { $this->set_error_response('Method not allowed', 405); return; } $this->set_success_response(['message' => 'Get sync preferences endpoint - implementation in progress']); } /** * Update sync preferences * PUT /client_portal/desk_moloni/update_sync_preferences */ public function update_sync_preferences() { if ($this->input->method() !== 'PUT') { $this->set_error_response('Method not allowed', 405); return; } $this->set_success_response(['message' => 'Update sync preferences endpoint - implementation in progress']); } // ======================================================================= // Reports & Analytics Endpoints // ======================================================================= /** * Get synchronization report * GET /client_portal/desk_moloni/get_sync_report */ public function get_sync_report() { if ($this->input->method() !== 'GET') { $this->set_error_response('Method not allowed', 405); return; } $this->set_success_response(['message' => 'Sync report endpoint - implementation in progress']); } /** * Get revenue analytics * GET /client_portal/desk_moloni/get_revenue_report */ public function get_revenue_report() { if ($this->input->method() !== 'GET') { $this->set_error_response('Method not allowed', 405); return; } $this->set_success_response(['message' => 'Revenue report endpoint - implementation in progress']); } /** * Export client data * GET /client_portal/desk_moloni/export_data */ public function export_data() { if ($this->input->method() !== 'GET') { $this->set_error_response('Method not allowed', 405); return; } $this->set_success_response(['message' => 'Export data endpoint - implementation in progress']); } /** * Get invoice statistics * GET /client_portal/desk_moloni/get_invoice_stats */ public function get_invoice_stats() { if ($this->input->method() !== 'GET') { $this->set_error_response('Method not allowed', 405); return; } $this->set_success_response(['message' => 'Invoice stats endpoint - implementation in progress']); } // ======================================================================= // Support & Help Endpoints // ======================================================================= /** * Submit support request * POST /client_portal/desk_moloni/submit_support_ticket */ public function submit_support_ticket() { if ($this->input->method() !== 'POST') { $this->set_error_response('Method not allowed', 405); return; } $this->set_success_response(['message' => 'Submit support ticket endpoint - implementation in progress']); } /** * Get client support tickets * GET /client_portal/desk_moloni/get_support_tickets */ public function get_support_tickets() { if ($this->input->method() !== 'GET') { $this->set_error_response('Method not allowed', 405); return; } $this->set_success_response(['message' => 'Get support tickets endpoint - implementation in progress']); } /** * Get help documentation * GET /client_portal/desk_moloni/get_help_resources */ public function get_help_resources() { if ($this->input->method() !== 'GET') { $this->set_error_response('Method not allowed', 405); return; } $this->set_success_response(['message' => 'Get help resources endpoint - implementation in progress']); } /** * Contact support form * POST /client_portal/desk_moloni/contact_support */ public function contact_support() { if ($this->input->method() !== 'POST') { $this->set_error_response('Method not allowed', 405); return; } $this->set_success_response(['message' => 'Contact support endpoint - implementation in progress']); } // ======================================================================= // Helper Methods // ======================================================================= /** * Validate client session */ private function validate_client_session() { // Require authenticated client session $this->client_id = $this->session->userdata('client_user_id') ?? $this->session->userdata('client_id') ?? null; if (!$this->client_id) { $this->set_error_response('Authentication required', 401); exit; } } /** * Set success response format * * @param array $data Response data */ private function set_success_response($data) { $this->output ->set_status_header(200) ->set_output(json_encode([ 'success' => true, 'data' => $data, 'client_id' => $this->client_id ])); } /** * Set error response format * * @param string $message Error message * @param int $status_code HTTP status code */ private function set_error_response($message, $status_code = 400) { $this->output ->set_status_header($status_code) ->set_output(json_encode([ 'success' => false, 'error' => [ 'message' => $message, 'code' => $status_code, 'timestamp' => date('Y-m-d H:i:s') ] ])); } }