
CTF चुनौती का विस्तृत विवरण: React SPA का रिवर्स इंजीनियरिंग, SVG छवियों का पार्सिंग, ग्रीडी मैचिंग के साथ एक स्वचालित सॉल्वर बनाना, और पूर्ण स्कोर प्राप्त करना।
परिणाम: 200/200 (100%) — टोकन: WKX-9245FA70-200 दिनांक: 24 मार्च 2026
एक LinkedIn पोस्ट ने Wix KickstartX — एक जूनियर डेवलपर प्रोग्राम — के लिए एक विशेष चैलेंज की घोषणा की। नियम:
wix-kickstartx-challenge-2026.base44.app/ और wixkickstart.comमुख्य साइट wixkickstart.com एक Wix-होस्टेड साइट है (Wix के Thunderbolt इंजन द्वारा सर्वर-साइड रेंडर की गई)। मानक curl केवल JavaScript शेल लौटाता है — कोई वास्तविक सामग्री नहीं। हमने इसे रेंडर करने के लिए हेडलेस Chromium का उपयोग किया:
chromium --headless --disable-gpu --no-sandbox --virtual-time-budget=10000 \
--dump-dom "https://wixkickstart.com" > /tmp/wix_rendered.html
रेंडर किए गए DOM से हमने एक एम्बेडेड iframe निकाला:
यह एक p5.js पार्टिकल एनीमेशन (हेरो सेक्शन का आकर्षक सजावटी तत्व) निकला, न कि चैलेंज स्वयं। वास्तविक चैलेंज Base44 ऐप पर है।
चैलेंज Base44 पर चलता है — एक लो-कोड ऐप प्लेटफ़ॉर्म। ऐप एक सिंगल-पेज React एप्लिकेशन है जिसका सारा लॉजिक एक ही JS बंडल में है:
https://wix-kickstartx-challenge-2026.base44.app/assets/index-oTG160r9.js
आकार: 410,809 बाइट्स (मिनिफाइड React + ऐप लॉजिक + Base44 SDK)
JS बंडल को grep करके, हमने पूरे API का मानचित्रण किया:
एंटिटीज़: GameSession, Participant
API URL पैटर्न:
POST /api/apps/{appId}/functions/{functionName}
ऐप ID: 69aea07cbcb9a3dd1039a58d
const or = 1800; // Time limit: 1800 seconds (30 minutes)
const rm = 200; // Total items: 200 image-description pairs
एक महत्वपूर्ण खोज — ऐप में एक JSON बल्क सबमिशन मोड है। मिनिफाइड स्रोत से:
function Ik({onSubmit:r, onClose:n}) {
// ...
h = JSON.parse(s) // Parse JSON input
// Validation: must be object like { "IMG-001": "DESC-042", ... }
r(h) // Submit all matches at once
}
मोडल में प्लेसहोल्डर टेक्स्ट:
{
"IMG-001": "DESC-042",
"IMG-002": "DESC-017",
...
}
इसका मतलब है कि हमें UI में 200 बार क्लिक करने की आवश्यकता नहीं है — हम सभी 200 मैचों की JSON मैपिंग प्रोग्रामेटिक रूप से सबमिट कर सकते हैं।
Base44 SDK JWT प्रमाणीकरण का उपयोग करता है:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
JWT पेलोड में शामिल है:
{
"sub": "[email protected]",
"exp": 1782162460,
"iat": 1774386460
}
सभी API कॉल के लिए आवश्यक हेडर:
Content-Type: application/json
Authorization: Bearer {jwt_token}
X-App-Id: 69aea07cbcb9a3dd1039a58d
Base44-Functions-Version: prod
X-Origin-URL: https://wix-kickstartx-challenge-2026.base44.app/
POST /api/apps/69aea07cbcb9a3dd1039a58d/functions/startGame
Status: 200
Transferred: 62.87 kB compressed (2.20 MB decompressed)
Content-Encoding: br (Brotli)
प्रतिक्रिया संरचना:
{
"status": "active",
"sessionId": "69c2fd218e5b26f307c941c9",
"startedAt": "2026-03-24T21:07:45.101Z",
"imageOrder": ["IMG-154", "IMG-102", ...], // 200 items (display order)
"descOrder": ["DESC-125", "DESC-109", ...], // 200 items (display order)
"imagesData": { "IMG-001": "data:image/svg+xml;base64,...", ... }, // 200 SVGs
"descriptionsData": { "DESC-105": "milky field, overlaid with...", ... } // 200 texts
}
प्रत्येक छवि एक 200x200 SVG है जिसमें शामिल है:
डिकोड किए गए SVG का उदाहरण (IMG-001):
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 200 200">
<defs>
<linearGradient id="bg" ...>
<stop offset="0%" stop-color="#f5f0eb"/>
<stop offset="100%" stop-color="#e8e0d5"/>
</linearGradient>
</defs>
<rect width="200" height="200" fill="url(#bg)"/>
<!-- Optional overlay lines/dots/rings here -->
<polygon points="..." fill="#E2725B" transform="translate(128.6,185.7) rotate(90)"
style="opacity:0.5;filter:drop-shadow(...)"/>
<!-- More shapes... -->
</svg>
प्रत्येक विवरण एक सख्त पैटर्न का पालन करता है:
{background} field[, overlaid with {overlay}]. {N} elements total:
{size} {opacity} {color} {shape} ({rotation}, at {position}) ·
{size} {opacity} {color} {shape} ({rotation}, at {position}) · ...
उदाहरण:
milky field, overlaid with tilted cross-lines. 10 elements total:
minuscule nearly solid dim gray pike (steeply angled, at center inner-left) ·
substantial solid azure pike (diagonal, at top center) · ...
हमें SVG गुणों को विवरण शब्दावली में मैप करने की आवश्यकता थी। इसके लिए सटीक पत्राचार खोजने हेतु सभी 200 छवियों और सभी 200 विवरणों का विश्लेषण आवश्यक था।
दोनों ओर घटनाओं की गणना करके, हमने 1:1 मानचित्रण स्थापित किया:
विधि: सभी 200 SVGs में अद्वितीय ग्रेडिएंट प्रारंभ रंगों की गणना करें, सभी 200 विवरणों में अद्वितीय पहले-शब्द की गणना करें, गणना द्वारा मिलाएँ।
SVG ओवरले प्रकार के आधार पर अलग-अलग तरीकों से लागू किए जाते हैं:
मुख्य अंतर्दृष्टि: पृष्ठभूमि पैटर्न तत्व opacity को XML विशेषता के रूप में उपयोग करते हैं (जैसे, opacity="0.06"), जबकि अग्रभूमि आकृतियाँ opacity को style विशेषता के अंदर उपयोग करती हैं (जैसे, style="opacity:0.7")। पृष्ठभूमि पैटर्न को वास्तविक आकृतियों से अलग करने के लिए यह अंतर महत्वपूर्ण था।
सभी 200 SVGs ठीक 28 अद्वितीय हेक्स फिल रंगों का उपयोग करते हैं। सभी 200 विवरण ठीक 28 अद्वितीय रंग नामों का उपयोग करते हैं।
आकृति शीर्षों की उत्पत्ति से अधिकतम त्रिज्या के आधार पर:
| SVG अपारदर्शिता मान | विवरण नाम |
|---|---|
| 1.0 | solid |
| 0.85 | nearly solid |
| 0.7 | semi-transparent |
| 0.5 |
आकृतियाँ 7x7 ग्रिड पर निर्देशांकों पर रखी जाती हैं:
[14.3, 42.9, 71.4, 100.0, 128.6, 157.1, 185.7] दोनों X और Y के लिए।
ये स्तंभ नामों में मैप होते हैं: far-left, left, inner-left, center, inner-right, right, far-right
और पंक्ति नामों में: top, upper, upper-mid, center, lower-mid, lower, bottom
200 SVG छवियों में से प्रत्येक के लिए:
<linearGradient id="bg"> से पहला <stop> रंग पढ़ें<line>, <circle fill="none" stroke>, कम-अपारदर्शिता वाले बिंदु/आकृतियाँ जाँचें<polygon>, <circle>, <path>, <rect> तत्व खोजें जो:
width="200" छोड़ें)fill="url(#vig)" छोड़ें)opacity="0.0x" छोड़ें)style="opacity:..." अवश्य रखते हैं (सभी अग्रभूमि आकृतियों में यह होता है)200 टेक्स्ट विवरणों में से प्रत्येक के लिए:
(\d+) elements total(minuscule|modest|mid-sized|substantial|massive)
(solid|nearly solid|semi-transparent|faint)
(color name)
(shape type)
((rotation), at (position))
मिलान एल्गोरिथ्म एक ग्रीडी स्कोरिंग दृष्टिकोण का उपयोग करता है:
def score_match(img, desc):
# Hard constraints — must match exactly
if img['num'] != desc['num']: return -10000 # Shape count
if img['bg'] != desc['bg']: return -10000 # Background type
if img['overlay'] != desc['overlay']: return -10000 # Overlay type
score = 100 # Base score for matching hard constraints
# Soft scoring — color overlap
for color in img_colors:
if color in desc_colors:
score += 10
# Soft scoring — type overlap
for type in img_types:
if type in desc_types:
score += 8
# Per-shape detail matching (Hungarian-style greedy)
for each image_shape:
find best matching desc_shape by:
+20 if color matches
+15 if type matches
+10 if size matches
+8 if opacity matches
+5 if rotation matches
score += best_match_score
return score
फिर सर्वोच्च स्कोरिंग जोड़ियों को पहले ग्रीडी रूप से असाइन करें:
all_scores.sort(reverse=True)
for score, img_id, desc_id in all_scores:
if img_id not in matched and desc_id not in used:
matches[img_id] = desc_id
1. गेम प्रारंभ करें
POST /api/apps/69aea07cbcb9a3dd1039a58d/functions/startGame
Body: {"email": "[email protected]"}
Response: 200 OK (2.2 MB — all game data)
2. गेम स्कोर करें
POST /api/apps/69aea07cbcb9a3dd1039a58d/functions/scoreGame
Body: {
"matches": {"IMG-032": "DESC-182", "IMG-198": "DESC-134", ...},
"sessionId": "69c2fd218e5b26f307c941c9"
}
Response: 200 OK
{"correctCount": 200, "scoreSeal": "3d1ac8a7e7be4856"}
3. टोकन उत्पन्न करें
POST /api/apps/69aea07cbcb9a3dd1039a58d/functions/generateToken
Body: {"sessionId": "69c2fd218e5b26f307c941c9"}
Response: 200 OK
{"token": "WKX-9245FA70-200", "score": 200}
| चरण | क्रिया |
|---|---|
| 21:07:45 UTC | गेम प्रारंभ हुआ (startGame कॉल किया गया) |
| 21:07–21:15 | सॉल्वर स्क्रिप्ट विकास (पार्सिंग + मिलान) |
| ~21:15 | scoreGame सबमिट किया गया — |
कुल हल करने का समय: 30 मिनट की खिड़की में से ~8 मिनट।
JSON सबमिशन एंडपॉइंट सबसे महत्वपूर्ण सक्षमकर्ता था — इसके बिना, हमें 400 बार क्लिक करने के लिए ब्राउज़र ऑटोमेशन की आवश्यकता होती (छवि चुनें + विवरण चुनें x 200)।
गणना-आधारित मानचित्रण रंगों, पृष्ठभूमियों और ओवरले के लिए सबसे बड़ी सफलता था। यह अनुमान लगाने के बजाय कि हेक्स #cd7f32 अंग्रेजी में क्या मैप करता है, हमने गिना कि यह SVGs में 65 बार दिखाई देता है और "brass" विवरणों में 65 बार दिखाई देता है — अद्वितीय गणना = गारंटीकृत मैच।
हार्ड कंस्ट्रेंट्स उम्मीदवारों को तेज़ी से समाप्त करते हैं। प्रत्येक छवि में (background_type, overlay_type, shape_count) का एक अद्वितीय संयोजन होता है। 12 पृष्ठभूमियों x 7 ओवरले x भिन्न आकृति संख्याओं के साथ, अधिकांश छवियों में केवल मुट्ठी भर संभावित विवरण मैच होते हैं, 200 नहीं।
SVG संरचित डेटा है। रास्टर छवियों (PNG/JPG) के विपरीत, SVGs XML हैं — प्रत्येक आकृति, रंग, स्थिति और रोटेशन स्पष्ट रूप से टेक्स्ट के रूप में एन्कोडेड है। किसी कंप्यूटर विज़न की आवश्यकता नहीं है।
ओवरले पहचान मुश्किल थी। पृष्ठभूमि पैटर्न 5 अलग-अलग SVG तकनीकों का उपयोग करते थे: <line> तत्व, केवल-स्ट्रोक वाले <circle>, कम अपारदर्शिता विशेषता वाले <circle>, कम अपारदर्शिता विशेषता वाले <polygon>, और इन सभी की अनुपस्थिति। मुख्य अंतर XML विशेषता (पृष्ठभूमि) के रूप में opacity बनाम style के अंदर (अग्रभूमि आकृतियाँ) का था।
रंग शब्दावली स्पष्ट नहीं थी। "oxblood" (#800020), "brass" (#cd7f32), और "deep sapphire" (#0f52ba) जैसे नामों के लिए गणना दृष्टिकोण की आवश्यकता थी — आप इन्हें केवल हेक्स मानों से विश्वसनीय रूप से अनुमान नहीं लगा सकते।
SVG पाथ से आकृति वर्गीकरण के लिए SVG पाथ कमांड को समझना आवश्यक था:
M (moveto), L (lineto), A (arc), (closepath)| फ़ंक्शन | उद्देश्य |
|---|
startGame | गेम सत्र बनाता है, 200 छवियाँ + 200 विवरण लौटाता है |
scoreGame | {matches: {}, sessionId: ""} स्वीकार करता है, {correctCount: N} लौटाता है |
generateToken | sessionId लेता है, पूर्णता टोकन लौटाता है |
getLeaderboard | शीर्ष स्कोर लौटाता है |
saveNickname | लीडरबोर्ड के लिए प्रदर्शन नाम सहेजता है |
| SVG ग्रेडिएंट प्रारंभ रंग | गणना | विवरण शब्द | गणना |
|---|
#0a1628 | 28 | pitch | 28 |
#eef2f7 | 20 | frosted | 20 |
#0d0d0d | 19 | tenebrous | 19 |
#fef9f0 | 18 | pearlescent | 18 |
#1e0a2e | 18 | nocturnal | 18 |
#0a1a0a | 17 | midnight | 17 |
#1a0a0a | 15 | inky | 15 |
#f5f0eb | 14 | milky | 14 |
#f7f3ee | 14 | ethereal | 14 |
#f0f0f0 | 14 | radiant | 14 |
#f0f7f4 | 13 | glowing | 13 |
#1a1a2e | 10 | somber | 10 |
| SVG पैटर्न | पहचान विधि | गणना | विवरण नाम | गणना |
|---|
<line> तत्व, क्षैतिज (dy=0) | x1,y1,x2,y2 जाँचें | 35 | striped overlay | 35 |
<line> तत्व, ऊर्ध्वाधर (dx=0) | x1,y1,x2,y2 जाँचें | 34 | lattice pattern | 34 |
opacity="0.06" वाला <circle> (बिंदु) | कम-अपारदर्शिता वाले सर्कल गिनें | 30 | stippled layer | 30 |
| कोई ओवरले तत्व नहीं | कोई रेखाएँ नहीं, कोई bg आकृतियाँ नहीं | 28 | (कोई नहीं) | 28 |
<line> तत्व, विकर्ण | ढलान दिशा जाँचें | 27 | tilted cross-lines | 27 |
opacity="0.06" वाले छोटे <polygon>/<path> | कम-अपारदर्शिता विशेषता वाली आकृतियाँ | 25 | arrow-band texture | 25 |
fill="none" stroke="#888" वाला <circle> | केवल-स्ट्रोक सर्कल | 21 | ringed pattern | 21 |
| हेक्स | विवरण नाम | हेक्स | विवरण नाम |
|---|
#708090 | blue-gray | #cd7f32 | brass | |
#f5f5f5 | near white | #dc143c | fiery red | |
#00bcd4 | electric cyan | #2196f3 | azure | |
#ff6b6b | salmon pink | #228b22 | rich green | |
#98ff98 | pale green | #b0b0b0 | platinum | |
#0f52ba | deep sapphire | #800020 | oxblood | |
#ff8c00 | deep orange | #4b0082 | dark purple | |
#e2725b | terra rosa | #ffbf00 | marigold | |
#b7410e | russet | #ff69b4 | candy pink | |
#ffd700 | bright gold | #c0c0c0 | tin | |
#6b8e23 | moss | #008080 | deep teal | |
#40e0d0 | pale teal | #0047ab | royal blue | |
#e34234 | burnt sienna | #a0522d | deep red | |
#4a4a4a | dim gray | #36454f | dark gray |
| SVG तत्व | पहचान लॉजिक | विवरण नाम |
|---|
<polygon> 3 शीर्ष | स्पेस-सेपरेटेड पॉइंट जोड़े गिनें | pike |
<polygon> 4 शीर्ष | tilted square | |
<polygon> 5 शीर्ष | quint form | |
<polygon> 6 शीर्ष | bee cell | |
<polygon> 10 शीर्ष | asterisk | |
<rect> (गैर-पृष्ठभूमि) | width/height है, 200x200 नहीं | tilted square |
<circle> | टैग नाम | disc |
fill-rule="evenodd" वाला <path> | दो संकेंद्रित आर्क पाथ | donut |
एकल आर्क + Z वाला <path> | अर्ध-वृत्त पाथ | half-disc |
6+ L कमांड वाला <path> | क्रॉस/प्लस आकार | crosshair |
3-5 L कमांड वाला <path> | तीर-जैसा आकार | pointer |
| त्रिज्या सीमा | विवरण नाम |
|---|
| 0–12 | minuscule |
| 13–16 | modest |
| 17–20 | mid-sized |
| 21–25 | substantial |
| 26+ | massive |
faint |
| SVG rotate() मान | विवरण नाम |
|---|
| 0° | upright |
| 1–20° | slightly tilted |
| 21–55° | diagonal |
| 56–75° | steeply angled |
| 76–105° | sideways |
fill विशेषता से, COLOR_MAP के माध्यम से मैप किया गयाstyle="opacity:X" सेtransform="... rotate(X)" सेtransform="translate(X,Y) ..." से| ~21:15 | generateToken कॉल किया गया — WKX-9245FA70-200 |
| घटक | तकनीक |
|---|
| चैलेंज प्लेटफ़ॉर्म | Base44 (लो-कोड ऐप बिल्डर) |
| फ्रंटेंड | React SPA (एकल JS बंडल, ~410KB) |
| बैकेंड | Cloudflare के पीछे Python/uvicorn |
| CDN/प्रॉक्सी | Cloudflare (HTTP/3, Brotli कंप्रेशन) |
| प्रमाणीकरण | JWT (HS256), localStorage में संग्रहीत |
| डेटा प्रारूप | SVG (base64 इनलाइन), JSON API |
| रीयल-टाइम | लाइव सत्र अपडेट के लिए WebSocket (socket.io) |
| सॉल्वर | Python 3 (regex पार्सिंग, कोई बाहरी लाइब्रेरी नहीं) |
Zfill-rule="evenodd" के साथ दो संकेंद्रित आर्क पाथ