PluginProbe
AL Pack / 1.0.0
AL Pack v1.0.0
1.3.13 trunk 1.0.0 1.1.1 1.1.2 1.2.0 1.2.1 1.2.2 1.3.0 1.3.1 1.3.11 1.3.12
alpack / includes / api.php

api.php in AL Pack 1.0.0, at includes/api.php

248 lines 8.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * PressLearn API
4 */
5
6 if (!defined('ABSPATH')) {
7 exit;
8 }
9
10 class PressLearn_API {
11
12 public static function init() {
13 add_action('rest_api_init', array(__CLASS__, 'register_endpoints'));
14 add_action('rest_api_init', array(__CLASS__, 'add_cors_support'));
15 add_filter('rest_authentication_errors', array(__CLASS__, 'disable_rest_authentication'), 999);
16 add_filter('rest_nonce_enabled', '__return_false');
17 remove_filter('rest_pre_dispatch', 'rest_cookie_check_errors', 10);
18 }
19
20 public static function disable_rest_authentication($errors) {
21 $current_route = isset($_SERVER['REQUEST_URI']) ? sanitize_text_field(wp_unslash($_SERVER['REQUEST_URI'])) : '';
22
23 if (strpos($current_route, '/wp-json/presslearn/') !== false) {
24 return true;
25 }
26
27 return $errors;
28 }
29
30 public static function add_cors_support() {
31 add_filter('rest_pre_serve_request', function($served, $result) {
32 $origin = get_http_origin();
33 if ($origin) {
34 header('Access-Control-Allow-Origin: ' . esc_url_raw($origin));
35 header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
36 header('Access-Control-Allow-Headers: Content-Type, Authorization');
37 header('Access-Control-Allow-Credentials: true');
38 }
39
40 if (isset($_SERVER['REQUEST_METHOD']) && sanitize_text_field(wp_unslash($_SERVER['REQUEST_METHOD'])) === 'OPTIONS') {
41 status_header(200);
42 return true;
43 }
44
45 return $served;
46 }, 10, 2);
47 }
48
49 public static function register_endpoints() {
50 register_rest_route('presslearn/v1', '/activate', array(
51 'methods' => 'POST',
52 'callback' => array(__CLASS__, 'activate_plugin'),
53 'permission_callback' => array(__CLASS__, 'check_activate_permission'),
54 ));
55
56 register_rest_route('presslearn/v1', '/status', array(
57 'methods' => 'GET',
58 'callback' => array(__CLASS__, 'check_status'),
59 'permission_callback' => array(__CLASS__, 'check_permission'),
60 ));
61
62 register_rest_route('presslearn/v1', '/banner', array(
63 'methods' => 'GET',
64 'callback' => array(__CLASS__, 'get_banner'),
65 'permission_callback' => array(__CLASS__, 'check_permission'),
66 ));
67 }
68
69 public static function check_permission($request) {
70 if (current_user_can('manage_options')) {
71 return true;
72 }
73
74 $site_host = wp_parse_url(site_url(), PHP_URL_HOST);
75 $origin = get_http_origin();
76 $origin_host = $origin ? wp_parse_url($origin, PHP_URL_HOST) : '';
77
78 if ($origin_host && $origin_host === $site_host) {
79 return true;
80 }
81
82 $current_host = isset($_SERVER['HTTP_HOST']) ? sanitize_text_field(wp_unslash($_SERVER['HTTP_HOST'])) : '';
83 if ($current_host === $site_host) {
84 return true;
85 }
86
87 return false;
88 }
89
90 public static function check_admin_permission($request) {
91 return self::check_permission($request);
92 }
93
94 public static function check_activate_permission($request) {
95 $origin = get_http_origin();
96 $allowed_domains = array('qa.ledu.kr', 'api.qa.ledu.kr', 'presslearn.co.kr');
97
98 if (!empty($origin)) {
99 $origin_host = wp_parse_url($origin, PHP_URL_HOST);
100 if ($origin_host && in_array($origin_host, $allowed_domains, true)) {
101 return true;
102 }
103 }
104
105 return false;
106 }
107
108 public static function activate_plugin($request) {
109 $key = $request->get_param('key');
110
111 if (empty($key)) {
112 return new WP_Error(
113 'invalid_key',
114 '유효하지 않은 키�
115 니다.',
116 array('status' => 400)
117 );
118 }
119
120 $is_valid = self::validate_key($key);
121
122 if (!$is_valid) {
123 return new WP_Error(
124 'invalid_key',
125 '키가 유효하지 않습니다.',
126 array('status' => 400)
127 );
128 }
129
130 update_option('presslearn_plugin_key', $key);
131
132 self::perform_activation_tasks($key);
133
134 return array(
135 'success' => true,
136 'message' => 'Successfully activated.',
137 'timestamp' => current_time('timestamp')
138 );
139 }
140
141 public static function check_status($request) {
142 $key = get_option('presslearn_plugin_key', '');
143 $is_active = !empty($key);
144
145 $activated_time = get_option('presslearn_plugin_activated_time', 0);
146
147 return array(
148 'is_active' => $is_active,
149 'activated_time' => $activated_time,
150 'message' => $is_active ? '플러그인이 활성화되었습니다.' : '플러그인이 비활성화 상태�
151 니다.'
152 );
153 }
154
155 private static function validate_key($key) {
156 $start_time = microtime(true);
157
158 $is_empty = empty($key);
159 $is_short = strlen($key ?: '') < 32;
160
161 $server_valid = self::mock_validate_with_presslearn_server($key ?: '');
162
163 $is_valid = !$is_empty && !$is_short && $server_valid;
164
165 $min_execution_time = 0.1;
166 $elapsed = microtime(true) - $start_time;
167 if ($elapsed < $min_execution_time) {
168 usleep(($min_execution_time - $elapsed) * 1000000);
169 }
170
171 return $is_valid;
172 }
173
174 private static function mock_validate_with_presslearn_server($key) {
175 return true;
176 }
177
178
179 private static function perform_activation_tasks($key) {
180 update_option('presslearn_plugin_activated_time', time());
181 self::log_activation_event($key);
182 }
183
184 private static function log_activation_event($key) {
185 $masked_key = substr($key, 0, 4) . '...' . substr($key, -4);
186
187 $remote_addr = isset($_SERVER['REMOTE_ADDR']) ? sanitize_text_field(wp_unslash($_SERVER['REMOTE_ADDR'])) : '';
188 $user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? sanitize_text_field(wp_unslash($_SERVER['HTTP_USER_AGENT'])) : '';
189
190 $log_data = array(
191 'time' => current_time('mysql'),
192 'key' => $masked_key,
193 'ip' => $remote_addr,
194 'user_agent' => $user_agent
195 );
196
197 $activation_logs = get_option('presslearn_activation_logs', array());
198 $activation_logs[] = $log_data;
199
200 if (count($activation_logs) > 10) {
201 $activation_logs = array_slice($activation_logs, -10);
202 }
203
204 update_option('presslearn_activation_logs', $activation_logs);
205 }
206
207 public static function get_banner($request) {
208 $supabase_url = 'https://odkponsvhcfajgoetubm.supabase.co';
209 $supabase_key = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Im9ka3BvbnN2aGNmYWpnb2V0dWJtIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NDU4OTIxMjMsImV4cCI6MjA2MTQ2ODEyM30.yR08gaJeSy4kagAT3PZl1i8uAC6aEEnZSfQ4sSbqOYk';
210
211 $response = wp_remote_get(
212 $supabase_url . '/rest/v1/banner_table?id=eq.1',
213 array(
214 'headers' => array(
215 'apikey' => $supabase_key,
216 'Authorization' => 'Bearer ' . $supabase_key,
217 'Content-Type' => 'application/json'
218 )
219 )
220 );
221
222 if (is_wp_error($response)) {
223 return new WP_Error(
224 'banner_fetch_error',
225 '배너 데이터를 가져오는데 실패했습니다.',
226 array('status' => 500)
227 );
228 }
229
230 $body = wp_remote_retrieve_body($response);
231 $data = json_decode($body, true);
232
233 if (empty($data)) {
234 return new WP_Error(
235 'no_banner',
236 '배너 데이터가 없습니다.',
237 array('status' => 404)
238 );
239 }
240
241 return array(
242 'success' => true,
243 'data' => $data[0]
244 );
245 }
246 }
247
248 PressLearn_API::init();