License.php (18151B)
1 <?php 2 namespace ReduxAppsero; 3 4 /** 5 * Appsero License Checker 6 * 7 * This class will check, active and deactive license 8 */ 9 class License { 10 11 /** 12 * AppSero\Client 13 * 14 * @var object 15 */ 16 protected $client; 17 18 /** 19 * Arguments of create menu 20 * 21 * @var array 22 */ 23 protected $menu_args; 24 25 /** 26 * `option_name` of `wp_options` table 27 * 28 * @var string 29 */ 30 protected $option_key; 31 32 /** 33 * Error message of HTTP request 34 * 35 * @var string 36 */ 37 public $error; 38 39 /** 40 * Success message on form submit 41 * 42 * @var string 43 */ 44 public $success; 45 46 /** 47 * Corn schedule hook name 48 * 49 * @var string 50 */ 51 protected $schedule_hook; 52 53 /** 54 * Set value for valid licnese 55 * 56 * @var boolean 57 */ 58 private $is_valid_licnese = null; 59 60 /** 61 * Initialize the class 62 * 63 * @param Appsero\Client 64 */ 65 public function __construct( Client $client ) { 66 $this->client = $client; 67 68 $this->option_key = 'appsero_' . md5( $this->client->slug ) . '_manage_license'; 69 70 $this->schedule_hook = $this->client->slug . '_license_check_event'; 71 72 // Run hook to check license status daily 73 add_action( $this->schedule_hook, array( $this, 'check_license_status' ) ); 74 75 // Active/Deactive corn schedule 76 $this->run_schedule(); 77 } 78 79 /** 80 * Check license 81 * 82 * @return boolean 83 */ 84 public function check( $license_key ) { 85 $route = 'public/license/' . $this->client->hash . '/check'; 86 87 return $this->send_request( $license_key, $route ); 88 } 89 90 /** 91 * Active a license 92 * 93 * @return boolean 94 */ 95 public function activate( $license_key ) { 96 $route = 'public/license/' . $this->client->hash . '/activate'; 97 98 return $this->send_request( $license_key, $route ); 99 } 100 101 /** 102 * Deactivate a license 103 * 104 * @return boolean 105 */ 106 public function deactivate( $license_key ) { 107 $route = 'public/license/' . $this->client->hash . '/deactivate'; 108 109 return $this->send_request( $license_key, $route ); 110 } 111 112 /** 113 * Send common request 114 * 115 * @param $license_key 116 * @param $route 117 * 118 * @return array 119 */ 120 protected function send_request( $license_key, $route ) { 121 $params = array( 122 'license_key' => $license_key, 123 'url' => esc_url( home_url() ), 124 'is_local' => $this->client->is_local_server(), 125 ); 126 127 $response = $this->client->send_request( $params, $route, true ); 128 129 if ( is_wp_error( $response ) ) { 130 return array( 131 'success' => false, 132 'error' => $response->get_error_message(), 133 ); 134 } 135 136 $response = json_decode( wp_remote_retrieve_body( $response ), true ); 137 138 if ( empty( $response ) || isset( $response['exception'] ) ) { 139 return array( 140 'success' => false, 141 'error' => 'Unknown error occurred, Please try again.', 142 ); 143 } 144 145 if ( isset( $response['errors'] ) && isset( $response['errors']['license_key'] ) ) { 146 $response = array( 147 'success' => false, 148 'error' => $response['errors']['license_key'][0], 149 ); 150 } 151 152 return $response; 153 } 154 155 /** 156 * Add settings page for license 157 * 158 * @param array $args 159 * 160 * @return void 161 */ 162 public function add_settings_page( $args = array() ) { 163 $defaults = array( 164 'type' => 'menu', // Can be: menu, options, submenu 165 'page_title' => 'Manage License', 166 'menu_title' => 'Manage License', 167 'capability' => 'manage_options', 168 'menu_slug' => $this->client->slug . '-manage-license', 169 'icon_url' => '', 170 'position' => null, 171 'parent_slug' => '', 172 ); 173 174 $this->menu_args = wp_parse_args( $args, $defaults ); 175 176 add_action( 'admin_menu', array( $this, 'admin_menu' ), 99 ); 177 } 178 179 /** 180 * Admin Menu hook 181 * 182 * @return void 183 */ 184 public function admin_menu() { 185 switch ( $this->menu_args['type'] ) { 186 case 'menu': 187 $this->create_menu_page(); 188 break; 189 190 case 'submenu': 191 $this->create_submenu_page(); 192 break; 193 194 case 'options': 195 $this->create_options_page(); 196 break; 197 } 198 } 199 200 /** 201 * License menu output 202 */ 203 public function menu_output() { 204 205 if ( isset( $_POST['submit'] ) ) { 206 $this->license_form_submit( $_POST ); 207 } 208 209 $license = get_option( $this->option_key, null ); 210 $action = ( $license && isset( $license['status'] ) && 'activate' == $license['status'] ) ? 'deactive' : 'active'; 211 $this->licenses_style(); 212 ?> 213 214 <div class="wrap appsero-license-settings-wrapper"> 215 <h1>License Settings</h1> 216 217 <?php 218 $this->show_license_page_notices(); 219 do_action( 'before_appsero_license_section' ); 220 ?> 221 222 <div class="appsero-license-settings appsero-license-section"> 223 <?php $this->show_license_page_card_header(); ?> 224 225 <div class="appsero-license-details"> 226 <p>Activate <strong><?php echo $this->client->name; ?></strong> by your license key to get professional support and automatic update from your WordPress dashboard.</p> 227 <form method="post" action="<?php $this->formActionUrl(); ?>" novalidate="novalidate" spellcheck="false"> 228 <input type="hidden" name="_action" value="<?php echo $action; ?>"> 229 <input type="hidden" name="_nonce" value="<?php echo wp_create_nonce( $this->client->name ); ?>"> 230 <div class="license-input-fields"> 231 <div class="license-input-key"> 232 <svg enable-background="new 0 0 512 512" version="1.1" viewBox="0 0 512 512" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"> 233 <path d="m463.75 48.251c-64.336-64.336-169.01-64.335-233.35 1e-3 -43.945 43.945-59.209 108.71-40.181 167.46l-185.82 185.82c-2.813 2.813-4.395 6.621-4.395 10.606v84.858c0 8.291 6.709 15 15 15h84.858c3.984 0 7.793-1.582 10.605-4.395l21.211-21.226c3.237-3.237 4.819-7.778 4.292-12.334l-2.637-22.793 31.582-2.974c7.178-0.674 12.847-6.343 13.521-13.521l2.974-31.582 22.793 2.651c4.233 0.571 8.496-0.85 11.704-3.691 3.193-2.856 5.024-6.929 5.024-11.206v-27.929h27.422c3.984 0 7.793-1.582 10.605-4.395l38.467-37.958c58.74 19.043 122.38 4.929 166.33-39.046 64.336-64.335 64.336-169.01 0-233.35zm-42.435 106.07c-17.549 17.549-46.084 17.549-63.633 0s-17.549-46.084 0-63.633 46.084-17.549 63.633 0 17.548 46.084 0 63.633z"/> 234 </svg> 235 <input type="text" value="<?php echo $this->get_input_license_value( $action, $license ); ?>" 236 placeholder="Enter your license key to activate" name="license_key" 237 <?php echo ( 'deactive' == $action ) ? 'readonly="readonly"' : ''; ?> 238 /> 239 </div> 240 <button type="submit" name="submit" class="<?php echo 'deactive' == $action ? 'deactive-button' : ''; ?>"> 241 <?php echo $action == 'active' ? 'Activate License' : 'Deactivate License'; ?> 242 </button> 243 </div> 244 </form> 245 246 <?php 247 if ( 'deactive' == $action && isset( $license['remaining'] ) ) { 248 $this->show_active_license_info( $license ); 249 } 250 ?> 251 </div> 252 </div> <!-- /.appsero-license-settings --> 253 254 <?php do_action( 'after_appsero_license_section' ); ?> 255 </div> 256 <?php 257 } 258 259 /** 260 * License form submit 261 */ 262 public function license_form_submit( $form ) { 263 if ( ! isset( $form['_nonce'], $form['_action'] ) ) { 264 $this->error = 'Please add all information'; 265 return; 266 } 267 268 if ( ! wp_verify_nonce( $form['_nonce'], $this->client->name ) ) { 269 $this->error = "You don't have permission to manage license."; 270 return; 271 } 272 273 switch ( $form['_action'] ) { 274 case 'active': 275 $this->active_client_license( $form ); 276 break; 277 278 case 'deactive': 279 $this->deactive_client_license( $form ); 280 break; 281 } 282 } 283 284 /** 285 * Check license status on schedule 286 */ 287 public function check_license_status() { 288 $license = get_option( $this->option_key, null ); 289 290 if ( isset( $license['key'] ) && ! empty( $license['key'] ) ) { 291 $response = $this->check( $license['key'] ); 292 293 if ( isset( $response['success'] ) && $response['success'] ) { 294 $license['status'] = 'activate'; 295 $license['remaining'] = $response['remaining']; 296 $license['activation_limit'] = $response['activation_limit']; 297 $license['expiry_days'] = $response['expiry_days']; 298 $license['title'] = $response['title']; 299 $license['source_id'] = $response['source_identifier']; 300 $license['recurring'] = $response['recurring']; 301 } else { 302 $license['status'] = 'deactivate'; 303 $license['expiry_days'] = 0; 304 } 305 306 update_option( $this->option_key, $license, false ); 307 } 308 } 309 310 /** 311 * Check this is a valid license 312 */ 313 public function is_valid() { 314 if ( null !== $this->is_valid_licnese ) { 315 return $this->is_valid_licnese; 316 } 317 318 $license = get_option( $this->option_key, null ); 319 if ( ! empty( $license['key'] ) && isset( $license['status'] ) && $license['status'] == 'activate' ) { 320 $this->is_valid_licnese = true; 321 } else { 322 $this->is_valid_licnese = false; 323 } 324 325 return $this->is_valid_licnese; 326 } 327 328 /** 329 * Check this is a valid license 330 */ 331 public function is_valid_by( $option, $value ) { 332 $license = get_option( $this->option_key, null ); 333 334 if ( ! empty( $license['key'] ) && isset( $license['status'] ) && $license['status'] == 'activate' ) { 335 if ( isset( $license[ $option ] ) && $license[ $option ] == $value ) { 336 return true; 337 } 338 } 339 340 return false; 341 } 342 343 /** 344 * Styles for licenses page 345 */ 346 private function licenses_style() { 347 ?> 348 <style type="text/css"> 349 .appsero-license-section { 350 width: 100%; 351 max-width: 1100px; 352 min-height: 1px; 353 box-sizing: border-box; 354 } 355 .appsero-license-settings { 356 background-color: #fff; 357 box-shadow: 0px 3px 10px rgba(16, 16, 16, 0.05); 358 } 359 .appsero-license-settings * { 360 box-sizing: border-box; 361 } 362 .appsero-license-title { 363 background-color: #F8FAFB; 364 border-bottom: 2px solid #EAEAEA; 365 display: flex; 366 align-items: center; 367 padding: 10px 20px; 368 } 369 .appsero-license-title svg { 370 width: 30px; 371 height: 30px; 372 fill: #0082BF; 373 } 374 .appsero-license-title span { 375 font-size: 17px; 376 color: #444444; 377 margin-left: 10px; 378 } 379 .appsero-license-details { 380 padding: 20px; 381 } 382 .appsero-license-details p { 383 font-size: 15px; 384 margin: 0 0 20px 0; 385 } 386 .license-input-key { 387 position: relative; 388 flex: 0 0 72%; 389 max-width: 72%; 390 } 391 .license-input-key input { 392 background-color: #F9F9F9; 393 padding: 10px 15px 10px 48px; 394 border: 1px solid #E8E5E5; 395 border-radius: 3px; 396 height: 45px; 397 font-size: 16px; 398 color: #71777D; 399 width: 100%; 400 box-shadow: 0 0 0 transparent; 401 } 402 .license-input-key input:focus { 403 outline: 0 none; 404 border: 1px solid #E8E5E5; 405 box-shadow: 0 0 0 transparent; 406 } 407 .license-input-key svg { 408 width: 22px; 409 height: 22px; 410 fill: #0082BF; 411 position: absolute; 412 left: 14px; 413 top: 13px; 414 } 415 .license-input-fields { 416 display: flex; 417 justify-content: space-between; 418 margin-bottom: 30px; 419 max-width: 850px; 420 width: 100%; 421 } 422 .license-input-fields button { 423 color: #fff; 424 font-size: 17px; 425 padding: 8px; 426 height: 46px; 427 background-color: #0082BF; 428 border-radius: 3px; 429 cursor: pointer; 430 flex: 0 0 25%; 431 max-width: 25%; 432 border: 1px solid #0082BF; 433 } 434 .license-input-fields button.deactive-button { 435 background-color: #E40055; 436 border-color: #E40055; 437 } 438 .license-input-fields button:focus { 439 outline: 0 none; 440 } 441 .active-license-info { 442 display: flex; 443 } 444 .single-license-info { 445 min-width: 220px; 446 flex: 0 0 30%; 447 } 448 .single-license-info h3 { 449 font-size: 18px; 450 margin: 0 0 12px 0; 451 } 452 .single-license-info p { 453 margin: 0; 454 color: #00C000; 455 } 456 .single-license-info p.occupied { 457 color: #E40055; 458 } 459 </style> 460 <?php 461 } 462 463 /** 464 * Show active license information 465 */ 466 private function show_active_license_info( $license ) { 467 ?> 468 <div class="active-license-info"> 469 <div class="single-license-info"> 470 <h3>Activation Remaining</h3> 471 <?php if ( empty( $license['activation_limit'] ) ) : ?> 472 <p>Unlimited</p> 473 <?php else : ?> 474 <p class="<?php echo $license['remaining'] ? '' : 'occupied'; ?>"> 475 <?php echo $license['remaining']; ?> out of <?php echo $license['activation_limit']; ?> 476 </p> 477 <?php endif; ?> 478 </div> 479 <div class="single-license-info"> 480 <h3>Expires in</h3> 481 <?php 482 if ( $license['recurring'] && false !== $license['expiry_days'] ) { 483 $occupied = $license['expiry_days'] > 10 ? '' : 'occupied'; 484 echo '<p class="' . $occupied . '">' . $license['expiry_days'] . ' days</p>'; 485 } else { 486 echo '<p>Never</p>'; 487 } 488 ?> 489 </div> 490 </div> 491 <?php 492 } 493 494 /** 495 * Show license settings page notices 496 */ 497 private function show_license_page_notices() { 498 if ( ! empty( $this->error ) ) : 499 ?> 500 <div class="notice notice-error is-dismissible appsero-license-section"> 501 <p><?php echo $this->error; ?></p> 502 </div> 503 <?php 504 endif; 505 if ( ! empty( $this->success ) ) : 506 ?> 507 <div class="notice notice-success is-dismissible appsero-license-section"> 508 <p><?php echo $this->success; ?></p> 509 </div> 510 <?php 511 endif; 512 echo '<br />'; 513 } 514 515 /** 516 * Card header 517 */ 518 private function show_license_page_card_header() { 519 ?> 520 <div class="appsero-license-title"> 521 <svg enable-background="new 0 0 299.995 299.995" version="1.1" viewBox="0 0 300 300" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"> 522 <path d="m150 161.48c-8.613 0-15.598 6.982-15.598 15.598 0 5.776 3.149 10.807 7.817 13.505v17.341h15.562v-17.341c4.668-2.697 7.817-7.729 7.817-13.505 0-8.616-6.984-15.598-15.598-15.598z"/> 523 <path d="m150 85.849c-13.111 0-23.775 10.665-23.775 23.775v25.319h47.548v-25.319c-1e-3 -13.108-10.665-23.775-23.773-23.775z"/> 524 <path d="m150 1e-3c-82.839 0-150 67.158-150 150 0 82.837 67.156 150 150 150s150-67.161 150-150c0-82.839-67.161-150-150-150zm46.09 227.12h-92.173c-9.734 0-17.626-7.892-17.626-17.629v-56.919c0-8.491 6.007-15.582 14.003-17.25v-25.697c0-27.409 22.3-49.711 49.711-49.711 27.409 0 49.709 22.3 49.709 49.711v25.697c7.993 1.673 14 8.759 14 17.25v56.919h2e-3c0 9.736-7.892 17.629-17.626 17.629z"/> 525 </svg> 526 <span>Activate License</span> 527 </div> 528 <?php 529 } 530 531 /** 532 * Active client license 533 */ 534 private function active_client_license( $form ) { 535 if ( empty( $form['license_key'] ) ) { 536 $this->error = 'The license key field is required.'; 537 return; 538 } 539 540 $license_key = sanitize_text_field( $form['license_key'] ); 541 $response = $this->activate( $license_key ); 542 543 if ( ! $response['success'] ) { 544 $this->error = $response['error'] ? $response['error'] : 'Unknown error occurred.'; 545 return; 546 } 547 548 $data = array( 549 'key' => $license_key, 550 'status' => 'activate', 551 'remaining' => $response['remaining'], 552 'activation_limit' => $response['activation_limit'], 553 'expiry_days' => $response['expiry_days'], 554 'title' => $response['title'], 555 'source_id' => $response['source_identifier'], 556 'recurring' => $response['recurring'], 557 ); 558 559 update_option( $this->option_key, $data, false ); 560 561 $this->success = 'License activated successfully.'; 562 } 563 564 /** 565 * Deactive client license 566 */ 567 private function deactive_client_license( $form ) { 568 $license = get_option( $this->option_key, null ); 569 570 if ( empty( $license['key'] ) ) { 571 $this->error = 'License key not found.'; 572 return; 573 } 574 575 $response = $this->deactivate( $license['key'] ); 576 577 $data = array( 578 'key' => '', 579 'status' => 'deactivate', 580 ); 581 582 update_option( $this->option_key, $data, false ); 583 584 if ( ! $response['success'] ) { 585 $this->error = $response['error'] ? $response['error'] : 'Unknown error occurred.'; 586 return; 587 } 588 589 $this->success = 'License deactivated successfully.'; 590 } 591 592 /** 593 * Add license menu page 594 */ 595 private function create_menu_page() { 596 call_user_func( 597 'add_' . 'menu' . '_page', 598 $this->menu_args['page_title'], 599 $this->menu_args['menu_title'], 600 $this->menu_args['capability'], 601 $this->menu_args['menu_slug'], 602 array( $this, 'menu_output' ), 603 $this->menu_args['icon_url'], 604 $this->menu_args['position'] 605 ); 606 } 607 608 /** 609 * Add submenu page 610 */ 611 private function create_submenu_page() { 612 call_user_func( 613 'add_' . 'submenu' . '_page', 614 $this->menu_args['parent_slug'], 615 $this->menu_args['page_title'], 616 $this->menu_args['menu_title'], 617 $this->menu_args['capability'], 618 $this->menu_args['menu_slug'], 619 array( $this, 'menu_output' ), 620 $this->menu_args['position'] 621 ); 622 } 623 624 /** 625 * Add submenu page 626 */ 627 private function create_options_page() { 628 call_user_func( 629 'add_' . 'options' . '_page', 630 $this->menu_args['page_title'], 631 $this->menu_args['menu_title'], 632 $this->menu_args['capability'], 633 $this->menu_args['menu_slug'], 634 array( $this, 'menu_output' ), 635 $this->menu_args['position'] 636 ); 637 } 638 639 /** 640 * Schedule daily sicense checker event 641 */ 642 public function schedule_cron_event() { 643 if ( ! wp_next_scheduled( $this->schedule_hook ) ) { 644 wp_schedule_event( time(), 'daily', $this->schedule_hook ); 645 646 wp_schedule_single_event( time() + 20, $this->schedule_hook ); 647 } 648 } 649 650 /** 651 * Clear any scheduled hook 652 */ 653 public function clear_scheduler() { 654 wp_clear_scheduled_hook( $this->schedule_hook ); 655 } 656 657 /** 658 * Enable/Disable schedule 659 */ 660 private function run_schedule() { 661 switch ( $this->client->type ) { 662 case 'plugin': 663 register_activation_hook( $this->client->file, array( $this, 'schedule_cron_event' ) ); 664 register_deactivation_hook( $this->client->file, array( $this, 'clear_scheduler' ) ); 665 break; 666 667 case 'theme': 668 add_action( 'after_switch_theme', array( $this, 'schedule_cron_event' ) ); 669 add_action( 'switch_theme', array( $this, 'clear_scheduler' ) ); 670 break; 671 } 672 } 673 674 /** 675 * Form action URL 676 */ 677 private function formActionUrl() { 678 echo add_query_arg( 679 array( 'page' => $_GET['page'] ), 680 admin_url( basename( $_SERVER['SCRIPT_NAME'] ) ) 681 ); 682 } 683 684 /** 685 * Get input license key 686 * 687 * @param $action 688 * @return $license 689 */ 690 private function get_input_license_value( $action, $license ) { 691 if ( 'active' == $action ) { 692 return isset( $license['key'] ) ? $license['key'] : ''; 693 } 694 695 if ( 'deactive' == $action ) { 696 $key_length = strlen( $license['key'] ); 697 698 return str_pad( 699 substr( $license['key'], 0, $key_length / 2 ), 700 $key_length, 701 '*' 702 ); 703 } 704 705 return ''; 706 } 707 708 }