[{"data":1,"prerenderedAt":30},["ShallowReactive",2],{"case-why-we-built-devpeek-en":3,"blog-list-en":13},{"slug":4,"title":5,"summary":6,"date":7,"featured":8,"seoDescription":9,"series":10,"seriesOrder":11,"html":12},"why-we-built-devpeek","Why We Built DevPeek (1): HTTPS Decrypted, Body Still Gibberish","The night before a release, TLS was already open—but changing one request field still meant digging up encrypt\u002Fdecrypt scripts. That pushed us toward a proxy tool with business-layer crypto built in—and DevPeek started there.","2026-07-09",true,"DevPeek origin series, part 1: the manual request-body encrypt\u002Fdecrypt grind—and why we set out to build a proxy tool that owns business-layer crypto.","origin",1,"\u003Ch2>9:40 PM, pinged in the group again\u003C\u002Fh2>\n\u003Cp>Night before a release. QA dropped a line:\u003C\u002Fp>\n\u003Cblockquote>\n\u003Cp>“Staging login is broken—production users are reporting it too.”\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Cp>Not a scheduled joint-debug session. People were already chasing updates in the thread.\u003C\u002Fp>\n\u003Cp>Proxy on, HTTPS decrypting fine. That \u003Ccode>POST \u002Fapi\u002Fuser\u002Flogin\u003C\u002Fcode> showed \u003Cstrong>200\u003C\u002Fstrong>—the path looked healthy. I opened the request body anyway:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-json\">{\n  &quot;payload&quot;: &quot;U2FsdGVkX1+8K3v… (long string continues)&quot;,\n  &quot;sign&quot;: &quot;a8f3c2…&quot;\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>TLS was fine. \u003Ccode>payload\u003C\u002Fcode> was still a Base64 blob. We had been shipping this style of API for years: gateway-wrapped body, AES on the fields, a sign on the side. Normal on a slow day. That night was not slow.\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"\u002Fdocs\u002Ffigures\u002Fproxy_requestlist.png\" alt=\"DevPeek HTTPS capture list with per-client tabs\">\u003C\u002Fp>\n\u003Cp>\u003Cem>TLS is decrypted in the list—but fields like \u003Ccode>payload\u003C\u002Fcode> can still be ciphertext.\u003C\u002Fem>\u003C\u002Fp>\n\u003Ch2>Fine most days. Miserable when you are rushed.\u003C\u002Fh2>\n\u003Cp>My usual loop looked something like this:\u003C\u002Fp>\n\u003Cp>Copy the ciphertext. Open an online decrypt page—I keep three of those bookmarked. Paste, get plaintext. Backend says “try field X,” so I edit it, encrypt again, and replay in Postman or a script.\u003C\u002Fp>\n\u003Cp>Charles handles HTTPS. Business-layer crypto still lives somewhere else. When I am not in a hurry, hopping windows is annoying but survivable. When time is tight, bouncing between capture, browser, and terminal gets old fast.\u003C\u002Fp>\n\u003Ch2>That night\u003C\u002Fh2>\n\u003Cp>The \u003Ccode>payload\u003C\u002Fcode> in the request was still ciphertext. I could not tell where login was failing. I dropped a screenshot in the backend channel: “Can you help read the body plaintext?”\u003C\u002Fp>\n\u003Cp>Message sent. Reply not in yet. The decrypt script in my terminal was already running—done this so many times it is basically reflex.\u003C\u002Fp>\n\u003Cp>Then the reply:\u003C\u002Fp>\n\u003Cblockquote>\n\u003Cp>“Staging uses key set B. Do not decrypt with production keys.”\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Cp>The API itself was fine. Time went to matching keys and environment first. Until the plaintext lines up, there is nothing useful to debug.\u003C\u002Fp>\n\u003Cp>Then a small ask: “Change \u003Ccode>userId\u003C\u002Fcode> in the request to 0 and run login again—see if auth is misjudging.”\u003C\u002Fp>\n\u003Cp>That means touching the login request the app actually sends. Same encrypted body. Same grind: decrypt, edit the field, encrypt again, let the app emit something the server will accept.\u003C\u002Fp>\n\u003Cp>I tried Breakpoints in Charles to edit it in flight. Open the body—ciphertext. Cannot edit. Back to the Python script under \u003Ccode>scripts\u002Fdebug\u002F\u003C\u002Fcode>, untouched for three months. Postman can send a version, but headers, cookies, and signing order never quite match the real app path, so you never fully trust the result.\u003C\u002Fp>\n\u003Cp>QA kept asking: “So can we log in on staging?”\u003C\u002Fp>\n\u003Cp>I burned nearly an hour in that manual loop. Looking back, they wanted to check one or two fields.\u003C\u002Fp>\n\u003Cp>Before standup, product added: “Check signup too—same encryption as login.” New URL. Copy the script. Tweak it. Same grind again.\u003C\u002Fp>\n\u003Cp>A new backend teammate asked which key each endpoint uses. The doc is in Confluence. Not something you see in the capture UI.\u003C\u002Fp>\n\u003Ch2>We were never stuck on TLS\u003C\u002Fh2>\n\u003Cp>Charles and Fiddler earn their keep stripping HTTPS. The grind sits one layer up: request bodies still ciphertext, and every edit or replay still done by hand—decrypt, change, encrypt again.\u003C\u002Fp>\n\u003Cp>Certs are fine. The endpoint returns 200. The thread is still blowing up. And somehow you still cannot skip copying ciphertext, matching staging vs production keys, or the decrypt–edit–re-encrypt–replay loop.\u003C\u002Fp>\n\u003Ch2>After that night\u003C\u002Fh2>\n\u003Cp>Before standup, my head was still on last night’s login request.\u003C\u002Fp>\n\u003Cp>The proxy already sat on the path. TLS was stripped. Business-layer crypto still lived outside the proxy—external sites, terminal scripts, Postman, each doing its own thing. Change one \u003Ccode>userId\u003C\u002Fcode>? They wanted one or two fields checked, and the whole manual loop had to run again.\u003C\u002Fp>\n\u003Cp>After grinding through that night, a blunt thought surfaced: \u003Cstrong>what if one tool owned capture and business-layer crypto together?\u003C\u002Fstrong> The proxy is already in the chain—decrypt scripts, environment keys, edit-and-replay should not mean hopping across four windows.\u003C\u002Fp>\n\u003Cp>That is roughly where DevPeek started.\u003C\u002Fp>\n\u003Cp>The first piece we wanted to pull in was the part that night would not let go of—\u003Cstrong>outbound requests\u003C\u002Fstrong>. Charles handles TLS; we would handle the layer above: read ciphertext in the proxy, edit plaintext, encrypt again on the way out—and request-only first, because that was the slowest, hardest-to-skip slice of joint debugging.\u003C\u002Fp>\n\u003Cp>That became \u003Cstrong>param transform\u003C\u002Fstrong>. It maps onto the same manual steps, except you never leave the capture UI:\u003C\u002Fp>\n\u003Cp>\u003Cstrong>Conversion config\u003C\u002Fstrong> handles how to decrypt and re-encrypt. Staging key set B vs production key set A lives next to your capture context—no more Confluence hunting. The Python under \u003Ccode>scripts\u002Fdebug\u002F\u003C\u002Fcode> can move into script conversion; common AES setups can use built-in algorithms.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>Param transform rules\u003C\u002Fstrong> decide which requests and which parameters get converted. Right-click \u003Ccode>POST \u002Fapi\u002Fuser\u002Flogin\u003C\u002Fcode>, pick URL + \u003Ccode>payload\u003C\u002Fcode>, bind the conversion config—save once, matching traffic hits it automatically.\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"\u002Fdocs\u002Ffigures\u002Fparam_transform_rule_wizard.png\" alt=\"Param transform rule wizard in DevPeek\">\u003C\u002Fp>\n\u003Cp>\u003Cem>Pick URL and encrypted fields from a captured request; bind a conversion config once.\u003C\u002Fem>\u003C\u002Fp>\n\u003Cp>Once that is in place, you mostly work in plaintext: decrypted fields show up in details; when backend says “try \u003Ccode>userId\u003C\u002Fcode> = 0,” edit in Mock tamper or the “Debug API” drawer and send—DevPeek re-encrypts on the way out while headers, cookies, and signing stay on the real app path. The Mock tamper dialog is \u003Cstrong>not limited by client tab\u003C\u002Fstrong>—whether you are on Capture or Debug, it auto-opens while items are pending, on the same proxy chain as capture and Debug tab Network. Signup? Change the URL match, reuse the config.\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"\u002Fdocs\u002Ffigures\u002Fmock_tamper_req.png\" alt=\"DevPeek Mock tamper dialog: editing the request phase\">\u003C\u002Fp>\n\u003Cp>\u003Cem>On manual Mock hit, edit plaintext in the dialog—Continue re-encrypts on the way out, no Postman hop.\u003C\u002Fem>\u003C\u002Fp>\n\u003Cp>The list still records what the client actually sent; plaintext lives in details for comparison. Postman and that three-month-old Python script can step back.\u003C\u002Fp>\n\u003Cp>An hour that night was really about one or two fields. DevPeek grew from there; param transform was the first piece to land—turning that verification into “edit the value, hit send.”\u003C\u002Fp>\n\u003Ch2>Next\u003C\u002Fh2>\n\u003Cp>\u003Cstrong>\u003Ca href=\"\u002Fen\u002Fblog\u002Fwhy-we-built-devpeek-h5-debug\u002F\">Why We Built DevPeek (2): That H5 Page in the App—Debug It on Your PC\u003C\u002Fa>\u003C\u002Fstrong>—mobile pages opened through the proxy, mirrored in the Debug tab, with our own panel for DOM, console, and network—not just squinting at the phone.\u003C\u002Fp>\n\u003Chr>\n\u003Cp>If you are still hand-rolling request bodies under pressure, \u003Ca href=\"\u002F\">try DevPeek\u003C\u002Fa> or say hi on \u003Ca href=\"https:\u002F\u002Fgithub.com\u002FGYPengDev\u002Fdevpeek\u002Fdiscussions\">GitHub Discussions\u003C\u002Fa>—param transform guide: \u003Ca href=\"\u002Fdocs\u002Fparam-transform\u002F\">docs\u003C\u002Fa>.\u003C\u002Fp>\n",{"items":14},[15,22,29],{"slug":16,"title":17,"summary":18,"date":19,"featured":8,"seoDescription":20,"series":21,"seriesOrder":11},"wechat-h5-storage-debug","H5 Debug in Practice (1): WeChat H5 Local Cache—Debug It on Desktop","After switching test accounts in a WeChat official-account H5, the avatar still showed the old user—capture had the new token, stale data stayed in localStorage. This post walks through a real joint-debug case and how to view and edit localStorage, sessionStorage, and IndexedDB in WeChat WebView from your PC.","2026-07-11","DevPeek H5 debug: locate localStorage, sessionStorage, and IndexedDB cache issues in WeChat H5—compared with vConsole and remote debug, with real WebView debugging workflow.","h5-debug",{"slug":23,"title":24,"summary":25,"date":26,"featured":8,"seoDescription":27,"series":10,"seriesOrder":28},"why-we-built-devpeek-h5-debug","Why We Built DevPeek (2): That H5 Page in the App—Debug It on Your PC","Param transform fixed login, but the activity H5 only broke inside the App WebView. Remote debug and capture lived in different windows—so we folded mirroring and our own debug panels into DevPeek.","2026-07-10","DevPeek origin series, part 2: in-app H5 bugs that only show on real devices, the split between remote debug and capture, and how the Debug tab mirrors pages with built-in DOM, Console, and Network panels.",2,{"slug":4,"title":5,"summary":6,"date":7,"featured":8,"seoDescription":9,"series":10,"seriesOrder":11},1783734905162]