Protection Map: एक build ने क्या protect किया

HTML report जो दिखाती है कि AfterPack ने आपके code के साथ क्या किया: हर token इस आधार पर रंगा हुआ कि उस पर कितना transformation हुआ।

Protection Map वह तरीका है जिससे आप अपनी protection की पुष्टि करते हैं: आपका मूल source, जिसमें हर token इस आधार पर रंगा है कि उस पर कितना transformation हुआ।

$ npx afterpack@latest dist/

आपको यह map मिलता है:

entitlements.jslight · complexity 5Open full size
entitlements.js, 54 lines, built at the light preset with a directive around the signature check. Click any token to see what was applied to it.

इसे कैसे पढ़ें

Tokens complexity score के आधार पर रंगे जाते हैं: हर token पर कितना transformation हुआ, यानी वह संख्या जिसका target complexity तय करता है। Token जितना ज़्यादा लाल, उस पर उतना ज़्यादा transformation हुआ:

रंगComplexity score
धूसरकुछ नहीं जोड़ा गया। जान-बूझकर पढ़ने योग्य छोड़ा गया code भी धूसर होता है।
हरा4 से कम
पीला4 से 7
लाल7 से 10
गहरा लाल10 से ज़्यादा

रंग दिखाता है कि कितना लागू हुआ। कोई token चुनें, और inspector दिखाता है कि उसका region किन चरणों से गुज़रा: लागू किए गए transforms, वे region के कितने हिस्से को cover करते हैं, और वहाँ का कोई code पढ़ने योग्य क्यों रहा। पुराने engine से बने map में per-token scores नहीं होते, और वह सारा protected code एक ही रंग में दिखाता है। Engine ने जो declaration दोबारा लिखा, जैसे var से let या function से arrow, वह "Also rewritten" line पर दर्ज होता है। कोई formatter इन बदलावों को वापस पलट देता है, इसलिए ये न कोई complexity जोड़ते हैं, न कोई रंग।

किसी token को छूने वाला सबसे मज़बूत transform उसका reversal-class label तय करता है, जो उसके transforms के बगल में दिखता है। ये static-attacker classes हैं: ये बताती हैं कि bytes पढ़ने वाले के सामने क्या है। चार labels:

LabelReversal classइसका मतलब
Preservedकोई नहींअछूता: third-party imports, public exports, जो भी exclude किया गया या skip से mark किया गया। पढ़ने योग्य छोड़ा गया ताकि callers अब भी resolve हो सकें।
Renamed & encodedpolynomial-injectiveIdentifiers rename किए गए, strings encode की गईं, control flow flatten किया गया, identities fuse की गईं। संरचना असली मेहनत से recover की जा सकती है; AI explainers और आम deobfuscators को मात देता है।
Flattened & fusedpolynomial-non-injectiveLogic को ऐसे फिर से लिखा गया कि कई अलग मूल programs एक ही output पर सिमट जाते हैं, और attacker एक equivalent computation recover करता है, आपका नहीं। आज कोई shipped transform इस class तक नहीं पहुँचता।
Destroyed & fuseddestructive fusionपूरे bundle में decompose और fuse किया गया। Static reader एक equivalent program recover करता है, यह नहीं कि आपने मूल रूप से कौन-सा लिखा था। उपलब्ध नहीं; नीचे देखें।

किसी token पर hover करें तो उस पर लागू transforms दिखते हैं, category के अनुसार grouped (उदाहरण के लिए control-flow flattening), और साथ में वह class जिसमें वह आता है। लाइव demo में आज़माएँ।

रंग के पीछे की संख्या complexity score है। जिस region पर आपकी अपेक्षा से कम transformation हुआ, उसी का preset बढ़ाएँ या उसे preset=hard से mark करें।

रंग कोई security गारंटी नहीं है

Protected region static read का प्रतिरोध करता है: grep, AST tooling, बिना संदर्भ वाला LLM। चलता हुआ code जिस value का उपयोग करता है, वह उस attacker को अब भी दिख सकती है जो उसे instrumented runtime में चलाता है। वाक़ई उच्च-मूल्य वाले secrets को server-side रखें। Map दिखाता है कि static reader के सामने क्या है, इससे ज़्यादा कुछ नहीं।

उच्च-मूल्य वाले code को mark करें

