Viewing File: /usr/local/cpanel/base/3rdparty/roundcube/plugins/mixpanel_analytics/mixpanel_analytics.php

<?php

/**
* This plugin adds Mixpanel analytics to Roundcube.
**/

class mixpanel_analytics extends rcube_plugin
{
  function enabledGlobally() {
      return file_exists('/var/cpanel/feature_toggles/analytics_ui_includes');
  }

  function versionCheck() {
      $version = file_get_contents('/usr/local/cpanel/version');
      $pieces = explode( ".", $version );

      if ( $pieces[1] >= 117 ) {
          return true;
      }
      return false;
  }

  function getEnvDetails() {
      $cpnatStat = @stat('/var/cpanel/cpnat');
      $isNat = ( $cpnatStat && $cpnatStat[7] );

      $isPrivate = false;
      $mainIp = file_get_contents('/var/cpanel/mainip');
      if ( preg_match( '/^10\./', $mainIp) ) {
          $isPrivate = true;
      }

      $companyId = readlink('/var/cpanel/companyid.fast');

      $envDetails = [
          "mainIp"           => $mainIp,
          "companyId"        => $companyId,
          "isDevEnvironment" => false,
      ];

      if ( file_exists('/var/cpanel/dev_sandbox') || !$isNat && $isPrivate ) {
          $envDetails['isDevEnvironment'] = true;
      }

      return $envDetails;
  }

  function init()
  {
    if ( $this->enabledGlobally() && $this->versionCheck() ) {
        $this->include_script('mixpanel_analytics_include.js');
        $this->add_hook('render_page', array($this, 'addConfigurationJS'));
    }
  }

  // Query Leika via perl to see if consent is required.
  // Returns true if consent is required, false if Leika indicates we can skip consent.
  // On any error we default to requiring consent (true).
  private function leika_consent_required() {
    // If disabled at the server level we return true (caller aborts earlier anyway).
    if ( !$this->enabledGlobally() ) { return true; }

    $perl = '/usr/local/cpanel/3rdparty/bin/perl';
    $cmd  = "$perl -MCpanel::Analytics -e 'print Cpanel::Analytics::is_user_analytics_consent_required_by_leika()' 2>/dev/null";
    $out  = @shell_exec($cmd);
    $out  = trim((string)$out);
    if ( $out === '0' ) { return false; }
    return true;
  }

  function addConfigurationJS() {
    $envDetailsJSON = json_encode($this->getEnvDetails());
    $leikaConsentRequired = $this->leika_consent_required();
    $leikaConsentRequiredJSON = $leikaConsentRequired ? 'true' : 'false';

    # Examples:
    #   Webmail-Roundcube-Mail
    #   Webmail-Roundcube-Mail-Compose
    #   Webmail-Roundcube-Addressbook
    $event = 'Webmail-Roundcube';
    if (array_key_exists('_task', $_GET)) {
        $event .= '-' . ucfirst($_GET['_task']);
        if (array_key_exists('_action', $_GET)) {
            $event .= '-' . ucfirst($_GET['_action']);
        }
    }
    $eventJSON = json_encode($event);

    $debug = false;
    if (array_key_exists('debug', $_GET) && $_GET['debug']) {
        $debug = true;
    }
    $debugJSON = json_encode($debug);

    $js = <<<EOF
        <script type="text/javascript">
        var envDetails = $envDetailsJSON; // envDetails value interpolated from mixpanel_analytics.php

        var event = $eventJSON;
        var debugMode = $debugJSON;
        var leikaConsentRequired = $leikaConsentRequiredJSON;

        var mixpanelToken = envDetails.isDevEnvironment ? 'c7c6f1b1bc8e7b3d8254ebe545861955' : '2cca34424fe0e8ad6897d354b9591c45';

        var loadedFunc = function(mixp) {
            if (!mixp.has_opted_in_tracking() && !leikaConsentRequired) {
                mixp.opt_in_tracking();
            }

            if (!leikaConsentRequired || mixp.has_opted_in_tracking()) {

                // Add these two properties that are among the most important of the super properties added by mixpanel-utils.service.ts,
                // but without having access to the full data normally gathered by Cpanel/Template/Plugin/UIAnalytics.pm
                mixp.register(
                    {
                        "server_main_ip": envDetails.mainIp,
                        "company_id": [envDetails.companyId], // array wrapper matches what's done elsewhere
                    }
                );

                mixp.track(event);
            }
        };

        window.addEventListener('DOMContentLoaded', function() {
            if (window.mixpanel) {
                window.mixpanel.init(
                    mixpanelToken,
                    {
                        debug: debugMode,
                        persistence: "localStorage",
                        opt_out_of_tracking_by_default: leikaConsentRequired,
                        track_pageview: false,
                        property_blacklist: [
                            "\$initial_referrer",
                            "\$referrer",
                            "\$current_url",
                            "url",
                        ],
                        ip: false,
                        autotrack: false,
                        api_host: "https://mixpanel-proxy.cpanel.net",
                        loaded: loadedFunc,
                    }
                );

                // On the Compose page, track when the Send button is clicked.
                // Note that there are 2 different send buttons, depending on
                // the window width.

                var sendButtonClicked = false;
                var sendTimerId = null;

                function trackSendEvent(button) {
                    button.addEventListener("click", function(e) {
                        if (!leikaConsentRequired || window.mixpanel && window.mixpanel.has_opted_in_tracking()) {
                            sendButtonClicked = true;

                            // Clear any existing timer
                            if (sendTimerId) {
                                clearTimeout(sendTimerId);
                            }

                            // Set a 5-second timer to clear the flag if no page unload occurs
                            sendTimerId = setTimeout(function() {
                                sendButtonClicked = false;
                                sendTimerId = null;
                            }, 5000);
                        }
                    });
                }

                // Track successful send when page unloads (indicating redirect/success)
                window.addEventListener('beforeunload', function() {
                    if (sendButtonClicked && window.mixpanel && window.mixpanel.has_opted_in_tracking()) {
                        // Clear the timer since we're tracking the event now
                        if (sendTimerId) {
                            clearTimeout(sendTimerId);
                            sendTimerId = null;
                        }

                        // Use mixpanel's track method with transport: 'sendBeacon' for reliable delivery
                        window.mixpanel.track(event + "-Send", {
                            "send_method": "page_unload"
                        }, {
                            transport: 'sendBeacon'
                        });
                    }
                });

                var composeContent = document.getElementById("compose-content");
                if (composeContent) {
                    var sendButtonWide = composeContent.getElementsByClassName("btn send");
                    if (sendButtonWide[0]) {
                        trackSendEvent(sendButtonWide[0]);
                    }
                }

                var sendButtonNarrow = document.getElementsByClassName("send button");
                if (sendButtonNarrow[0]) {
                    trackSendEvent(sendButtonNarrow[0]);
                }
            }
        });
        </script>
    EOF;

    rcube::get_instance()->output->add_footer($js);
  }

}

?>
Back to Directory File Manager