matewa_lifecycle_uuid(), 'hash'=>hash('sha256',$proof), 'expires'=>time()+180, ], 180); return $proof; } function matewa_lifecycle_proof_callback(WP_REST_Request $request) { $uuid=sanitize_text_field((string)$request->get_param('install_uuid')); $proof=sanitize_text_field((string)$request->get_param('proof')); $s=get_transient(MATEWA_LIFECYCLE_PROOF_TRANSIENT); $ok=is_array($s)&&($s['expires']??0)>=time() &&hash_equals((string)($s['uuid']??''),$uuid) &&hash_equals((string)($s['hash']??''),hash('sha256',$proof)); if(!$ok) return new WP_REST_Response(['ok'=>false],403); delete_transient(MATEWA_LIFECYCLE_PROOF_TRANSIENT); return new WP_REST_Response(['ok'=>true,'install_uuid'=>$uuid],200); } add_action('rest_api_init', function(){ register_rest_route('247chatmate/v1','/lifecycle-proof',[ 'methods'=>WP_REST_Server::READABLE, 'callback'=>'matewa_lifecycle_proof_callback', 'permission_callback'=>'__return_true', ]); }); function matewa_lifecycle_post_event($action, array $extra = []) { $proof=matewa_lifecycle_make_proof(); $payload=array_merge([ 'action'=>sanitize_key((string)$action), 'site_url'=>esc_url_raw(home_url('/')), 'install_uuid'=>matewa_lifecycle_uuid(), 'plugin_version'=>defined('MATEWA_VERSION')?(string)MATEWA_VERSION:'', 'release_channel'=>matewa_lifecycle_release_channel(), 'proof_url'=>esc_url_raw(rest_url('247chatmate/v1/lifecycle-proof')), 'site_proof'=>$proof, ], $extra); $r=wp_remote_post(MATEWA_LIFECYCLE_ENDPOINT,[ 'timeout'=>12, 'headers'=>['Content-Type'=>'application/json; charset=utf-8'], 'body'=>wp_json_encode($payload,JSON_UNESCAPED_SLASHES), ]); return !is_wp_error($r) && (int)wp_remote_retrieve_response_code($r)>=200 && (int)wp_remote_retrieve_response_code($r)<300; } function matewa_lifecycle_send_activation() { if (get_option('matewa_activation_event_sent','')==='1') return; if (matewa_lifecycle_post_event('activation')) { update_option('matewa_activation_event_sent','1',false); } } add_action('admin_init','matewa_lifecycle_send_activation',20); /* * Observational lifecycle telemetry only. * This never sets, restores, removes or otherwise decides entitlement. */ function matewa_lifecycle_observe_entitlement_transition() { if (!function_exists('matewa_get_entitlement_state')) return; $current=sanitize_key((string)matewa_get_entitlement_state()); if ($current==='master') return; $previous=sanitize_key((string)get_option(MATEWA_LIFECYCLE_LAST_STATE_OPTION,'')); // First observation establishes a baseline only. It must not invent a transition. if ($previous==='') { update_option(MATEWA_LIFECYCLE_LAST_STATE_OPTION,$current,false); return; } if ($previous===$current) return; $action=''; if ($current==='pro' && $previous!=='pro') { // First paid conversion remains "upgrade"; later recovery is "pro_restored". $upgrade_sent=(get_option('matewa_lifecycle_pro_upgrade_sent','')==='1'); $action=$upgrade_sent ? 'pro_restored' : 'upgrade'; } elseif ($previous==='pro' && $current!=='pro') { $action='pro_lost'; } elseif ($current==='trial_expired' && $previous==='trial_active') { $action='trial_expired'; } if ($action==='') { update_option(MATEWA_LIFECYCLE_LAST_STATE_OPTION,$current,false); return; } $sent=matewa_lifecycle_post_event($action,[ 'previous_state'=>$previous, 'current_state'=>$current, 'transitioned_at'=>time(), ]); if ($sent) { if ($action==='upgrade') { update_option('matewa_lifecycle_pro_upgrade_sent','1',false); } update_option(MATEWA_LIFECYCLE_LAST_STATE_OPTION,$current,false); } } add_action('admin_init','matewa_lifecycle_observe_entitlement_transition',40);