'GET', 'callback' => [__CLASS__, 'get_licenses'], 'permission_callback' => function () { return current_user_can('manage_woocommerce'); }, ]); register_rest_route('woonoow/v1', '/licenses/(?P\d+)', [ 'methods' => 'GET', 'callback' => [__CLASS__, 'get_license'], 'permission_callback' => function () { return current_user_can('manage_woocommerce'); }, ]); register_rest_route('woonoow/v1', '/licenses/(?P\d+)', [ 'methods' => 'DELETE', 'callback' => [__CLASS__, 'revoke_license'], 'permission_callback' => function () { return current_user_can('manage_woocommerce'); }, ]); register_rest_route('woonoow/v1', '/licenses/(?P\d+)/activations', [ 'methods' => 'GET', 'callback' => [__CLASS__, 'get_activations'], 'permission_callback' => function () { return current_user_can('manage_woocommerce'); }, ]); // Customer routes register_rest_route('woonoow/v1', '/account/licenses', [ 'methods' => 'GET', 'callback' => [__CLASS__, 'get_customer_licenses'], 'permission_callback' => function () { return is_user_logged_in(); }, ]); register_rest_route('woonoow/v1', '/account/licenses/(?P\d+)/deactivate', [ 'methods' => 'POST', 'callback' => [__CLASS__, 'customer_deactivate'], 'permission_callback' => function () { return is_user_logged_in(); }, ]); // Public API routes (for software validation) register_rest_route('woonoow/v1', '/licenses/validate', [ 'methods' => 'POST', 'callback' => [__CLASS__, 'validate_license'], 'permission_callback' => '__return_true', ]); register_rest_route('woonoow/v1', '/licenses/activate', [ 'methods' => 'POST', 'callback' => [__CLASS__, 'activate_license'], 'permission_callback' => '__return_true', ]); register_rest_route('woonoow/v1', '/licenses/deactivate', [ 'methods' => 'POST', 'callback' => [__CLASS__, 'deactivate_license'], 'permission_callback' => '__return_true', ]); // OAuth endpoints for license-connect register_rest_route('woonoow/v1', '/licenses/oauth/validate', [ 'methods' => 'GET', 'callback' => [__CLASS__, 'oauth_validate'], 'permission_callback' => function () { return is_user_logged_in(); }, ]); register_rest_route('woonoow/v1', '/licenses/oauth/confirm', [ 'methods' => 'POST', 'callback' => [__CLASS__, 'oauth_confirm'], 'permission_callback' => function () { return is_user_logged_in(); }, ]); } /** * Get all licenses (admin) */ public static function get_licenses(WP_REST_Request $request) { $args = [ 'search' => $request->get_param('search'), 'status' => $request->get_param('status'), 'product_id' => $request->get_param('product_id'), 'user_id' => $request->get_param('user_id'), 'limit' => $request->get_param('per_page') ?: 50, 'offset' => (($request->get_param('page') ?: 1) - 1) * ($request->get_param('per_page') ?: 50), ]; $result = LicenseManager::get_all_licenses($args); // Enrich with product and user info foreach ($result['licenses'] as &$license) { $license = self::enrich_license($license); } return new WP_REST_Response([ 'licenses' => $result['licenses'], 'total' => $result['total'], 'page' => $request->get_param('page') ?: 1, 'per_page' => $args['limit'], ]); } /** * Get single license (admin) */ public static function get_license(WP_REST_Request $request) { $license = LicenseManager::get_license($request->get_param('id')); if (!$license) { return new WP_Error('not_found', __('License not found', 'woonoow'), ['status' => 404]); } $license = self::enrich_license($license); $license['activations'] = LicenseManager::get_activations($license['id']); return new WP_REST_Response($license); } /** * Revoke license (admin) */ public static function revoke_license(WP_REST_Request $request) { $result = LicenseManager::revoke($request->get_param('id')); if (!$result) { return new WP_Error('revoke_failed', __('Failed to revoke license', 'woonoow'), ['status' => 500]); } return new WP_REST_Response(['success' => true]); } /** * Get activations for license (admin) */ public static function get_activations(WP_REST_Request $request) { $activations = LicenseManager::get_activations($request->get_param('id')); return new WP_REST_Response($activations); } /** * Get customer's licenses */ public static function get_customer_licenses(WP_REST_Request $request) { $user_id = get_current_user_id(); $licenses = LicenseManager::get_user_licenses($user_id); // Enrich each license foreach ($licenses as &$license) { $license = self::enrich_license($license); $license['activations'] = LicenseManager::get_activations($license['id']); } return new WP_REST_Response($licenses); } /** * Customer deactivate their own activation */ public static function customer_deactivate(WP_REST_Request $request) { $user_id = get_current_user_id(); $license = LicenseManager::get_license($request->get_param('id')); if (!$license || $license['user_id'] != $user_id) { return new WP_Error('not_found', __('License not found', 'woonoow'), ['status' => 404]); } $data = $request->get_json_params(); $result = LicenseManager::deactivate( $license['license_key'], $data['activation_id'] ?? null, $data['machine_id'] ?? null ); if (is_wp_error($result)) { return $result; } return new WP_REST_Response($result); } /** * Validate license (public API) */ public static function validate_license(WP_REST_Request $request) { $data = $request->get_json_params(); if (empty($data['license_key'])) { return new WP_Error('missing_key', __('License key is required', 'woonoow'), ['status' => 400]); } $result = LicenseManager::validate($data['license_key']); return new WP_REST_Response($result); } /** * Activate license (public API) */ public static function activate_license(WP_REST_Request $request) { $data = $request->get_json_params(); if (empty($data['license_key'])) { return new WP_Error('missing_key', __('License key is required', 'woonoow'), ['status' => 400]); } $activation_data = [ 'domain' => $data['domain'] ?? null, 'ip_address' => $_SERVER['REMOTE_ADDR'] ?? null, 'machine_id' => $data['machine_id'] ?? null, 'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? null, 'return_url' => $data['return_url'] ?? null, 'activation_token' => $data['activation_token'] ?? null, ]; $result = LicenseManager::activate($data['license_key'], $activation_data); if (is_wp_error($result)) { return $result; } return new WP_REST_Response($result); } /** * Deactivate license (public API) */ public static function deactivate_license(WP_REST_Request $request) { $data = $request->get_json_params(); if (empty($data['license_key'])) { return new WP_Error('missing_key', __('License key is required', 'woonoow'), ['status' => 400]); } $result = LicenseManager::deactivate( $data['license_key'], $data['activation_id'] ?? null, $data['machine_id'] ?? null ); if (is_wp_error($result)) { return $result; } return new WP_REST_Response($result); } /** * Enrich license with product and user info */ private static function enrich_license($license) { // Add product info $product = wc_get_product($license['product_id']); $license['product_name'] = $product ? $product->get_name() : __('Unknown Product', 'woonoow'); // Add user info $user = get_userdata($license['user_id']); $license['user_email'] = $user ? $user->user_email : ''; $license['user_name'] = $user ? $user->display_name : __('Unknown User', 'woonoow'); // Add computed fields $license['is_expired'] = $license['expires_at'] && strtotime($license['expires_at']) < time(); $license['activations_remaining'] = $license['activation_limit'] > 0 ? max(0, $license['activation_limit'] - $license['activation_count']) : -1; return $license; } /** * OAuth validate endpoint - validates license key and state for OAuth flow */ public static function oauth_validate(WP_REST_Request $request) { $license_key = sanitize_text_field($request->get_param('license_key')); $state = sanitize_text_field($request->get_param('state')); if (empty($license_key)) { return new WP_Error('missing_license_key', __('License key is required.', 'woonoow'), ['status' => 400]); } // Get license $license = LicenseManager::get_license_by_key($license_key); if (!$license) { return new WP_Error('license_not_found', __('License key not found.', 'woonoow'), ['status' => 404]); } // Verify license belongs to current user $current_user_id = get_current_user_id(); if ($license['user_id'] != $current_user_id) { return new WP_Error('unauthorized', __('This license does not belong to your account.', 'woonoow'), ['status' => 403]); } // Verify state token if provided if (!empty($state)) { $state_data = LicenseManager::verify_oauth_state($state); if (!$state_data) { return new WP_Error('invalid_state', __('Invalid or expired state token.', 'woonoow'), ['status' => 400]); } } // Get product info $product = wc_get_product($license['product_id']); return new WP_REST_Response([ 'license_key' => $license['license_key'], 'product_id' => $license['product_id'], 'product_name' => $product ? $product->get_name() : __('Unknown Product', 'woonoow'), 'status' => $license['status'], 'activation_limit' => $license['activation_limit'], 'activation_count' => $license['activation_count'], 'expires_at' => $license['expires_at'], ]); } /** * OAuth confirm endpoint - confirms license activation and returns token */ public static function oauth_confirm(WP_REST_Request $request) { $data = $request->get_json_params(); $license_key = sanitize_text_field($data['license_key'] ?? ''); $site_url = esc_url_raw($data['site_url'] ?? ''); $state = sanitize_text_field($data['state'] ?? ''); $nonce = sanitize_text_field($data['nonce'] ?? ''); if (empty($license_key) || empty($site_url) || empty($state)) { return new WP_Error('missing_params', __('Missing required parameters.', 'woonoow'), ['status' => 400]); } // Get license $license = LicenseManager::get_license_by_key($license_key); if (!$license) { return new WP_Error('license_not_found', __('License key not found.', 'woonoow'), ['status' => 404]); } // Verify license belongs to current user $current_user_id = get_current_user_id(); if ($license['user_id'] != $current_user_id) { return new WP_Error('unauthorized', __('This license does not belong to your account.', 'woonoow'), ['status' => 403]); } // Verify state token $state_data = LicenseManager::verify_oauth_state($state); if (!$state_data) { return new WP_Error('invalid_state', __('Invalid or expired state token.', 'woonoow'), ['status' => 400]); } // Generate activation token $token_data = LicenseManager::generate_activation_token($license['id'], $site_url); if (is_wp_error($token_data)) { return $token_data; } $activation_token = $token_data['token']; // Build return URL with token $return_url = $state_data['return_url'] ?? $site_url; $redirect_url = add_query_arg([ 'activation_token' => $activation_token, 'license_key' => $license_key, 'nonce' => $nonce, ], $return_url); return new WP_REST_Response([ 'success' => true, 'redirect_url' => $redirect_url, 'activation_token' => $activation_token, ]); } }