Я просил код парсера JS сгенерировать ChatGPT, DeepSeek, Qwen и в итоге написал все сам. тут вроде все просто:
- Из значений только пустой массив
[]
. - Операторы:
+
,!
,(
,)
. Приоритет должен соблюдаться. - Под капотом у нас строки в виде чисел, числа, булев и пустые массивы
import re
class JSExpressionParser:
tokenizer = re.compile(r"\[\]|[+!()]")
def __init__(self):
self.index = 0
self.token = None
self.tokens = []
def advance(self):
try:
self.token = self.tokens[self.index]
self.index += 1
except IndexError:
self.token = None
def parse(self, expression: str):
self.tokens = self.tokenizer.findall(expression)
self.index = 0
self.advance()
result = self.expression()
assert self.token is None, f"unexpected token: {self.token!r}"
return result
def expression(self):
left = self.factor()
while self.token == "+":
self.advance()
right = self.factor()
left = self.js_add(left, right)
return left
def js_add(self, left, right):
# Если одно из значений строка, результат — строка
# [] + 1 === '1'
if isinstance(left, (str, list)) or isinstance(right, (str, list)):
result = self.to_string(left) + self.to_string(right)
else:
result = self.to_number(left) + self.to_number(right)
# print(f"{left!r} + {right!r} = {result!r}")
return result
def factor(self):
if self.token == "+":
self.advance()
return self.to_number(self.factor())
elif self.token == "!":
self.advance()
return not self.to_boolean(self.factor())
elif self.token == "(":
self.advance()
result = self.expression()
assert self.token == ")", (
f"unexpected token: {self.token!r}; expected ')'"
)
self.advance()
return result
elif self.token == "[]":
self.advance()
return []
else:
raise ValueError(f"Unexpected token: {self.token}")
def to_string(self, value):
if value == []:
return ""
return str(value)
def to_number(self, value):
if value == []:
return 0
return int(value)
def to_boolean(self, value):
return value not in (0, False)
def parse_challenge(challenge_body: str):
west, east = re.findall(r"(?:west|east)=([^,]+)", challenge_body)
parser = JSExpressionParser()
west_value = parser.parse(west)
east_value = parser.parse(east)
return {
"west": west_value,
"east": east_value,
"wsidchk": west_value + east_value,
"action": re.search('action="([^"]+)', challenge_body).group(1),
"method": re.search('="([^"]+)', challenge_body).group(1),
}
challenge_body = """\
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="robots" content="noindex, nofollow">
<title>One moment, please...</title>
<!-- ... -->
<body>
<h1>Please wait while your request is being verified...</h1>
<form id="wsidchk-form" style="display:none;" action="/z0f76a1d14fd21a8fb5fd0d03e0fdc3d3cedae52f" method="GET">
<input type="hidden" id="wsidchk" name="wsidchk"/>
</form>
<script>
(function(){
var west=+((+!+[]+!![]+!![]+!![]+!![]+!![]+!![])+(+!+[]+!![]+!![]+!![]+!![]+[])+(+!+[]+!![]+!![]+!![]+!![]+!![]+!![])+(+!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(+!+[]+!![]+!![]+!![]+!![]+!![])+(+!+[]+!![]+[])+(+!+[]+!![]+!![]+!![]+!![]+!![])),
east=+((+!+[])+(+!+[]+!![]+!![]+!![]+!![]+[])+(+!+[]+!![]+!![]+!![]+!![]+!![])+(+!+[]+[])+(+!+[]+!![]+!![]+!![]+!![]+!![]+!![])+(+!+[]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(+!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(+![]+[])),
x=function(){try{return !!window.addEventListener;}catch(e){return !!0;} },
y=function(y,z){x() ? document.addEventListener('DOMContentLoaded',y,z) : document.attachEvent('onreadystatechange',y);};
y(function(){
document.getElementById('wsidchk').value = west + east;
document.getElementById('wsidchk-form').submit();
}, false);
})();
</script>
</body>
</html>
"""
challenge = parse_challenge(challenge_body)
print(challenge)
assert challenge["west"] == 7579626
assert challenge["east"] == 15617780
assert challenge["action"] == "/z0f76a1d14fd21a8fb5fd0d03e0fdc3d3cedae52f"
Сделал я его методом тыка… Тут не все по стандартам JS, но такие выражения правильно решает:
+((+!+[]+!![]+!![]+!![]+!![]+!![]+!![])+(+!+[]+!![]+!![]+!![]+!![]+[])+(+!+[]+!![]+!![]+!![]+!![]+!![]+!![])+(+!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(+!+[]+!![]+!![]+!![]+!![]+!![])+(+!+[]+!![]+[])+(+!+[]+!![]+!![]+!![]+!![]+!![]))
Хорошо… Я это написал после борьбы с придурочным AI. Решил я ему поручить все переписать на Go.
- ChatGPT не могет, высрал говнину
- DeepSeek сообразил сразу как правильно, но код не рабочий
- Qwen тот же результат
Нерабочий код на Go:
package cloudflare_challenge_parser
import (
"fmt"
"regexp"
"strconv"
)
// EmptyArray представляет пустой массив.
type EmptyArray struct{}
// ChallengeResult представляет результат парсинга вызова Cloudflare.
type ChallengeResult struct {
West int
East int
Wsidchk int
Action string
Method string
}
// JSExpressionParser представляет парсер для JavaScript-выражений.
type JSExpressionParser struct {
index int
token string
tokens []string
}
// Tokenizer для разбиения выражения на токены.
var tokenizer = regexp.MustCompile(`\[\]|[+!()]|\d+`)
// Advance переходит к следующему токену.
func (p *JSExpressionParser) Advance() {
if p.index < len(p.tokens) {
p.token = p.tokens[p.index]
p.index++
} else {
p.token = ""
}
}
// Parse парсит выражение и возвращает результат как целое число.
func (p *JSExpressionParser) Parse(expression string) (int, error) {
p.tokens = tokenizer.FindAllString(expression, -1)
p.index = 0
p.Advance()
result := p.expression()
if p.token != "" {
return 0, fmt.Errorf("unexpected token: %s", p.token)
}
return p.toNumber(result), nil
}
// expression обрабатывает сложение.
func (p *JSExpressionParser) expression() interface{} {
left := p.factor()
for p.token == "+" {
p.Advance()
right := p.factor()
left = p.jsAdd(left, right)
}
return left
}
// jsAdd реализует логику сложения в JavaScript.
func (p *JSExpressionParser) jsAdd(left, right interface{}) interface{} {
// Если одно из значений строка или пустой массив, результат — строка.
if p.isStringOrEmptyArray(left) || p.isStringOrEmptyArray(right) {
return p.toString(left) + p.toString(right)
}
// Иначе результат — число.
return p.toNumber(left) + p.toNumber(right)
}
// isStringOrEmptyArray проверяет, является ли значение строкой или пустым массивом.
func (p *JSExpressionParser) isStringOrEmptyArray(value interface{}) bool {
switch value.(type) {
case string, EmptyArray:
return true
default:
return false
}
}
// factor обрабатывает факторы выражения.
func (p *JSExpressionParser) factor() interface{} {
switch p.token {
case "+":
p.Advance()
return p.toNumber(p.factor())
case "!":
p.Advance()
return !p.toBoolean(p.factor())
case "(":
p.Advance()
result := p.expression()
if p.token != ")" {
panic(fmt.Sprintf("unexpected token: %s; expected ')'", p.token))
}
p.Advance()
return result
case "[]":
p.Advance()
return EmptyArray{}
default:
if num, err := strconv.Atoi(p.token); err == nil {
p.Advance()
return num
}
panic(fmt.Sprintf("unexpected token: %s", p.token))
}
}
// toBoolean преобразует значение в булево.
func (p *JSExpressionParser) toBoolean(value interface{}) bool {
switch v := value.(type) {
case bool:
return v
case int:
return v != 0
case string:
return v != ""
case EmptyArray:
return false
default:
return false
}
}
// toNumber преобразует значение в число.
func (p *JSExpressionParser) toNumber(value interface{}) int {
switch v := value.(type) {
case int:
return v
case string:
num, err := strconv.Atoi(v)
if err != nil {
return 0
}
return num
case EmptyArray:
return 0
default:
return 0
}
}
// toString преобразует значение в строку.
func (p *JSExpressionParser) toString(value interface{}) string {
switch v := value.(type) {
case string:
return v
case int:
return strconv.Itoa(v)
case EmptyArray:
return ""
default:
return fmt.Sprint(value)
}
}
// ParseChallenge парсит тело вызова Cloudflare и возвращает структуру.
func ParseChallenge(challengeBody string) (*ChallengeResult, error) {
// Регулярные выражения для извлечения данных.
reWestEast := regexp.MustCompile(`(?:west|east)=([^,]+)`)
reAction := regexp.MustCompile(`action="([^"]+)"`)
reMethod := regexp.MustCompile(`method="([^"]+)"`)
// Извлечение значений west и east.
matches := reWestEast.FindAllStringSubmatch(challengeBody, -1)
if len(matches) < 2 {
return nil, fmt.Errorf("failed to extract west and east values")
}
westExpr := matches[0][1]
eastExpr := matches[1][1]
// Парсинг west и east.
parser := &JSExpressionParser{}
westValue, err := parser.Parse(westExpr)
if err != nil {
return nil, fmt.Errorf("failed to parse west: %v", err)
}
eastValue, err := parser.Parse(eastExpr)
if err != nil {
return nil, fmt.Errorf("failed to parse east: %v", err)
}
// Извлечение action и method.
actionMatch := reAction.FindStringSubmatch(challengeBody)
methodMatch := reMethod.FindStringSubmatch(challengeBody)
if len(actionMatch) < 2 || len(methodMatch) < 2 {
return nil, fmt.Errorf("failed to extract action or method")
}
action := actionMatch[1]
method := methodMatch[1]
// Формирование результата.
return &ChallengeResult{
West: westValue,
East: eastValue,
Wsidchk: westValue + eastValue,
Action: action,
Method: method,
}, nil
}
Он нерабочий. Что там править, делать я в душе не знаю — тупо прикрутил интерпретатор JS, но факт, что такое я написал сам…
Итого: я все еще лучше AI…