Map वहाँ ज़्यादा transformation दिखाता है जहाँ आप उसे माँगते हैं। दो directive रूप लगभग हर स्थिति कवर करते हैं। Inline marker अपनी पंक्ति के बाकी हिस्से में मौजूद literal या expression पर लागू होता है। अपनी पंक्ति पर अकेला block marker एक region खोलता है जिसे मेल खाने वाला /* @afterpack end */ बंद करता है; बीच का सब कुछ कवर होता है, पूरे function bodies भी।

// A single literal — API keys, license secrets, sensitive constants:
const SECRET = /* @afterpack preset=extreme */ "EXPECTED_LICENSE_SECRET";

// A whole function — validators, anti-cheat, payment flow.
// The opener is alone on its line; the matching end closes the block:
/* @afterpack preset=hard */
export function checkLicense(token: string): LicenseClaims | null {
  // ...everything in here is at complexity target 12...
}
/* @afterpack end */

// A span of several statements:
/* @afterpack preset=extreme */
const claims = JSON.parse(atob(payload));
if (claims.secret !== SECRET) return null;
/* @afterpack end */

अगर आपके mark किए region में आसपास के code से ज़्यादा transformation नहीं दिखता, तो directive का असर नहीं हुआ। आमतौर पर किसी compiler ने AfterPack के देखने से पहले comment हटा दिया। AfterPack इसे report करता है। पूरी directive grammar Directives में है; ऊपर इस्तेमाल हुए markers preset=hard और preset=extreme हैं।

Free बनाम Pro

Free डिफ़ॉल्ट light preset पर पहले से ही rename और encode करता है, और medium और ऊपर यह एक फ़ाइल के भीतर control flow को flatten और identities को fuse भी करता है। यह सब polynomial-injective class में ही रहता है: एक static reader असली मेहनत से आपकी मूल संरचना recover कर लेता है, और यह मेहनत हर build पर दोबारा करनी पड़ती है।

Pro सटीक per-region targeting जोड़ता है, जिससे आप ठीक उन दर्जन भर functions को रंग सकते हैं जहाँ ग़लती महँगी पड़ती है, और साथ में दो hardening transforms (selfIntegrity, comparisonHardening)। Free किसी असली codebase के बड़े हिस्से को अच्छी तरह कवर करता है; license checks और secrets के आसपास आप Pro का सहारा लेते हैं। दोनों की तुलना Tiers में देखें।

flattened & fused और destroyed & fused classes आज किसी shipped transform से नहीं बनतीं। देखें Reversal classes।

अपना बनाएँ

$ npx afterpack@latest dist/

आपको वही interactive view आपके अपने source पर render होकर मिलता है: एक static HTML फ़ाइल, बिना login या telemetry के, जिसे आप PR में attach कर सकते हैं। Map आपका मूल source render करता है, इसलिए default रूप से यह केवल तब लिखा जाता है जब आपकी build ने engine के जोड़ने के लिए source map emit किया हो, और CI (CI=true या CI=1) में नहीं लिखा जाता। बाकी स्थितियों में यह opt-in है: अपने plugin options में protectionMap: { enabled: true } दें और plugin आपके लिए bundler का map चालू कर देता है। इसे छोड़ने के लिए --protectionMap.enabled=false दें। इसे अपनी build directory पर चलाएँ: Next.js .next/ में लिखता है, Nuxt .output/ में, ज़्यादातर bundlers dist/ में।

आपका map कहाँ रहता है

Local (Free) build map को आपकी machine पर .afterpack/protectionMap.html में लिखती है और कहीं कुछ नहीं भेजता। उस directory की अपनी .gitignore होती है, इसलिए git उसे ignore करता है। CLI map को किसी serve होने वाले path में लिखने से इनकार करता है। प्रकाशित Protection Map में आपका पूरा source होता है। इसे कभी publish न करें।

Pro cloud build कोई local file नहीं लिखती। AfterPack उसका map dashboard में store करता है, और जब protectionMap.enabled चालू हो, तो build पूरी होने पर उस map का link print करती है। Map उसी cloud engine द्वारा बनाया जाता है जिसने obfuscation किया, जो अकेला engine है जो आपके preset=hard, preset=extreme और skip directives का पालन करता है, इसलिए यही अकेला map है जो उनका असर दिखा सकता है।

