談談我是如何獲得知乎的前端源碼的

文章首發於我的個人項目SunHuawei/SourceDetector

緣起

此前我在回答這個問題的時候提到,「我偶然間獲得了知乎的前端源碼」。本文將解釋我是如何「偶然獲取」的。另外,文末提供工具。

Source Map

前端工程化的一個重要部分就是就是源碼轉換,一方面壓縮體積,另一方面合併文件。當然還有可能是為了轉換Typescript、ES6+或其他代碼。但通常轉換完的代碼難以閱讀和調試。Source Map就是為了解決這個問題而出現的。

關於Source Map的詳細信息,推薦阮一峰的這篇文章-JavaScript Source Map 詳解。

故事

話說,某天我在逛知乎的時候習慣性的打開了Chrome Dev-tools,在Sources欄下竟然發現了一個webpack://目錄。用過webpack source map的前端應該立刻就會反應過來-哇,有源碼!於是我便如此「偶然獲得」了文件zfeedback.js.map。

故事還沒完。

事實上,我此時是可以直接查看各個源碼文件的。只是如何將其保存到本地呢?我嘗試點擊右鍵,貌似並沒有保存整個目錄到本地的選項,看起來只能一個一個文件的保存,好累。

受好奇心驅使,我在github上搜了一圈,找到了一個開源項目-mozilla/source-map。於是自己手動寫了些代碼便將整個目錄下載到了本地。啊哈~

源碼如下,可用node app.js執行。

// app.jsconst fs = require(fs-extra)const https = require(https)const crypto = require(crypto)const SourceMapConsumer = require(source-map).SourceMapConsumerconst analyse = (srcMapURL) => { const BASE_CACHE_PATH = __dirname + /cache/ const BASE_OUTPUT_PATH = __dirname + /output/ + srcMapURL.substr(srcMapURL.lastIndexOf(/) + 1) + / const BASE_OUTPUT_LIB_PATH = BASE_OUTPUT_PATH + node_modules/ const md5 = (content) => { let md5Maker = crypto.createHash(md5); md5Maker.update(content); return md5Maker.digest(hex); } const download = (url, callback) => { const hash = md5(url) const cacheFileName = BASE_CACHE_PATH + hash if (fs.existsSync(cacheFileName)) { fs.readFile(cacheFileName, utf8, (err, data) => { console.log("From cache") callback(data) }) } else { return https.get(url, function(response) { let body = ; let totalSize = parseInt(response.headers[content-length]) response.on(data, function(d) { body += d printDownloading(body, totalSize) }); response.on(end, function() { printFinishDownload(body) fs.outputFile(cacheFileName, body, error => { callback(body) }) }); }); } } const printDownloading = (body, totalSize) => { let statusLine =
statusLine += Downloading statusLine += srcMapURL.substr(srcMapURL.lastIndexOf(/) + 1) statusLine += statusLine += (body.length / totalSize * 100).toFixed(2) statusLine += % process.stdout.write(statusLine) } const printFinishDownload = (body) => { let statusLine = Finish Download statusLine += srcMapURL.substr(srcMapURL.lastIndexOf(/) + 1) statusLine += total size: statusLine += body.length statusLine += bytes console.log(
+ statusLine) } download(srcMapURL, (rawSourceMap) => { try { const consumer = new SourceMapConsumer(rawSourceMap); if (consumer.hasContentsOfAllSources()) { consumer.sources.forEach(fileName => { if (fileName.indexOf(webpack://) !== 0) { return } let fileContent = consumer.sourceContentFor(fileName) fileName = fileName.replace(/^webpack:///, ) fileName = fileName.replace(/^//, BASE_OUTPUT_PATH) fileName = fileName.replace(/^.*/~//, BASE_OUTPUT_LIB_PATH) fs.outputFile(fileName, fileContent, error => { // console.log(error) // TODO, debug code, to delete before commit }) }) console.log(Please check here for sources: , BASE_OUTPUT_PATH) } else { console.log(TODO) } } catch (e) { console.log("Failed to parse", srcMapURL) // TODO, debug code, to delete before commit } })}let jsURLs = `https://zhstatic.zhihu.com/assets/zfeedback/3.0.13/zfeedback.js`jsURLs.split(
).filter(Boolean).forEach(jsURL => { const srcMapURL = jsURL + .map analyse(srcMapURL)})

之後的故事是,我將分析源碼的過程寫到了這個回答。之後知乎某員工詢問我如何獲取的源碼,建議我與知乎開發及安全團隊取得聯繫,我解釋了該過程,然後知乎修復了問題。

事後

不過依然不過癮。這樣只能是當我有了某個.map文件時可以解析出源文件。如果能有一個工具隨時提醒我,我訪問的某個網站有源碼,並幫我下載下來就更完美了。於是便有了這個Chrome extention。

安裝

Chrome web store

安裝地址chrome.google.com/webst

源碼安裝

1. 下載安裝

  1. git clone https://github.com/SunHuawei/SourceDetector.gitcd SourceDetectornpm installbower installgulp

  2. 打開Chrome設置-擴展程序
  3. 點擊"載入已解壓的擴展程序..."
  4. 選擇path/to/source-detector/dist目錄

之後你在瀏覽任何網頁時,該插件將自動檢測是否有.map文件。其會自動按網站分組顯示源碼文件,並可點擊下載全部或部分源碼文件。

進入webpack首頁,查看右上角的小圖標吧~

有問題?有建議?

歡迎說出你的想法。歡迎issue和PR。


推薦閱讀:

黑客(安全研究員)是怎樣開始黑客生涯的,經歷怎樣的學習過程?
腳本小子自封黑客誤闖暗槍世界(上)少年的心理魔障
斯諾登主演的美國大片,你看過幾部?
選擇網路安全還是選擇頹廢?
一個雲本地文件包含漏洞,影響世界一流公司

TAG:前端开发 | 网络安全 | 知乎 |