From fe4d0d562e345dda6d5f8d7f2f414afb688a0d7d Mon Sep 17 00:00:00 2001 From: "Namhyeon, Go" Date: Wed, 1 Jan 2025 21:12:42 +0900 Subject: [PATCH] Add the server-side script files --- app/assets/php/class.tfa.php | 61 +++++ app/assets/php/coupang.class.php | 70 +++++ app/assets/php/punycode.class.php | 418 ++++++++++++++++++++++++++++++ lib/coupang.js | 32 +++ 4 files changed, 581 insertions(+) create mode 100644 app/assets/php/class.tfa.php create mode 100644 app/assets/php/coupang.class.php create mode 100644 app/assets/php/punycode.class.php create mode 100644 lib/coupang.js diff --git a/app/assets/php/class.tfa.php b/app/assets/php/class.tfa.php new file mode 100644 index 0000000..fdc9e0e --- /dev/null +++ b/app/assets/php/class.tfa.php @@ -0,0 +1,61 @@ +alphabet, $char); + $j += 5; + + if($j >= 8) { + $j -= 8; + $binary_key .= chr(($n & (0xFF << $j)) >> $j); + } + } + /* End of Base32 decoder */ + + // current unix time 30sec period as binary + $binary_timestamp = pack('N*', 0) . pack('N*', floor(microtime(true)/30)); + // generate keyed hash + $hash = hash_hmac('sha1', $binary_timestamp, $binary_key, true); + + // generate otp from hash + $offset = ord($hash[19]) & 0xf; + $otp = ( + ((ord($hash[$offset+0]) & 0x7f) << 24 ) | + ((ord($hash[$offset+1]) & 0xff) << 16 ) | + ((ord($hash[$offset+2]) & 0xff) << 8 ) | + (ord($hash[$offset+3]) & 0xff) + ) % pow(10, 6); + + return $otp; + } + + function getPubKey() { + $alphabet = str_split($this->alphabet); + $key = ''; + // generate 16 chars public key from Base32 alphabet + for ($i = 0; $i < 16; $i++) $key .= $alphabet[mt_rand(0,31)]; + // split into 4x4 chunks for easy reading + return implode(" ", str_split($key, 4)); + } + +} + +?> diff --git a/app/assets/php/coupang.class.php b/app/assets/php/coupang.class.php new file mode 100644 index 0000000..2d6cfbc --- /dev/null +++ b/app/assets/php/coupang.class.php @@ -0,0 +1,70 @@ + +// https://github.com/gnh1201/welsonjs +// +date_default_timezone_set("GMT+0"); + +class CoupangProductSearch { + private $accessKey = ""; + private $secretKey = ""; + private $baseUrl = "https://api-gateway.coupang.com"; + + private function generateSignature($method, $path, $query = "") { + $datetime = (new \DateTime("now", new \DateTimeZone("GMT")))->format("ymd\THis\Z"); + $message = $datetime . $method . $path . $query; + + $signature = hash_hmac('sha256', $message, $this->secretKey); + return [ + 'authorization' => "CEA algorithm=HmacSHA256, access-key={$this->accessKey}, signed-date={$datetime}, signature={$signature}", + 'datetime' => $datetime + ]; + } + + public function searchProducts($keyword, $limit = 10, $subId = null, $imageSize = null, $srpLinkOnly = false) { + $path = "/v2/providers/affiliate_open_api/apis/openapi/products/search"; + $queryParams = http_build_query([ + 'keyword' => $keyword, + 'limit' => $limit, + 'subId' => $subId, + 'imageSize' => $imageSize, + 'srpLinkOnly' => $srpLinkOnly + ]); + $fullPath = $path . '?' . $queryParams; + $url = $this->baseUrl . $fullPath; + + $signatureData = $this->generateSignature("GET", $path, $queryParams); + $authorization = $signatureData['authorization']; + $datetime = $signatureData['datetime']; + + $headers = [ + "Content-Type: application/json;charset=UTF-8", + "Authorization: $authorization" + ]; + + $curl = curl_init(); + curl_setopt($curl, CURLOPT_URL, $url); + curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "GET"); + curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + + $response = curl_exec($curl); + $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE); + + curl_close($curl); + + if ($httpCode === 200) { + return json_decode($response, true); + } else { + try { + return json_decode($response, true); + } catch (Exception $e) { + return [ + "status" => $httpCode, + "message" => $e->getMessage() + ]; + } + } + } +} diff --git a/app/assets/php/punycode.class.php b/app/assets/php/punycode.class.php new file mode 100644 index 0000000..45c490f --- /dev/null +++ b/app/assets/php/punycode.class.php @@ -0,0 +1,418 @@ +0) + { + $output.= self::DELIMITER; + } + + $h = $b; + while($h < $input_length) + { + $m = PHP_INT_MAX; + + // Find the minimum code point >= n + for($i=0; $i<$input_length; $i++) + { + $chr = self::mb_substr($input,$i,1); + $c = self::uniord( $chr ); + if ($c >= $n && $c < $m) + { + $m = $c; + } + } + + + if (($m - $n) > (PHP_INT_MAX - $delta) / ($h+1)) + { + throw new Exception("PunycodeException.OVERFLOW"); + } + $delta = $delta + ($m - $n) * ($h + 1); + $n = $m; + + + for($j=0; $j<$input_length; $j++) + { + $chr = self::mb_substr($input,$j,1); + $c = self::uniord( $chr ); + if ($c < $n) + { + $delta++; + if (0==$delta) + { + throw new Exception("PunycodeException.OVERFLOW"); + } + } + + if ($c == $n) + { + $q = $delta; + for($k= self::BASE;; $k+=self::BASE) + { + $t=0; + if ($k <= $bias) + { + $t= self::TMIN; + } else if ($k >= $bias + self::TMAX) { + $t= self::TMAX; + } else { + $t = $k - $bias; + } + if ($q < $t) + { + break; + } + $output.= chr( self::digit2codepoint($t + ($q - $t) % (self::BASE - $t)) ); + $q = floor( ($q-$t) / (self::BASE - $t) );//integer division + } + $output.= chr( self::digit2codepoint($q) ); + $bias = self::adapt($delta, $h+1, $h==$b); + $delta=0; + $h++; + } + } + $delta++; + $n++; + } + } + catch (Exception $e) + { + error_log("[PUNYCODE] error ".$e->getMessage()); + return $input; + } + return $output; + } + + protected static function decode($input) + { + try + { + $n = self::INITIAL_N; + $i = 0; + $bias = self::INITIAL_BIAS; + $output = ''; + + $d = self::rstrpos($input, self::DELIMITER); + if ($d>0) { + for($j=0; $j<$d; $j++) { + $chr = self::mb_substr($input,$j,1); + $c = self::uniord( $chr ); + if ($c>=self::INITIAL_N) { + throw new Exception("PunycodeException.BAD_INPUT"); + } + $output.=$chr; + } + $d++; + } else { + $d = 0; + } + + $input_length = self::mb_strlen($input); + while ($d < $input_length) { + $oldi = $i; + $w = 1; + + for($k= self::BASE;; $k += self::BASE) { + if ($d == $input_length) { + throw new Exception("PunycodeException.BAD_INPUT"); + } + $chr = self::mb_substr($input,$d++,1); + $c = self::uniord( $chr ); + $digit = self::codepoint2digit($c); + if ($digit > (PHP_INT_MAX - $i) / $w) { + throw new Exception("PunycodeException.OVERFLOW"); + } + + $i = $i + $digit * $w; + + $t=0; + if ($k <= $bias) { + $t = self::TMIN; + } else if ($k >= $bias + self::TMAX) { + $t = self::TMAX; + } else { + $t = $k - $bias; + } + if ($digit < $t) { + break; + } + $w = $w * (self::BASE - $t); + } + $output_length = self::mb_strlen($output); + + $bias = self::adapt($i - $oldi, $output_length + 1, $oldi == 0); + + if ($i / ($output_length + 1) > PHP_INT_MAX - $n) { + throw new Exception("PunycodeException.OVERFLOW"); + } + $n = floor($n + $i / ($output_length + 1)); + $i = $i % ($output_length + 1); + $output = self::mb_strinsert($output, self::utf8($n), $i); + $i++; + } + } + catch(Exception $e) + { + error_log("[PUNYCODE] error ".$e->getMessage()); + return $input; + } + return $output; + } + +//adapt patched from: +//https://github.com/takezoh/php-PunycodeEncoder/blob/master/punycode.php + protected static function adapt($delta, $numpoints, $firsttime) + { + $delta = (int)($firsttime ? $delta / self::DAMP : $delta / 2); + $delta += (int)($delta / $numpoints); + $k = 0; + while ($delta > (((self::BASE - self::TMIN) * self::TMAX) / 2)) { + $delta = (int)($delta / (self::BASE - self::TMIN)); + $k += self::BASE; + } + return $k + (int)((self::BASE - self::TMIN + 1) * $delta / ($delta + self::SKEW)); + } + + protected static function digit2codepoint($d) + { + if ($d < 26) { + // 0..25 : 'a'..'z' + return $d + ord('a'); + } else if ($d < 36) { + // 26..35 : '0'..'9'; + return $d - 26 + ord('0'); + } else { + throw new Exception("PunycodeException.BAD_INPUT"); + } + } + + protected static function codepoint2digit($c) + { + if ($c - ord('0') < 10) { + // '0'..'9' : 26..35 + return $c - ord('0') + 26; + } else if ($c - ord('a') < 26) { + // 'a'..'z' : 0..25 + return $c - ord('a'); + } else { + throw new Exception("PunycodeException.BAD_INPUT"); + } + } + + protected static function rstrpos($haystack, $needle) + { + $pos = strpos (strrev($haystack), $needle); + if ($pos === false) + return false; + return strlen ($haystack)-1 - $pos; + } + + protected static function mb_strinsert($haystack, $needle, $position) + { + $old_encoding = mb_internal_encoding(); + mb_internal_encoding("UTF-8"); + $r = mb_substr($haystack,0,$position).$needle.mb_substr($haystack,$position); + mb_internal_encoding($old_encoding); + return $r; + } + + protected static function mb_substr($str,$start,$length) + { + $old_encoding = mb_internal_encoding(); + mb_internal_encoding("UTF-8"); + $r = mb_substr($str,$start,$length); + mb_internal_encoding($old_encoding); + return $r; + } + + protected static function mb_strlen($str) + { + $old_encoding = mb_internal_encoding(); + mb_internal_encoding("UTF-8"); + $r = mb_strlen($str); + mb_internal_encoding($old_encoding); + return $r; + } + + protected static function mb_strtolower($str) + { + $old_encoding = mb_internal_encoding(); + mb_internal_encoding("UTF-8"); + $r = mb_strtolower($str); + mb_internal_encoding($old_encoding); + return $r; + } + + public static function uniord($c)//cousin of ord() but for unicode + { + $ord0 = ord($c[0]); if ($ord0>=0 && $ord0<=127) return $ord0; + $ord1 = ord($c[1]); if ($ord0>=192 && $ord0<=223) return ($ord0-192)*64 + ($ord1-128); + if ($ord0==0xed && ($ord1 & 0xa0) == 0xa0) return false; //code points, 0xd800 to 0xdfff + $ord2 = ord($c[2]); if ($ord0>=224 && $ord0<=239) return ($ord0-224)*4096 + ($ord1-128)*64 + ($ord2-128); + $ord3 = ord($c[3]); if ($ord0>=240 && $ord0<=247) return ($ord0-240)*262144 + ($ord1-128)*4096 + ($ord2-128)*64 + ($ord3-128); + return false; + } + + public static function utf8($num)//cousin of ascii() but for utf8 + { + if($num<=0x7F) return chr($num); + if($num<=0x7FF) return chr(($num>>6)+192).chr(($num&63)+128); + if(0xd800<=$num && $num<=0xdfff) return '';//invalid block of utf8 + if($num<=0xFFFF) return chr(($num>>12)+224).chr((($num>>6)&63)+128).chr(($num&63)+128); + if($num<=0x10FFFF) return chr(($num>>18)+240).chr((($num>>12)&63)+128).chr((($num>>6)&63)+128).chr(($num&63)+128); + return ''; + } + + public static function is_valid_utf8($string) + { + for ($i=0, $ix=strlen($string); $i < $ix; $i++) + { + $c = ord($string[$i]); + if ($c==0x09 || $c==0x0a || $c==0x0d || (0x20 <= $c && $c < 0x7e) ) $n = 0; # 0bbbbbbb + else if (($c & 0xE0) == 0xC0) $n=1; # 110bbbbb + else if ($c==0xed && (ord($string[$i+1]) & 0xa0)==0xa0) return false; //code points, 0xd800 to 0xdfff + else if (($c & 0xF0) == 0xE0) $n=2; # 1110bbbb + else if (($c & 0xF8) == 0xF0) $n=3; # 11110bbb + //else if (($c & 0xFC) == 0xF8) $n=4; # 111110bb //byte 5, unnecessary in 4 byte UTF-8 + //else if (($c & 0xFE) == 0xFC) $n=5; # 1111110b //byte 6, unnecessary in 4 byte UTF-8 + else return false; + for ($j=0; $j<$n; $j++) { // n bytes matching 10bbbbbb follow ? + if ((++$i == $ix) || ((ord($string[$i]) & 0xC0) != 0x80)) + return false; + } + } + return true; + } + +} + + diff --git a/lib/coupang.js b/lib/coupang.js new file mode 100644 index 0000000..692ba25 --- /dev/null +++ b/lib/coupang.js @@ -0,0 +1,32 @@ +// coupang.js +// Namhyeon Go +// https://github.com/gnh1201/welsonjs +// +// ***SECURITY NOTICE*** +// Due to potential security issues, the Public API URL is not provided. If you need to request access, please refer to the project's contact information. +// You can download the server-side script that implements this functionality from the link below: +// https://github.com/gnh1201/caterpillar +// +var JsonRpc2 = require("lib/jsonrpc2"); + +function search(s) { + var rpc = JsonRpc2.create(JsonRpc2.DEFAULT_JSONRPC2_URL); + var result = rpc.invoke("relay_invoke_method", { + "callback": "load_script", + "requires": [ + "https://pub-f926e14287b340cd9eff33731bb25329.r2.dev/coupang.class.php" + ], + "args": [ + "$search = new CoupangProductSearch(); return $search->searchProducts('" + s + "')" + ] + }, ""); + + return result.data; +} + +exports.search = search; + +exports.VERSIONINFO = "Coupang Product Search (coupang.js) version 0.1"; +exports.AUTHOR = "abuse@catswords.net"; +exports.global = global; +exports.require = global.require;