Store किए गए map में आपका मूल source होता है

Protection Map आपका code है, रंगा हुआ। Pro cloud build पर यह AfterPack के infrastructure पर store होता है और project के मालिक workspace का हर member इसे पढ़ सकता है। अगर आपका source पूरे workspace में पढ़ने योग्य नहीं होना चाहिए, तो इसे बंद करें। नीचे देखें।

ठीक-ठीक क्या store होता है:

  • हर build का map data: आपका मूल source और रंगों के पीछे के per-token metrics, Cloudflare R2 में, AES-256 से at rest encrypted, साथ में summary संख्याओं (coverage, inflation, weak-spot counts) की एक row जिसे dashboard chart करता है। आपका obfuscated output store नहीं होता।
  • एक project तक सीमित, वही जिससे build की key जुड़ी है।
  • केवल उस workspace के members पढ़ सकते हैं। Public नहीं, indexed नहीं, कोई share करने योग्य link नहीं।
  • एक साल तक, और हर project की आख़िरी 500 builds तक रखा जाता है, जो भी पहले ख़त्म हो। एक hourly job दोनों में से किसी भी सीमा से आगे की हर चीज़ हटा देता है। एक साल की अवधि किसी release की तुलना उससे पिछली release से करने के लिए है। 500-build की सीमा दिन में कई बार build करने वाले project को source की एक साल की copies जमा करने से रोकती है; ऐसे project के लिए यही सीमा पहले लागू होती है।
  • जो build map store नहीं कर सकी, वह उसकी जगह एक note छोड़ती है, जिसमें कारण और संबंधित sizes दर्ज होते हैं, कभी आपका code नहीं और कभी कोई फ़ाइल का नाम नहीं। यह भी उसी schedule पर रखा और हटाया जाता है, और dashboard उस build को सहेजा नहीं गया के रूप में दिखाता है, न कि ऐसी build के रूप में जो कभी चली ही नहीं।
  • उस अवधि के बाद, dashboard यही बताता है। Notes और maps साथ-साथ पुराने होकर हटते हैं; आपकी build history नहीं। ऊपर की retention से पुरानी build कोई रिकॉर्ड नहीं के रूप में दिखती है।

इसे बंद करना

Maps store करना डिफ़ॉल्ट रूप से चालू है, हर project के लिए। Workspace admin इसे project की settings में बंद कर सकता है। उसके बाद उस project की नई cloud builds कुछ भी generate या store नहीं करतीं; पहले से store किए maps तुरंत ग़ायब होने के बजाय ऊपर की retention के अनुसार हटते हैं। Free builds पर दोनों ही स्थितियों में कोई असर नहीं पड़ता: उनका map local रूप से लिखा जाता है और कभी network को नहीं छूता।

आपके dashboard charts काम करते रहते हैं। इसे बंद करने से आपके source को रखना बंद होता है। इससे यह दर्ज होना बंद नहीं होता कि build ने क्या मापा। Coverage, inflation, complexity और build time में कोई code नहीं होता, और capture बंद होने वाले project के लिए भी ये दर्ज और chart होते रहते हैं। Weak-spot count अकेला अपवाद है, क्योंकि उसकी गिनती store किए map के अंदर होती है। Obfuscated output नहीं बदलता।

Store किया गया map ही अकेली चीज़ है जिसे AfterPack at rest रखता है और जिसमें आपका source होता है। Cloud build की बाकी हर चीज़ एक request की अवधि तक memory में रहती है। देखें Privacy & data handling।

आगे

  • Reversal classes: इन labels के पीछे की तीन classes, हर transform के हिसाब से।
  • Best practices: सही regions mark करने के patterns।
  • Configuration: directive grammar, per-file नियम, presets।
  • AfterPack कैसे काम करता है: तीनों reversal classes विस्तार से।
  • Threat model: static बनाम dynamic का वह आयाम जिसे ये labels मानकर चलते हैं।
  • Privacy & data handling: cloud build क्या store करती है, कितने समय तक, और उसे कौन पढ़ सकता है।
  • Directives: हर marker जिसे आप किसी region के आगे लगा सकते हैं।
  • Pro: per-region marking और stored maps किससे unlock होते हैं।
  • लाइव demo: वही view, sample source पर, बिना कुछ install किए।