captcha_gen.php 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. <?php
  2. class captcha{
  3. public function __construct($frontend, $get, $filters, $page, $output){
  4. // check if we want captcha
  5. if(config::BOT_PROTECTION !== 1){
  6. apcu_inc("real_requests");
  7. if($output === true){
  8. $frontend->loadheader(
  9. $get,
  10. $filters,
  11. $page
  12. );
  13. }
  14. return;
  15. }
  16. /*
  17. Validate cookie, if it exists
  18. */
  19. if(isset($_COOKIE["pass"])){
  20. if(
  21. // check if key is not malformed
  22. preg_match(
  23. '/^c[0-9]+\.[A-Za-z0-9]{20}$/',
  24. $_COOKIE["pass"]
  25. ) &&
  26. // does key exist
  27. apcu_exists($_COOKIE["pass"])
  28. ){
  29. // exists, increment counter
  30. $inc = apcu_inc($_COOKIE["pass"]);
  31. // we start counting from 1
  32. // when it has been incremented to 102, it has reached
  33. // 100 reqs
  34. if($inc >= 102){
  35. // reached limit, delete and give captcha
  36. apcu_delete($_COOKIE["pass"]);
  37. }else{
  38. // the cookie is OK! dont die() and give results
  39. apcu_inc("real_requests");
  40. if($output === true){
  41. $frontend->loadheader(
  42. $get,
  43. $filters,
  44. $page
  45. );
  46. }
  47. return;
  48. }
  49. }
  50. }
  51. if($output === false){
  52. http_response_code(429); // too many reqs
  53. echo json_encode([
  54. "status" => "The \"pass\" token in your cookies is missing or has expired!!"
  55. ]);
  56. die();
  57. }
  58. /*
  59. Validate form data
  60. */
  61. $lines =
  62. explode(
  63. "\r\n",
  64. file_get_contents("php://input")
  65. );
  66. $invalid = false;
  67. $answers = [];
  68. $key = false;
  69. $error = "";
  70. foreach($lines as $line){
  71. $line = explode("=", $line, 2);
  72. if(count($line) !== 2){
  73. $invalid = true;
  74. break;
  75. }
  76. preg_match(
  77. '/^c\[([0-9]+)\]$/',
  78. $line[0],
  79. $regex
  80. );
  81. if(
  82. $line[1] != "on" ||
  83. !isset($regex[0][1])
  84. ){
  85. // check if its k
  86. if(
  87. $line[0] == "k" &&
  88. strpos($line[1], "c.") === 0
  89. ){
  90. $key = apcu_fetch($line[1]);
  91. apcu_delete($line[1]);
  92. }
  93. break;
  94. }
  95. $regex = (int)$regex[1];
  96. if(
  97. $regex >= 16 ||
  98. $regex <= -1
  99. ){
  100. $invalid = true;
  101. break;
  102. }
  103. $answers[] = $regex;
  104. }
  105. if(
  106. !$invalid &&
  107. $key !== false
  108. ){
  109. $check = $key[1];
  110. // validate answer
  111. for($i=0; $i<count($key[0]); $i++){
  112. if(!in_array($i, $answers)){
  113. continue;
  114. }
  115. if($key[0][$i][0] == $key[2]){
  116. $check--;
  117. }else{
  118. // got a wrong answer
  119. $check = -1;
  120. break;
  121. }
  122. }
  123. if($check === 0){
  124. // we passed the captcha
  125. // set cookie
  126. $inc = apcu_inc("cookie");
  127. $chars =
  128. array_merge(
  129. range("A", "Z"),
  130. range("a", "z"),
  131. range(0, 9)
  132. );
  133. $c = count($chars) - 1;
  134. $key = "c" . $inc . ".";
  135. for($i=0; $i<20; $i++){
  136. $key .= $chars[random_int(0, $c)];
  137. }
  138. apcu_inc($key, 1, $stupid, 86400);
  139. apcu_inc("real_requests");
  140. setcookie(
  141. "pass",
  142. $key,
  143. [
  144. "expires" => time() + 86400, // expires in 24 hours
  145. "samesite" => "Lax",
  146. "path" => "/"
  147. ]
  148. );
  149. $frontend->loadheader(
  150. $get,
  151. $filters,
  152. $page
  153. );
  154. return;
  155. }else{
  156. $error = "<div class=\"quote\">You were <a href=\"https://www.youtube.com/watch?v=e1d7fkQx2rk\" target=\"_BLANK\" rel=\"noreferrer nofollow\">kicked out of Mensa.</a> Please try again.</div>";
  157. }
  158. }
  159. // get the positions for the answers
  160. // will return between 3 and 6 answer positions
  161. $range = range(0, 15);
  162. $answer_pos = [];
  163. array_splice($range, 0, 1);
  164. for($i=0; $i<random_int(3, 6); $i++){
  165. $answer_pos_tmp =
  166. array_splice(
  167. $range,
  168. random_int(
  169. 0,
  170. 14 - $i
  171. ),
  172. 1
  173. );
  174. $answer_pos[] = $answer_pos_tmp[0];
  175. }
  176. // choose a dataset
  177. $c = count(config::CAPTCHA_DATASET);
  178. $choosen = config::CAPTCHA_DATASET[random_int(0, $c - 1)];
  179. $choices = [];
  180. for($i=0; $i<$c; $i++){
  181. if(config::CAPTCHA_DATASET[$i][0] == $choosen[0]){
  182. continue;
  183. }
  184. $choices[] = config::CAPTCHA_DATASET[$i];
  185. }
  186. // generate grid data
  187. $grid = [];
  188. for($i=0; $i<16; $i++){
  189. if(in_array($i, $answer_pos)){
  190. $grid[] = $choosen;
  191. }else{
  192. $grid[] = $choices[random_int(0, count($choices) - 1)];
  193. }
  194. }
  195. $key = "c." . apcu_inc("captcha_gen", 1) . "." . random_int(0, 100000000);
  196. apcu_store(
  197. $key,
  198. [
  199. $grid,
  200. count($answer_pos),
  201. $choosen[0],
  202. false // has captcha been generated?
  203. ],
  204. 120 // we give user 2 minutes to get captcha, in case of network error
  205. );
  206. $payload = [
  207. "class" => "",
  208. "right-left" => "",
  209. "right-right" => "",
  210. "left" =>
  211. '<div class="infobox">' .
  212. '<h1>IQ test</h1>' .
  213. 'Due to getting hit with 20,000 bot requests per day, I had to put this up. Sorry.<br><br>' .
  214. 'Solving this captcha will allow you to make 100 searches today. I will add a way for legit users to bypass the captcha later. Sorry /g/tards!!' .
  215. $error .
  216. '<form method="POST" enctype="text/plain" autocomplete="off">' .
  217. '<div class="captcha-wrapper">' .
  218. '<div class="captcha">' .
  219. '<img src="captcha?k=' . $key . '" alt="Captcha image">' .
  220. '<div class="captcha-controls">' .
  221. '<input type="checkbox" name="c[0]" id="c0">' .
  222. '<label for="c0"></label>' .
  223. '<input type="checkbox" name="c[1]" id="c1">' .
  224. '<label for="c1"></label>' .
  225. '<input type="checkbox" name="c[2]" id="c2">' .
  226. '<label for="c2"></label>' .
  227. '<input type="checkbox" name="c[3]" id="c3">' .
  228. '<label for="c3"></label>' .
  229. '<input type="checkbox" name="c[4]" id="c4">' .
  230. '<label for="c4"></label>' .
  231. '<input type="checkbox" name="c[5]" id="c5">' .
  232. '<label for="c5"></label>' .
  233. '<input type="checkbox" name="c[6]" id="c6">' .
  234. '<label for="c6"></label>' .
  235. '<input type="checkbox" name="c[7]" id="c7">' .
  236. '<label for="c7"></label>' .
  237. '<input type="checkbox" name="c[8]" id="c8">' .
  238. '<label for="c8"></label>' .
  239. '<input type="checkbox" name="c[9]" id="c9">' .
  240. '<label for="c9"></label>' .
  241. '<input type="checkbox" name="c[10]" id="c10">' .
  242. '<label for="c10"></label>' .
  243. '<input type="checkbox" name="c[11]" id="c11">' .
  244. '<label for="c11"></label>' .
  245. '<input type="checkbox" name="c[12]" id="c12">' .
  246. '<label for="c12"></label>' .
  247. '<input type="checkbox" name="c[13]" id="c13">' .
  248. '<label for="c13"></label>' .
  249. '<input type="checkbox" name="c[14]" id="c14">' .
  250. '<label for="c14"></label>' .
  251. '<input type="checkbox" name="c[15]" id="c15">' .
  252. '<label for="c15"></label>' .
  253. '</div>' .
  254. '</div>' .
  255. '</div>' .
  256. '<input type="hidden" name="k" value="' . $key . '">' .
  257. '<input type="submit" value="Check IQ" class="captcha-submit">' .
  258. '</form>' .
  259. '</div>'
  260. ];
  261. http_response_code(429); // too many reqs
  262. $frontend->loadheader(
  263. $get,
  264. $filters,
  265. $page
  266. );
  267. echo $frontend->load("search.html", $payload);
  268. die();
  269. }
  270. }