= self::CONSENT_VERSION; } public static function consent_outdated() { $c = get_option( self::OPT_CONSENT, array() ); return is_array( $c ) && ! empty( $c['at'] ) && (int) ( $c['consent_v'] ?? 1 ) < self::CONSENT_VERSION; } public static function paired() { return 'connected' === (string) get_option( 'aieo_rooster_status', '' ) && '' !== (string) get_option( 'aieo_rooster_api_key', '' ); } public static function state() { if ( ! self::consented() ) { return 'not_consented'; } $v = get_option( self::OPT_VERDICT, array() ); if ( is_array( $v ) && ! empty( $v['error'] ) ) { return 'error'; } if ( is_array( $v ) && ! empty( $v['data'] ) ) { return 'verdict'; } if ( ! self::paired() ) { return 'waiting_account'; } return 'sent'; } public static function verdict() { $v = get_option( self::OPT_VERDICT, array() ); return is_array( $v ) && ! empty( $v['data'] ) && is_array( $v['data'] ) ? $v['data'] : null; } public static function verdict_record() { $v = get_option( self::OPT_VERDICT, array() ); return is_array( $v ) ? $v : array(); } public static function consent_text() { return __( 'We will send the names, versions and on/off state of your plugins, your theme, your WordPress, PHP and WooCommerce versions, and the server your site runs on (its host name, address, operating system, database and cache software) to Rooster Systems. Nothing else: no settings, no customers, no orders. You can withdraw and delete it at any time from this card.', 'ai-eshop-optimizer' ); } private static function cap() { return defined( 'AIEO_CAPABILITY' ) ? AIEO_CAPABILITY : 'manage_options'; } private static function back_url( $args = array() ) { $url = class_exists( 'AIEO_DMM' ) ? AIEO_DMM::instance()->get_subtab_url( 'overlaps' ) : admin_url( 'admin.php?page=ai-eshop-dmm&dmm_tab=overlaps' ); return add_query_arg( $args, $url ) . '#aieo-simplify'; } public static function handle_scan() { if ( ! current_user_can( self::cap() ) ) { wp_die( esc_html__( 'Insufficient permissions.', 'ai-eshop-optimizer' ) ); } $action = isset( $_POST['action'] ) ? sanitize_key( wp_unslash( $_POST['action'] ) ) : self::ACTION_SCAN; check_admin_referer( $action ); if ( ! self::consented() ) { update_option( self::OPT_CONSENT, array( 'at' => time(), 'by' => get_current_user_id(), 'version' => defined( 'AIEO_VERSION' ) ? AIEO_VERSION : '', 'text' => md5( self::consent_text() ), 'consent_v' => self::CONSENT_VERSION, ), false ); } $r = self::send( self::ACTION_RESCAN === $action ? 'manual' : 'manual' ); $msg = $r['sent'] ? 'sent' : ( self::paired() ? 'queued' : 'account' ); wp_safe_redirect( self::back_url( array( 'aieo_simplify' => $msg ) ) ); exit; } public static function send( $reason = 'manual' ) { if ( ! self::consented() || ! class_exists( 'AIEO_Plugin_Inventory' ) || ! class_exists( 'AIEO_Portal_Client' ) ) { return array( 'sent' => false, 'code' => 0 ); } $payload = AIEO_Plugin_Inventory::snapshot( true ); $payload['scan_reason'] = $reason; update_option( self::OPT_PAYLOAD, $payload, false ); update_option( self::OPT_FP, AIEO_Plugin_Inventory::fingerprint(), false ); delete_option( self::OPT_VERDICT ); delete_transient( self::TR_POLL ); AIEO_Portal_Client::drop_queued( 'inventory' ); if ( 'manual' === $reason ) { delete_transient( AIEO_Portal_Client::TR_ENROL_BLOCK ); } $res = AIEO_Portal_Client::submit( 'inventory', $payload ); update_option( self::OPT_SENT, time(), false ); self::absorb( $res ); return array( 'sent' => ! empty( $res['ok'] ), 'code' => (int) $res['code'] ); } private static function absorb( array $res ) { $body = isset( $res['body'] ) && is_array( $res['body'] ) ? $res['body'] : array(); if ( ! empty( $res['ok'] ) && ! empty( $body['verdict'] ) && is_array( $body['verdict'] ) ) { update_option( self::OPT_VERDICT, array( 'at' => time(), 'data' => $body['verdict'] ), false ); return; } if ( isset( $body['code'] ) && 'site_unverified' === $body['code'] ) { $enrol = isset( $body['enrol'] ) && is_array( $body['enrol'] ) ? $body['enrol'] : array(); $detail = trim( (string) ( $enrol['code'] ?? '' ) . ( ! empty( $enrol['detail'] ) ? ' / ' . $enrol['detail'] : '' ) ); update_option( self::OPT_VERDICT, array( 'at' => time(), 'error' => 'site_unverified', 'http' => 0, 'detail' => $detail ), false ); return; } if ( ! empty( $res['terminal'] ) ) { $reason = isset( $body['code'] ) ? (string) $body['code'] : ( isset( $body['message'] ) ? (string) $body['message'] : 'rejected' ); update_option( self::OPT_VERDICT, array( 'at' => time(), 'error' => $reason, 'http' => (int) $res['code'] ), false ); } } public static function poll() { $state = self::state(); if ( 'sent' !== $state ) { return array( 'state' => $state, 'verdict' => self::verdict(), 'error' => (string) ( self::verdict_record()['error'] ?? '' ) ); } if ( get_transient( self::TR_POLL ) ) { return array( 'state' => 'sent', 'verdict' => null, 'error' => '' ); } set_transient( self::TR_POLL, 1, MINUTE_IN_SECONDS ); $url = AIEO_Portal_Client::portal_url() . '/wp-json/om-portal/v1/one/inventory/verdict?fp=' . rawurlencode( AIEO_Portal_Client::fp() ); $r = wp_remote_get( $url, array( 'headers' => array( 'Accept' => 'application/json', 'X-OM-API-Key' => (string) get_option( 'aieo_rooster_api_key', '' ) ), 'timeout' => 20, 'sslverify' => (bool) apply_filters( 'aieo_portal_sslverify', true ), ) ); if ( is_wp_error( $r ) ) { return array( 'state' => 'sent', 'verdict' => null, 'error' => '' ); } $code = (int) wp_remote_retrieve_response_code( $r ); $body = json_decode( (string) wp_remote_retrieve_body( $r ), true ); if ( 200 === $code && is_array( $body ) && ! empty( $body['verdict'] ) && is_array( $body['verdict'] ) ) { update_option( self::OPT_VERDICT, array( 'at' => time(), 'data' => $body['verdict'] ), false ); return array( 'state' => 'verdict', 'verdict' => $body['verdict'], 'error' => '' ); } if ( in_array( $code, array( 400, 409, 422 ), true ) && is_array( $body ) ) { $reason = isset( $body['code'] ) ? (string) $body['code'] : 'rejected'; update_option( self::OPT_VERDICT, array( 'at' => time(), 'error' => $reason, 'http' => $code ), false ); return array( 'state' => 'error', 'verdict' => null, 'error' => $reason ); } return array( 'state' => 'sent', 'verdict' => null, 'error' => '' ); } public static function ajax_poll() { if ( ! current_user_can( self::cap() ) ) { wp_send_json_error( array( 'message' => 'forbidden' ), 403 ); } check_ajax_referer( self::AJAX_POLL, 'nonce' ); wp_send_json_success( self::poll() ); } public static function handle_withdraw() { if ( ! current_user_can( self::cap() ) ) { wp_die( esc_html__( 'Insufficient permissions.', 'ai-eshop-optimizer' ) ); } check_admin_referer( self::ACTION_WITHDRAW ); $fp = class_exists( 'AIEO_Portal_Client' ) ? AIEO_Portal_Client::fp() : ''; foreach ( array( self::OPT_CONSENT, self::OPT_PAYLOAD, self::OPT_SENT, self::OPT_VERDICT, self::OPT_FP ) as $o ) { delete_option( $o ); } delete_transient( self::TR_POLL ); wp_clear_scheduled_hook( self::EVENT_RESCAN ); if ( self::paired() && class_exists( 'AIEO_Portal_Client' ) ) { AIEO_Portal_Client::submit( 'inventory_withdraw', array( 'inventory_fp' => $fp ) ); } wp_safe_redirect( self::back_url( array( 'aieo_simplify' => 'withdrawn' ) ) ); exit; } public static function on_change() { if ( ! self::consented() || ! class_exists( 'AIEO_Plugin_Inventory' ) ) { return; } if ( AIEO_Plugin_Inventory::fingerprint() === (string) get_option( self::OPT_FP, '' ) ) { return; } wp_clear_scheduled_hook( self::EVENT_RESCAN ); wp_schedule_single_event( time() + 30 * MINUTE_IN_SECONDS, self::EVENT_RESCAN ); } public static function cron_rescan() { if ( self::consented() && self::paired() ) { self::send( 'scheduled' ); } } public static function on_status( $old, $new ) { if ( 'connected' === (string) $new && self::consented() && class_exists( 'AIEO_Portal_Client' ) ) { AIEO_Portal_Client::flush(); } } public static function card() { $v = self::verdict_record(); return array( 'state' => self::state(), 'paired' => self::paired(), 'consent' => get_option( self::OPT_CONSENT, array() ), 'consent_outdated' => self::consent_outdated(), 'sent_at' => (int) get_option( self::OPT_SENT, 0 ), 'verdict' => self::verdict(), 'verdict_at' => isset( $v['at'] ) ? (int) $v['at'] : 0, 'error' => isset( $v['error'] ) ? (string) $v['error'] : '', 'error_detail' => isset( $v['detail'] ) ? (string) $v['detail'] : '', 'payload' => get_option( self::OPT_PAYLOAD, array() ), 'consent_text' => self::consent_text(), 'scan_url' => admin_url( 'admin-post.php' ), 'poll_nonce' => wp_create_nonce( self::AJAX_POLL ), ); } }