-
Notifications
You must be signed in to change notification settings - Fork 0
/
local-search.xml
183 lines (87 loc) · 166 KB
/
local-search.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>JetBrains 2024.2.4 激活教程及许可证服务器</title>
<link href="/2024/10/22/jetbrains-202423/"/>
<url>/2024/10/22/jetbrains-202423/</url>
<content type="html"><![CDATA[<p>JetBrains 系最新版本号已经到了 2024.2.4,之前版本的激活方案经测试,在一些小调整后依然可用。本文将介绍使用来自 <code>热心大佬</code> 的方案,激活最新版 Idea 等 JetBrains 产品的方法。同时提供一个激活服务器地址,供各位用于激活未被 <code>热心大佬</code> 覆盖的插件。</p><h2 id="成果展示"><a href="#成果展示" class="headerlink" title="成果展示"></a>成果展示</h2><div class="group-image-container"><div class="group-image-row"><div class="group-image-wrap"><img src="/../img/image-27.png" alt="PyCharm 2024.2.4"></div><div class="group-image-wrap"><img src="/../img/image-28.png" alt="WebStorm 2024.2.4"></div><div class="group-image-wrap"><img src="/../img/image-30.png" alt="IDEA 2024.2.4"></div></div></div><h2 id="1-下载破解补丁"><a href="#1-下载破解补丁" class="headerlink" title="1. 下载破解补丁"></a>1. 下载破解补丁</h2><p>激活过 2021.3 以后版本的朋友们应该的都熟悉,<code>热心大佬</code> 基于 <code>ja-netfilter</code> 制作的 <code>jetbra</code> 系列补丁。</p><p>这里提供下载地址:<a href="https://3.jetbra.in/">jetbra.in/s</a></p><p><img src="/../img/image-20.png" alt="IPFS Checker"></p><p>打开后会发现是一个 IPFS Checker 页面,我们在这个页面中选择一个可用的链接打开。</p><p><img src="/../img/image-21.png" alt="打开后的页面截图"></p><p>接下来,点击页面中的 <code>jetbra.zip</code> 链接,就可以下载我们所需要的补丁了。</p><h2 id="2-安装补丁"><a href="#2-安装补丁" class="headerlink" title="2. 安装补丁"></a>2. 安装补丁</h2><p>我们将 <code>jetbra.zip</code> 解压,然后打开 <code>scripts</code> 文件夹。</p><p><img src="/../img/image-22.png" alt="scripts 文件夹的内容"></p><p>这里的脚本有两种格式,<code>.vbs</code> 是为 Windows 系统准备的,<code>.sh</code> 是为其它系统准备的。你需要根据自己的需求来选择脚本运行。</p><p>如果你曾经安装过 <code>jetbra</code> 系列的旧版补丁,需要先运行 <code>uninstall</code> 开头的脚本。</p><p>接下来运行 <code>install</code> 开头的脚本,等待脚本运行完毕。</p><h2 id="3-配置补丁"><a href="#3-配置补丁" class="headerlink" title="3. 配置补丁"></a>3. 配置补丁</h2><p><code>ja-netfilter</code> 作者 <code>zhile</code> 提到<sup id="fnref:1" class="footnote-ref"><a href="#fn:1" rel="footnote"><span class="hint--top hint--rounded" aria-label="[JetBrains 新版本区域选择的坑](https://zhile.io/2024/09/05/jetbrains-2024-2-region.html)">[1]</span></a></sup>,新版 IDEA 为中国用户提供了专门的激活验证 API,因此我们也需要编辑对应的配置文件。</p><p>打开 <code>config-jetbrains/url.conf</code> 将内容改为:</p><figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs properties"><span class="hljs-attr">[URL]</span><br><span class="hljs-attr">PREFIX,https</span>:<span class="hljs-string">//account.jetbrains.com/lservice/rpc/validateKey.action</span><br><span class="hljs-attr">PREFIX,https</span>:<span class="hljs-string">//account.jetbrains.com.cn/lservice/rpc/validateKey.action</span><br></code></pre></td></tr></table></figure><p>同时,为了使用我提供的 JetBrains 激活服务器,还需要往 <code>config-jetbrains/power.conf</code> 的末尾添加这部分内容<sup id="fnref:2" class="footnote-ref"><a href="#fn:2" rel="footnote"><span class="hint--top hint--rounded" aria-label="内容来自 [ls.cxzlw.top](https://ls.cxzlw.top/)">[2]</span></a></sup>:</p><figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs properties"><span class="hljs-attr">[Result]</span><br><span class="hljs-attr">EQUAL,74536916935363972062676331234002795978371230636948551293621603151387012525605238437362717321374972744690556736705557452149497519412804345058881400041852152248781442398374098163466582715348121104283019915357094974189947691509248438017494612608877160854463801122408857053592284470003281993552170605889419992023038705192597311510734863341903647703840007318628804558346434827311733144529418566623714199565588181031770613580525237008189903834789078942762034416431160148672791037765767368214813401636365028031639884426126794115842679594980801784389705440469656481098442162146617906382071405164670982777208337204167914289682210535178020557113389359669265657696820776268705339574059938433729991223525911877835862344873763935678384081801004675023491836914378934761006350990456252681113253539880421773642536732092668061722476554573853994961057716516778138273777611940148330085010779542126866978669332562741093267867904170579076109624842072438223356166761104920950156877337904038406782440652886116687382019792158998260619254628867563400170565325011114569375987962380383313040551218643401540538478025122865871047085995035070082930349263334429199533531776938034249083427463322471533034172592961264436973331709502459982433402944574109570528373174,65537,860106576952879101192782278876319243486072481962999610484027161162448933268423045647258145695082284265933019120714643752088997312766689988016808929265129401027490891810902278465065056686129972085119605237470899952751915070244375173428976413406363879128531449407795115913715863867259163957682164040613505040314747660800424242248055421184038777878268502955477482203711835548014501087778959157112423823275878824729132393281517778742463067583320091009916141454657614089600126948087954465055321987012989937065785013284988096504657892738536613208311013047138019418152103262155848541574327484510025594166239784429845180875774012229784878903603491426732347994359380330103328705981064044872334790365894924494923595382470094461546336020961505275530597716457288511366082299255537762891238136381924520749228412559219346777184174219999640906007205260040707839706131662149325151230558316068068139406816080119906833578907759960298749494098180107991752250725928647349597506532778539709852254478061194098069801549845163358315116260915270480057699929968468068015735162890213859113563672040630687357054902747438421559817252127187138838514773245413540030800888215961904267348727206110582505606182944023582459006406137831940959195566364811905585377246353->31872219281407242025505148642475109331663948030010491344733687844358944945421064967310388547820970408352359213697487269225694990179009814674781374751323403257628081559561462351695605167675284372388551941279783515209238245831229026662363729380633136520288327292047232179909791526492877475417113579821717193807584807644097527647305469671333646868883650312280989663788656507661713409911267085806708237966730821529702498972114194166091819277582149433578383639532136271637219758962252614390071122773223025154710411681628917523557526099053858210363406122853294409830276270946292893988830514538950951686480580886602618927728470029090747400687617046511462665469446846624685614084264191213318074804549715573780408305977947238915527798680393538207482620648181504876534152430149355791756374642327623133843473947861771150672096834149014464956451480803326284417202116346454345929350148770746553056995922154382822307758515805142704373984019252210715650875853634697920708113806880196144197384637328982263167395073688501517286678083973976140696077590122053014085412828620051470085033364773099146103525313018873319293728800442101520384088109603555959893639842091339193916540786143451419950529324231092499266627290477930743308390718116223399064582</span><br><br><span class="hljs-attr">[Result]</span><br><span class="hljs-attr">EQUAL,112461441133519625377278033563377631217080810478044877913003583914648172091738157409921673196502504071932645557170019171979298595709352327802847769722044120499790085741936811108997304158745808767971516913718441191016834227872457230739137340571843164308934558717824577201912443223840644755180769504480393502755952629208233773261062450820065565988008725574313918475968373409242870402643190145552028259314958400337631849159185897138438439875424694124532866781262807038969447273824052492355210186488558693635452115878033675172769234889468457042725838181642541179089465010395802783763203718057315817018322305785075539591970216432243340366977824031569736525928733562828693571820672870610008956717834537299752992483571693698336452716670330967743846098030643538528204645931348565692824365943332663794928836727209414094750075716270817426458443599603160413128062421268628025660472739936815953924643652002565769233074966511472269518005528501545942584021818210587632705524697103775085784867648393186553267468729363798569623027883383917245256650355761359899139236166747130889213713310080522785602644742450625402390645549510027475808490196633734411293566393252889909125865355795314165239971352734320255879462427769889324003845415924485271874702773,65537,657823416415964932845156435107145357714205418747915356734397055242964933221752404166614935255105249101653916721681603662754307632457128805443068644284748929421507178622933348669378235847742899773920765918770105482851534467296284105250512573151705220224379509383835022323282176179690146311979451556541118129344282127375534752754929526193258755897888515754328964698687671896985405008425332766082319260988023654359845072776189451448786758245414253386146246727354454047135428416624852422567360097346671648093064429279847823280592246506886401865455491924420415707803245018138595108029359998829520236522620749918729938206134739331246902031807601266419258080411903201595710155467901291142142443220333539750397923736434950558371997170985472272249812750161962720036837656464089126216749585148030883029438285184930024286517865710539947589764564204842426698322404033441531662829238875205420761652375337327297032255730262635511533223504109798364923988127319356119135982652788834405038113746394301957551167740345788175766290794604666781402329824924118191746319728033878045396093674696713022814027690165596773992550010915823534552020920573926469894452526033833249442230929742486602298477270672101197444729222659891038350303699501280729658274069437->31872219281407242025505148642475109331663948030010491344733687844358944945421064967310388547820970408352359213697487269225694990179009814674781374751323403257628081559561462351695605167675284372388551941279783515209238245831229026662363729380633136520288327292047232179909791526492877475417113579821717193807584807644097527647305469671333646868883650312280989663788656507661713409911267085806708237966730821529702498972114194166091819277582149433578383639532136271637219758962252614390071122773223025154710411681628917523557526099053858210363406122853294409830276270946292893988830514538950951686480580886602618927728470029090747400687617046511462665469446846624685614084264191213318074804549715573780408305977947238915527798680393538207482620648181504876534152430149355791756374642327623133843473947861771150672096834149014464956451480803326284417202116346454345929350148770746553056995922154382822307758515805142704373984019252210715650875853634697920708113806880196144197384637328982263167395073688501517286678083973976140696077590122053014085412828620051470085033364773099146103525313018873319293728800442101520384088109603555959893639842091339193869176761112940712068557597508317971649031214973881730692211411295733498836914</span><br></code></pre></td></tr></table></figure><p>保存配置后,重启正在运行的 IDE,补丁就彻底配置好了。你可以在下面两种激活方式中选择一个,进行 JetBrains IDE 的激活。</p><h2 id="4-使用激活码激活-IDEA"><a href="#4-使用激活码激活-IDEA" class="headerlink" title="4. 使用激活码激活 IDEA"></a>4. 使用激活码激活 IDEA</h2><p>激活码的好处是离线使用,不需要联网验证。你可以在刚才 <code>热心大佬</code> 的网站 <a href="https://3.jetbra.in/">jetbra.in/s</a> 上获取激活码。</p><div class="group-image-container"><div class="group-image-row"><div class="group-image-wrap"><img src="/../img/image-24.png" alt="贴入激活码"></div><div class="group-image-wrap"><img src="/../img/image-23.png" alt="激活成功"></div></div></div><figcaption aria-hidden="true" class="image-caption">左:贴入激活码 右:激活成功</figcaption><p>注意到,部分插件 <code>热心大佬</code> 没有提供激活码,而且授权给的用户名是固定的。如果你想要使用自己电脑的用户名,亦或者是使用没有激活码的插件,可以使用下面的激活服务器。</p><h2 id="5-使用许可证服务器激活-IDEA"><a href="#5-使用许可证服务器激活-IDEA" class="headerlink" title="5. 使用许可证服务器激活 IDEA"></a>5. 使用许可证服务器激活 IDEA</h2><p>在激活时选择 <code>许可证服务器</code>,并填入下面的地址:</p><figure class="highlight dts"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs dts"><span class="hljs-symbol">https:</span><span class="hljs-comment">//ls.cxzlw.top/</span><br></code></pre></td></tr></table></figure><div class="group-image-container"><div class="group-image-row"><div class="group-image-wrap"><img src="/../img/image-25.png" alt="贴入许可证服务器地址"></div><div class="group-image-wrap"><img src="/../img/image-26.png" alt="激活成功"></div></div></div><figcaption aria-hidden="true" class="image-caption">左:贴入许可证服务器地址 右:激活成功</figcaption><p>可以看到激活成功,并且使用了我们自己电脑的用户名。</p><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ol><li><a href="https://zhile.io/2021/11/29/ja-netfilter-javaagent-lib.html">介绍一个“牛逼闪闪”开源库:ja-netfilter</a></li></ol><h2 id="注"><a href="#注" class="headerlink" title="注"></a>注</h2><section class="footnotes"><div class="footnote-list"><ol><li><span id="fn:1" class="footnote-text"><span><a href="https://zhile.io/2024/09/05/jetbrains-2024-2-region.html">JetBrains 新版本区域选择的坑</a><a href="#fnref:1" rev="footnote" class="footnote-backref"> ↩</a></span></span></li><li><span id="fn:2" class="footnote-text"><span>内容来自 <a href="https://ls.cxzlw.top/">ls.cxzlw.top</a><a href="#fnref:2" rev="footnote" class="footnote-backref"> ↩</a></span></span></li></ol></div></section>]]></content>
</entry>
<entry>
<title>RSAisEasy Writeup</title>
<link href="/2024/09/06/htb-rsaiseasy/"/>
<url>/2024/09/06/htb-rsaiseasy/</url>
<content type="html"><![CDATA[<blockquote><p>原题地址:<a href="https://app.hackthebox.com/challenges/RSAisEasy">HackTheBox - RSAisEasy</a></p></blockquote><p>之前做过这个题,是与另一位朋友一起分析的,但是当时没有写 writeup,于是再梳理一遍。</p><p>从标题可以看出,这道题与 RSA 有点相关,因此会用到一部分基于 RSA 公式的数学分析。(说实话,在拉着咱朋友一起来分析数学部分之前,是有那么一点不敢做这题的……)</p><h2 id="0-题目内容"><a href="#0-题目内容" class="headerlink" title="0. 题目内容"></a>0. 题目内容</h2><p>题目提供了一个 <code>zip</code> 文件,解压后有两个文件</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs plaintext"># output.txt<br><br>n1: 101302608234750530215072272904674037076286246679691423280860345380727387460347553585319149306846617895151397345134725469568034944362725840889803514170441153452816738520513986621545456486260186057658467757935510362350710672577390455772286945685838373154626020209228183673388592030449624410459900543470481715269<br>c1: 92506893588979548794790672542461288412902813248116064711808481112865246689691740816363092933206841082369015763989265012104504500670878633324061404374817814507356553697459987468562146726510492528932139036063681327547916073034377647100888763559498314765496171327071015998871821569774481702484239056959316014064<br>c2: 46096854429474193473315622000700040188659289972305530955007054362815555622172000229584906225161285873027049199121215251038480738839915061587734141659589689176363962259066462128434796823277974789556411556028716349578708536050061871052948425521408788256153194537438422533790942307426802114531079426322801866673<br>(n1 * E) + n2: 601613204734044874510382122719388369424704454445440856955212747733856646787417730534645761871794607755794569926160226856377491672497901427125762773794612714954548970049734347216746397532291215057264241745928752782099454036635249993278807842576939476615587990343335792606509594080976599605315657632227121700808996847129758656266941422227113386647519604149159248887809688029519252391934671647670787874483702292498358573950359909165677642135389614863992438265717898239252246163<br></code></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-comment"># RSAisEasy.py</span><br><br><span class="hljs-comment">#!/usr/bin/env python3</span><br><span class="hljs-keyword">from</span> Crypto.Util.number <span class="hljs-keyword">import</span> bytes_to_long, getPrime<br><span class="hljs-keyword">from</span> secrets <span class="hljs-keyword">import</span> flag1, flag2<br><span class="hljs-keyword">from</span> os <span class="hljs-keyword">import</span> urandom<br><br>flag1 = bytes_to_long(flag1)<br>flag2 = bytes_to_long(flag2)<br><br>p, q, z = [getPrime(<span class="hljs-number">512</span>) <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">3</span>)]<br><br>e = <span class="hljs-number">0x10001</span><br><br>n1 = p * q<br>n2 = q * z<br><br>c1 = <span class="hljs-built_in">pow</span>(flag1, e, n1)<br>c2 = <span class="hljs-built_in">pow</span>(flag2, e, n2)<br><br>E = bytes_to_long(urandom(<span class="hljs-number">69</span>))<br><br><span class="hljs-built_in">print</span>(<span class="hljs-string">f'n1: <span class="hljs-subst">{n1}</span>'</span>)<br><span class="hljs-built_in">print</span>(<span class="hljs-string">f'c1: <span class="hljs-subst">{c1}</span>'</span>)<br><span class="hljs-built_in">print</span>(<span class="hljs-string">f'c2: <span class="hljs-subst">{c2}</span>'</span>)<br><span class="hljs-built_in">print</span>(<span class="hljs-string">f'(n1 * E) + n2: <span class="hljs-subst">{n1 * E + n2}</span>'</span>)<br></code></pre></td></tr></table></figure><h2 id="1-眼盯侦!"><a href="#1-眼盯侦!" class="headerlink" title="1. 眼盯侦!"></a>1. 眼盯侦!</h2><p>首先观察提供的代码,注意到 <code>flag1</code> 和 <code>flag2</code> 两个变量,那我们接下来的目标就是还原这两个变量了。</p><p>接下来生成了 3 个质数,分别是 <code>p</code>, <code>q</code>, <code>z</code>,<code>e</code> 使用的是老熟人 <code>0x10001</code>。</p><p>然后使用 <code>p</code>, <code>q</code>, <code>z</code> 计算了 <code>n1</code>, <code>n2</code>。使用 <code>n1</code>, <code>n2</code> 分别加密了 <code>flag1</code>, <code>flag2</code>,得到 <code>c1</code>, <code>c2</code>。</p><p>最后生成了一个随机数 <code>E</code>,并输出了 <code>n1</code>, <code>c1</code>, <code>c2</code>, <code>(n1 * E) + n2</code>。</p><h2 id="2-RSA-公式"><a href="#2-RSA-公式" class="headerlink" title="2. RSA 公式"></a>2. RSA 公式</h2><p>这部分就来自 <a href="https://zh.m.wikipedia.org/zh-cn/RSA%E5%8A%A0%E5%AF%86%E6%BC%94%E7%AE%97%E6%B3%95">RSA加密算法 - 维基百科,自由的百科全书</a> 了,当时咱也是从 Wiki 上现学的。注意这里省略了一些过程。</p><p>加密算法</p><p>$$<br>c = n^e \pmod N<br>$$</p><p>解密算法</p><p>$$<br>n = c^d \pmod N<br>$$</p><p>密钥相关的公式</p><p>$$<br>N = pq,<br>$$</p><p>$$<br>r = (p-1)(q-1)<br>$$</p><p>$$<br>ed \equiv 1 \pmod r<br>$$</p><p>从公式可以看出,要解密 <code>c1</code> 和 <code>c2</code>,需要知道 <code>d1</code>, <code>d2</code>,而 <code>d1</code>, <code>d2</code> 是由 <code>e</code>, <code>r1</code>, <code>r2</code> 计算逆元得到的。<code>e</code> 是已知的,现在要求的就是 <code>r1</code>, <code>r2</code> 了。</p><h2 id="3-r"><a href="#3-r" class="headerlink" title="3. r?"></a>3. r?</h2><p>观察代码,发现</p><p>$$<br>n1 = pq, n2 = qz<br>$$</p><p>由 $p, q, z \in \mathbb{P}$ 得</p><p>$$<br>q = \gcd(n1, n2)<br>$$</p><p>$$<br>p = \frac{n1}{q}, z = \frac{n2}{q}<br>$$</p><p>这样,拿到 <code>p</code>, <code>q</code>, <code>z</code> 后,就可以计算出 <code>r1</code>, <code>r2</code> 了。</p><h2 id="4-d"><a href="#4-d" class="headerlink" title="4. d!"></a>4. d!</h2><p>有了 <code>r1</code>, <code>r2</code> 后,就可以计算出 <code>d1</code>, <code>d2</code> 了。逆元有几种求法,这里我们选择 <a href="https://oi-wiki.org/math/number-theory/inverse/#%E6%89%A9%E5%B1%95%E6%AC%A7%E5%87%A0%E9%87%8C%E5%BE%97%E6%B3%95">扩展欧几里得算法</a>。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-comment"># 输入 a=e, b=r, 输出 x=d</span><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">exgcd</span>(<span class="hljs-params">a, b</span>):<br> <span class="hljs-keyword">if</span> b == <span class="hljs-number">0</span>:<br> x = <span class="hljs-number">1</span><br> y = <span class="hljs-number">0</span><br> <span class="hljs-keyword">return</span> x, y<br> x1, y1 = exgcd(b, a % b)<br> x = y1<br> y = x1 - (a // b) * y1<br> <span class="hljs-keyword">return</span> x, y<br></code></pre></td></tr></table></figure><h2 id="5-n2"><a href="#5-n2" class="headerlink" title="5. n2"></a>5. n2</h2><p>上面的过程需要一个值 <code>n2</code>,而 <code>n2</code> 不是题目直接给出的,我们需要想办法找出来。</p><p>注意到题目提供了 <code>E</code> 和 <code>(n1 * E) + n2</code>,我们可以通过这个值来找到 <code>n2</code>。</p><p>为方便展示过程,我们将 <code>(n1 * E) + n2</code> 记为 <code>nE</code>。</p><p>$$<br>n2 \equiv nE \pmod {n1}<br>$$</p><p>即</p><p>$$<br>\def\mod{\text{ mod }}<br>n2 = nE \mod n1 + n1 \cdot k<br>$$</p><p>其中 <code>k</code> 是未知的,你可以直接猜测 <code>k = 0</code> 即 <code>n2 = nE % n1</code>,但我还是想证明它。</p><p>注意到 <code>n2</code> 是两个 <code>getPrime(512)</code> 相乘,因此 <code>0 < k < 2^1024</code>。接下来用代码测试 <code>k</code> 可以的取值。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs python">n1 = <span class="hljs-number">101302608234750530215072272904674037076286246679691423280860345380727387460347553585319149306846617895151397345134725469568034944362725840889803514170441153452816738520513986621545456486260186057658467757935510362350710672577390455772286945685838373154626020209228183673388592030449624410459900543470481715269</span><br>ne = <span class="hljs-number">601613204734044874510382122719388369424704454445440856955212747733856646787417730534645761871794607755794569926160226856377491672497901427125762773794612714954548970049734347216746397532291215057264241745928752782099454036635249993278807842576939476615587990343335792606509594080976599605315657632227121700808996847129758656266941422227113386647519604149159248887809688029519252391934671647670787874483702292498358573950359909165677642135389614863992438265717898239252246163</span><br><br><span class="hljs-keyword">for</span> k <span class="hljs-keyword">in</span> (-<span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>): <br> n2 = ne % n1 + n1 * k<br> <span class="hljs-built_in">print</span>(k, <span class="hljs-number">0</span> < n2 < <span class="hljs-number">2</span>**<span class="hljs-number">1024</span>, n2)<br></code></pre></td></tr></table></figure><p>得到运行结果:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs plaintext">-1 False -1165705193327509223646449377936290710713049039655470307166720571005763031384300382036555332312895310759950336222328427276047951088897538178479073322538390413188948373749356597618939249379728523681999077958826657180398342840434533058980374881243302617523598758343538175613136045714345227586034384136094220432<br>0 True 100136903041423020991425823526737746365573197640035952973693624809721624428963253203282593974533722584391447008912397042291986993273828302711324440847902763039627790146764630023926517236880457533976468679976683705170312329736955922713306570804595070537102421450884645497775455984735279182873866159334387494837<br>1 False 201439511276173551206498096431411783441859444319727376254553970190449011889310806788601743281380340479542844354047122511860021937636554143601127955018343916492444528667278616645471973723140643591634936437912194067521023002314346378485593516490433443691728441660112829171164048015184903593333766702804869210106<br></code></pre></td></tr></table></figure><p>因此 <code>k = 0</code> 而 <code>n2 = nE % n1</code>。</p><h2 id="6-结束了?"><a href="#6-结束了?" class="headerlink" title="6. 结束了?"></a>6. 结束了?</h2><p>按照上述流程编写代码:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> math <span class="hljs-keyword">import</span> gcd<br><br>e = <span class="hljs-number">0x10001</span><br>n1 = <span class="hljs-number">101302608234750530215072272904674037076286246679691423280860345380727387460347553585319149306846617895151397345134725469568034944362725840889803514170441153452816738520513986621545456486260186057658467757935510362350710672577390455772286945685838373154626020209228183673388592030449624410459900543470481715269</span><br>ne = <span class="hljs-number">601613204734044874510382122719388369424704454445440856955212747733856646787417730534645761871794607755794569926160226856377491672497901427125762773794612714954548970049734347216746397532291215057264241745928752782099454036635249993278807842576939476615587990343335792606509594080976599605315657632227121700808996847129758656266941422227113386647519604149159248887809688029519252391934671647670787874483702292498358573950359909165677642135389614863992438265717898239252246163</span><br>c1 = <span class="hljs-number">92506893588979548794790672542461288412902813248116064711808481112865246689691740816363092933206841082369015763989265012104504500670878633324061404374817814507356553697459987468562146726510492528932139036063681327547916073034377647100888763559498314765496171327071015998871821569774481702484239056959316014064</span><br>c2 = <span class="hljs-number">46096854429474193473315622000700040188659289972305530955007054362815555622172000229584906225161285873027049199121215251038480738839915061587734141659589689176363962259066462128434796823277974789556411556028716349578708536050061871052948425521408788256153194537438422533790942307426802114531079426322801866673</span><br><br>n2 = ne % n1 <span class="hljs-comment"># 用前面的推导计算 n2</span><br><br>q = gcd(n1, n2) <span class="hljs-comment"># 计算 p, q, z</span><br>p, z = n1 // q, n2 // q<br><br>r1, r2 = (p - <span class="hljs-number">1</span>) * (q - <span class="hljs-number">1</span>), (q - <span class="hljs-number">1</span>) * (z - <span class="hljs-number">1</span>) <span class="hljs-comment"># 计算 r1, r2</span><br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">exgcd</span>(<span class="hljs-params">a, b</span>): <span class="hljs-comment"># 用来求逆元的扩展欧几里得算法</span><br> <span class="hljs-keyword">if</span> b == <span class="hljs-number">0</span>:<br> x = <span class="hljs-number">1</span><br> y = <span class="hljs-number">0</span><br> <span class="hljs-keyword">return</span> x, y<br> x1, y1 = exgcd(b, a % b)<br> x = y1<br> y = x1 - (a // b) * y1<br> <span class="hljs-keyword">return</span> x, y<br><br>d1, d2 = exgcd(e, r1)[<span class="hljs-number">0</span>], exgcd(e, r2)[<span class="hljs-number">0</span>]<br>d1, d2 = d1 % r1, d2 % r2 <span class="hljs-comment"># exgcd 算出来可能是负数,所以再 mod 一次</span><br><br>flag1, flag2 = <span class="hljs-built_in">pow</span>(c1, d1, n1), <span class="hljs-built_in">pow</span>(c2, d2, n2)<br><br><span class="hljs-comment"># 一个比较拙劣但是能跑的 int to bytes</span><br>flag_hex = <span class="hljs-built_in">hex</span>(flag1)[<span class="hljs-number">2</span>:] + <span class="hljs-built_in">hex</span>(flag2)[<span class="hljs-number">2</span>:]<br>flag = <span class="hljs-built_in">bytes</span>.fromhex(flag_hex).decode()<br><span class="hljs-built_in">print</span>(flag)<br></code></pre></td></tr></table></figure><p>运行上述代码,得到 flag:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs plaintext">HTB{1_m1ght_h4v3_m3ss3d_uP_jU$t_4_l1ttle_b1t?}<br></code></pre></td></tr></table></figure><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ol><li><a href="https://zh.m.wikipedia.org/zh-cn/RSA%E5%8A%A0%E5%AF%86%E6%BC%94%E7%AE%97%E6%B3%95">RSA加密算法 - 维基百科,自由的百科全书</a></li><li><a href="https://oi-wiki.org/math/number-theory/inverse/">乘法逆元 - OI Wiki</a></li></ol>]]></content>
<tags>
<tag>cxzlw</tag>
<tag>HackTheBox</tag>
<tag>Crypto</tag>
<tag>Writeup</tag>
<tag>CTF</tag>
<tag>RSA</tag>
</tags>
</entry>
<entry>
<title>JSON 基础知识</title>
<link href="/2024/07/11/json-format/"/>
<url>/2024/07/11/json-format/</url>
<content type="html"><![CDATA[<p>你是否曾经疑惑过,当我们提到 <code>JSON</code> 的时候,我们在说什么?<code>JSON</code> 以 <code>JS</code> 开头,那么其与 <code>JavaScript</code> 的联系到底是什么?在这篇文章中,我们将尽可能通俗地了解 <code>JSON</code> 的起源、格式和意义,并解答一些常见的疑惑。</p><div class="note note-warning"> <p>标准 <code>JSON</code> 格式中不可以使用任何形式的注释。</p><p>本文仅为了解释方便,使用了注释。在实际使用中请删除所有注释。</p> </div><h2 id="一、JSON-是什么"><a href="#一、JSON-是什么" class="headerlink" title="一、JSON 是什么"></a>一、JSON 是什么</h2><p><code>JSON</code> (JavaScript Object Notation,读作 <code>Jason</code>) 是一种轻量级的数据交换格式,是基于 <code>JavaScript</code> 的一个子集。易于人阅读和编写,同时也易于机器解析和生成。这些特性使其成为理想的数据交换语言 <sup id="fnref:1" class="footnote-ref"><a href="#fn:1" rel="footnote"><span class="hint--top hint--rounded" aria-label="[介绍 JSON](https://www.json.org/json-zh.html)">[1]</span></a></sup>。</p><p>Crockford 率先设计并普及了 <code>JSON</code>。源自当年对不依赖 <code>Flash</code> & <code>Java Applet</code> 的实时 <code>Server-to-Browser</code> 通信协议的需求 <sup id="fnref:2" class="footnote-ref"><a href="#fn:2" rel="footnote"><span class="hint--top hint--rounded" aria-label="[JSON - Wikipedia](https://en.wikipedia.org/wiki/JSON)">[2]</span></a></sup>。</p><h2 id="二、JSON-的格式"><a href="#二、JSON-的格式" class="headerlink" title="二、JSON 的格式"></a>二、JSON 的格式</h2><h3 id="1-基本结构"><a href="#1-基本结构" class="headerlink" title="1. 基本结构"></a>1. 基本结构</h3><p><code>JSON</code> 由三种元素组成 <sup id="fnref:1" class="footnote-ref"><a href="#fn:1" rel="footnote"><span class="hint--top hint--rounded" aria-label="[介绍 JSON](https://www.json.org/json-zh.html)">[1]</span></a></sup>,包括:</p><ul><li>Object: 记录无序的映射关系,在 <code>Python</code> 中称为字典(<code>dict</code>),在一些语言中被称为映射(<code>map</code>)</li><li>Array: 记录有序的数据集合,在 <code>Python</code> 中称呼为列表(<code>list</code>)</li><li>Value:如其名,记录各种类型的数据,具体类型稍后解释</li></ul><p>这些结构都是 <code>language-independent</code> 的,被大部分现代计算机语言以各种形式支持。这使跨编程语言,进行数据交换成为一种可能 <sup id="fnref:1" class="footnote-ref"><a href="#fn:1" rel="footnote"><span class="hint--top hint--rounded" aria-label="[介绍 JSON](https://www.json.org/json-zh.html)">[1]</span></a></sup>。</p><p>接下来将分别解释上面的概念。</p><h3 id="2-JSON-语法"><a href="#2-JSON-语法" class="headerlink" title="2. JSON 语法"></a>2. JSON 语法</h3><p><code>JSON Text</code> 是数据经过序列化后的 <code>JSON</code> 字符串。可以是 <code>Object</code>, <code>Array</code> 和 <code>Value</code> <sup id="fnref:3" class="footnote-ref"><a href="#fn:3" rel="footnote"><span class="hint--top hint--rounded" aria-label="[JSON Grammar - RFC 8259](https://datatracker.ietf.org/doc/html/rfc8259#section-2)">[3]</span></a></sup>。</p><p>但是因为 <code>Value</code> 囊括了 <code>Object</code> & <code>Array</code>。所以一个非常简洁明了的等式是:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs plaintext">JSON Text = Value<br></code></pre></td></tr></table></figure><h3 id="3-Value"><a href="#3-Value" class="headerlink" title="3. Value"></a>3. Value</h3><p>其中 <code>Value</code> 是一个比较特别的元素,包括了不同的类型 <sup id="fnref:1" class="footnote-ref"><a href="#fn:1" rel="footnote"><span class="hint--top hint--rounded" aria-label="[介绍 JSON](https://www.json.org/json-zh.html)">[1]</span></a></sup>,包括:</p><ul><li>Object & Array:嵌套的 <code>Object</code> 和 <code>Array</code></li><li>String:被引号 <code>""</code> 包住的字符串</li><li>Number:数字,包括 <code>fixed</code> 和 <code>float</code></li><li>Boolean:布尔值, <code>true</code> 或 <code>false</code></li><li>Null:空值,在 <code>Python</code> 中对应 <code>None</code></li></ul><p><code>Value</code> 是一个基本概念,任何作为 <code>Object</code>, <code>Array</code>, <code>String</code>, <code>Number</code>, <code>Boolean</code>, <code>Null</code> 的数据都算作是 <code>Value</code>。</p><p>可以理解为只要是 <code>Value</code> 的地方实际上可以是上述任一类型的数据。(包括 <code>JSON Text</code> 的根元素)<sup id="fnref:1" class="footnote-ref"><a href="#fn:1" rel="footnote"><span class="hint--top hint--rounded" aria-label="[介绍 JSON](https://www.json.org/json-zh.html)">[1]</span></a></sup> <sup id="fnref:3" class="footnote-ref"><a href="#fn:3" rel="footnote"><span class="hint--top hint--rounded" aria-label="[JSON Grammar - RFC 8259](https://datatracker.ietf.org/doc/html/rfc8259#section-2)">[3]</span></a></sup></p><p>如果你略懂一点 <code>Python</code> 的 <code>type hints</code>,那么我想用 <code>Union</code> 来解释 <code>Value</code> 会更加直观:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> typing <span class="hljs-keyword">import</span> <span class="hljs-type">Union</span><br><br>Value = <span class="hljs-type">Union</span>[Object, Array, <span class="hljs-built_in">str</span>, <span class="hljs-built_in">int</span>, <span class="hljs-built_in">float</span>, <span class="hljs-built_in">bool</span>, <span class="hljs-literal">None</span>]<br></code></pre></td></tr></table></figure><h3 id="4-Object"><a href="#4-Object" class="headerlink" title="4. Object"></a>4. Object</h3><p><code>Object</code> 是 <code>JSON</code> 非常重要的一个组成部分甚至不少人认为 <code>JSON</code> 必须以 <code>{}</code> 作为最外层元素(尽管这并不正确 <sup id="fnref:3" class="footnote-ref"><a href="#fn:3" rel="footnote"><span class="hint--top hint--rounded" aria-label="[JSON Grammar - RFC 8259](https://datatracker.ietf.org/doc/html/rfc8259#section-2)">[3]</span></a></sup>)。</p><p><code>Object</code> 内含有数对 <code>key-value</code> 的映射关系,其形态如下:</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs json"><span class="hljs-punctuation">{</span><br> <span class="hljs-attr">"key1"</span><span class="hljs-punctuation">:</span> <value1><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"key2"</span><span class="hljs-punctuation">:</span> <value2><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"key3"</span><span class="hljs-punctuation">:</span> <value3> <span class="hljs-comment">// 最后一个元素不可以有逗号</span><br><span class="hljs-punctuation">}</span><br></code></pre></td></tr></table></figure><p>在这里 <code>key</code> 必须是一个 <code>String</code>,<code>value</code> 的类型则为 <code>Value</code>。</p><p><code>key</code> 和 <code>value</code> 之间用 <code>:</code> 分隔,<code>key-value</code> 之间用 <code>,</code> 分隔。外面则用 <code>{}</code> 包裹 <sup id="fnref:1" class="footnote-ref"><a href="#fn:1" rel="footnote"><span class="hint--top hint--rounded" aria-label="[介绍 JSON](https://www.json.org/json-zh.html)">[1]</span></a></sup>。</p><p>前面提到过,<code>Object</code> 也是 <code>Value</code> 的一种 <sup id="fnref:1" class="footnote-ref"><a href="#fn:1" rel="footnote"><span class="hint--top hint--rounded" aria-label="[介绍 JSON](https://www.json.org/json-zh.html)">[1]</span></a></sup>,所以 <code>Object</code> 也可以作为 <code>Value</code> 的一部分。看下面这个例子:</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs json"><span class="hljs-punctuation">{</span><br> <span class="hljs-attr">"key1"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span> <span class="hljs-comment">// 这里 key1 对应的 value 是一个 Object</span><br> <span class="hljs-attr">"key2"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"value"</span> <span class="hljs-comment">// 这里 key2 对应的 value 是一个 String</span><br> <span class="hljs-punctuation">}</span><span class="hljs-punctuation">,</span> <br> <span class="hljs-attr">"key3"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span><span class="hljs-number">1</span><span class="hljs-punctuation">,</span> <span class="hljs-number">2</span><span class="hljs-punctuation">,</span> <span class="hljs-number">3</span><span class="hljs-punctuation">]</span> <span class="hljs-comment">// 这里 key3 对应的 value 是一个 Array</span><br><span class="hljs-punctuation">}</span><br></code></pre></td></tr></table></figure><h3 id="5-Array"><a href="#5-Array" class="headerlink" title="5. Array"></a>5. Array</h3><p><code>Array</code> 是 <code>JSON</code> 中的另一个重要元素,其形态如下:</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs json"><span class="hljs-punctuation">[</span><br> <value1><span class="hljs-punctuation">,</span><br> <value2><span class="hljs-punctuation">,</span><br> <value3> <span class="hljs-comment">// 最后一个元素不可以有逗号</span><br><span class="hljs-punctuation">]</span><br></code></pre></td></tr></table></figure><p>和上面一样,这里的 <code>value</code> 也是 <code>Value</code> 类型的数据。<code>value</code> 之间用 <code>,</code> 分隔,外面则用 <code>[]</code> 包裹。<sup id="fnref:1" class="footnote-ref"><a href="#fn:1" rel="footnote"><span class="hint--top hint--rounded" aria-label="[介绍 JSON](https://www.json.org/json-zh.html)">[1]</span></a></sup></p><p>同样,这里我们展示一下 <code>Object</code> 和 <code>Array</code> 作为 <code>Value</code> 的一个例子:</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs json"><span class="hljs-punctuation">[</span><br> <span class="hljs-punctuation">[</span><span class="hljs-number">1</span><span class="hljs-punctuation">,</span> <span class="hljs-number">2</span><span class="hljs-punctuation">,</span> <span class="hljs-number">3</span><span class="hljs-punctuation">]</span><span class="hljs-punctuation">,</span> <span class="hljs-comment">// 这里是一个 Array</span><br> <span class="hljs-punctuation">{</span><br> <span class="hljs-attr">"key1"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"value1"</span><span class="hljs-punctuation">,</span><br> <span class="hljs-punctuation">}</span><br><span class="hljs-punctuation">]</span><br></code></pre></td></tr></table></figure><h3 id="6-String"><a href="#6-String" class="headerlink" title="6. String"></a>6. String</h3><p><code>String</code> 是 <code>JSON</code> 中的一个基本数据类型,其形态如下:</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs json"><span class="hljs-string">"Hello, World!"</span><br></code></pre></td></tr></table></figure><p><code>String</code> 是由 <code>"</code> 包裹的字符序列。<code>String</code> 也是 <code>Value</code> 的一种。<sup id="fnref:1" class="footnote-ref"><a href="#fn:1" rel="footnote"><span class="hint--top hint--rounded" aria-label="[介绍 JSON](https://www.json.org/json-zh.html)">[1]</span></a></sup></p><h3 id="7-Number"><a href="#7-Number" class="headerlink" title="7. Number"></a>7. Number</h3><p><code>Number</code> 也是 <code>JSON</code> 中的一个基本数据类型,其形态如下:</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs json"><span class="hljs-number">123456</span><br><span class="hljs-number">123.456</span><br><span class="hljs-number">123456e-3</span><br></code></pre></td></tr></table></figure><p>这里的 <code>Number</code> 包括了整数和浮点数。<code>Number</code> 也是 <code>Value</code> 的一种。<sup id="fnref:1" class="footnote-ref"><a href="#fn:1" rel="footnote"><span class="hint--top hint--rounded" aria-label="[介绍 JSON](https://www.json.org/json-zh.html)">[1]</span></a></sup></p><h3 id="8-Boolean"><a href="#8-Boolean" class="headerlink" title="8. Boolean"></a>8. Boolean</h3><p><code>Boolean</code>,布尔值,作为基本类型的它只存在两个不同的数据:</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs json"><span class="hljs-literal"><span class="hljs-keyword">true</span></span><br><span class="hljs-literal"><span class="hljs-keyword">false</span></span><br></code></pre></td></tr></table></figure><p><code>Boolean</code> 也是 <code>Value</code> 的一种。<sup id="fnref:1" class="footnote-ref"><a href="#fn:1" rel="footnote"><span class="hint--top hint--rounded" aria-label="[介绍 JSON](https://www.json.org/json-zh.html)">[1]</span></a></sup></p><h3 id="9-Null"><a href="#9-Null" class="headerlink" title="9. Null"></a>9. Null</h3><p><code>Null</code>,空值,比 <code>Boolean</code> 还过分,只有一个数据:</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs json"><span class="hljs-literal"><span class="hljs-keyword">null</span></span><br></code></pre></td></tr></table></figure><p><code>Null</code> 也是 <code>Value</code> 的一种。<sup id="fnref:1" class="footnote-ref"><a href="#fn:1" rel="footnote"><span class="hint--top hint--rounded" aria-label="[介绍 JSON](https://www.json.org/json-zh.html)">[1]</span></a></sup></p><h2 id="三、示例"><a href="#三、示例" class="headerlink" title="三、示例"></a>三、示例</h2><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><code class="hljs json"><span class="hljs-punctuation">{</span><br> <span class="hljs-attr">"name"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"cxzlw"</span><span class="hljs-punctuation">,</span> <span class="hljs-comment">// string</span><br> <span class="hljs-attr">"age"</span><span class="hljs-punctuation">:</span> <span class="hljs-number">16</span><span class="hljs-punctuation">,</span> <span class="hljs-comment">// number</span><br> <span class="hljs-attr">"gender"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"mtf"</span><span class="hljs-punctuation">,</span> <span class="hljs-comment">// also string(夹杂私货)</span><br> <span class="hljs-attr">"balance"</span><span class="hljs-punctuation">:</span> <span class="hljs-number">123.45</span><span class="hljs-punctuation">,</span> <span class="hljs-comment">// also number</span><br> <span class="hljs-attr">"is_student"</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">true</span></span><span class="hljs-punctuation">,</span> <span class="hljs-comment">// boolean</span><br> <span class="hljs-attr">"hobbies"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span> <span class="hljs-comment">// array of strings</span><br> <span class="hljs-string">"coding"</span><span class="hljs-punctuation">,</span><br> <span class="hljs-string">"reading"</span><span class="hljs-punctuation">,</span><br> <span class="hljs-string">"writing"</span><br> <span class="hljs-punctuation">]</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"friends"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span> <span class="hljs-comment">// array of objects</span><br> <span class="hljs-punctuation">{</span> <span class="hljs-comment">// 这里演示的是一个 Object 嵌套在 Array 中,再嵌套在另一个 Object 中</span><br> <span class="hljs-attr">"name"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"Alice"</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"age"</span><span class="hljs-punctuation">:</span> <span class="hljs-number">18</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"is_student"</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">true</span></span><span class="hljs-punctuation">,</span> <br> <span class="hljs-attr">"balance"</span><span class="hljs-punctuation">:</span> <span class="hljs-number">123.45</span><br> <span class="hljs-punctuation">}</span><span class="hljs-punctuation">,</span><br> <span class="hljs-punctuation">{</span><br> <span class="hljs-attr">"name"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"Bob"</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"age"</span><span class="hljs-punctuation">:</span> <span class="hljs-number">19</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"is_student"</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">false</span></span><span class="hljs-punctuation">,</span> <br> <span class="hljs-attr">"balance"</span><span class="hljs-punctuation">:</span> <span class="hljs-number">123.45</span><br> <span class="hljs-punctuation">}</span> <span class="hljs-comment">// 末尾不能有逗号</span><br> <span class="hljs-punctuation">]</span> <span class="hljs-comment">// 注意每个 [ 都要有与之配对的 ]</span><br><span class="hljs-punctuation">}</span> <span class="hljs-comment">// 同样 { 要有配对的 }</span><br></code></pre></td></tr></table></figure><h2 id="四、JSON-的意义"><a href="#四、JSON-的意义" class="headerlink" title="四、JSON 的意义"></a>四、JSON 的意义</h2><p><code>JSON</code> 作为一种数据交换格式,其最大的意义在于其跨语言的特性。<code>JSON</code> 可以被大部分现代编程语言解析,这使得 <code>JSON</code> 成为了一种非常之理想的数据交换格式 <sup id="fnref:1" class="footnote-ref"><a href="#fn:1" rel="footnote"><span class="hint--top hint--rounded" aria-label="[介绍 JSON](https://www.json.org/json-zh.html)">[1]</span></a></sup>。</p><p>同时,随着前后端分离概念的出现,越来越多网站使用 <code>JSON</code> 格式在前后端之间交换数据。无论是进行 Web 开发,还是反过来进行数据抓取(爬虫),<code>JSON</code> 都是值得掌握的一种数据格式。</p><p>在不久后的 <a href="https://mp.weixin.qq.com/s/yGyvLGjcdLOM2JqgufhvwQ">TeensCamp3</a> 中,我们将会涉及到使用 <code>JSON</code> 来存储数据的项目。因此提前了解 <code>JSON</code> 的基本知识是非常有必要的。</p><hr><section class="footnotes"><div class="footnote-list"><ol><li><span id="fn:1" class="footnote-text"><span><a href="https://www.json.org/json-zh.html">介绍 JSON</a><a href="#fnref:1" rev="footnote" class="footnote-backref"> ↩</a></span></span></li><li><span id="fn:2" class="footnote-text"><span><a href="https://en.wikipedia.org/wiki/JSON">JSON - Wikipedia</a><a href="#fnref:2" rev="footnote" class="footnote-backref"> ↩</a></span></span></li><li><span id="fn:3" class="footnote-text"><span><a href="https://datatracker.ietf.org/doc/html/rfc8259#section-2">JSON Grammar - RFC 8259</a><a href="#fnref:3" rev="footnote" class="footnote-backref"> ↩</a></span></span></li></ol></div></section>]]></content>
<tags>
<tag>cxzlw</tag>
</tags>
</entry>
<entry>
<title>不蒜子在 Safari 中计数异常</title>
<link href="/2023/10/03/busuanzi-bug/"/>
<url>/2023/10/03/busuanzi-bug/</url>
<content type="html"><![CDATA[<p>近期,我的博客在 Safari 中,文章访问量异常的大。经过抓包,确认了问题与 Referer 头相关。然而,Referrer-Policy 并没有解决问题。这与其接口设计有关。本文将进行解释,并提出我的解决方案。</p><h2 id="问题表现"><a href="#问题表现" class="headerlink" title="问题表现"></a>问题表现</h2><div class="group-image-container"><div class="group-image-row"><div class="group-image-wrap"><img src="/../img/image-6.png" alt="Safari 打开效果"></div><div class="group-image-wrap"><img src="/../img/image-7.png" alt="正常情况打开效果"></div></div></div><figcaption aria-hidden="true" class="image-caption">左:Safari 打开效果 右:正常情况打开效果</figcaption><p>如图所示,Safari 显示的访问量高达 1k+,比实际访问量高出了 1448 次。这是很奇怪的,引起了我的注意。</p><h2 id="问题原因"><a href="#问题原因" class="headerlink" title="问题原因"></a>问题原因</h2><p>为了找到引起这个问题的原因,我们对上述页面分别向 busuanzi 发的请求都进行抓包。</p><h3 id="Safari"><a href="#Safari" class="headerlink" title="Safari"></a>Safari</h3><p><img src="/../img/img-20231004-safari-busuanzi.png" alt="Safari 向 busuanzi 发的请求"></p><h3 id="Chrome"><a href="#Chrome" class="headerlink" title="Chrome"></a>Chrome</h3><p><img src="/../img/img-20231004-chrome-busuanzi.png" alt="Chrome 向 busuanzi 发的请求"></p><p>从上面的两个请求,可以看出Safari 向 busuanzi 发送的请求 Referer 头是错误的。这导致 Safari 获得了 <code>https://blog.cxzlw.top/</code> 的浏览量信息。这是为什么呢?</p><h2 id="高人指点"><a href="#高人指点" class="headerlink" title="高人指点"></a>高人指点</h2><p>加入 busuanzi QQ 群<sup id="fnref:1" class="footnote-ref"><a href="#fn:1" rel="footnote"><span class="hint--top hint--rounded" aria-label="419260983,来自 busunazi 官网 [不蒜子 | 不如](https://ibruce.info/2015/04/04/busuanzi/#more:~:text=%E5%A3%B0%E6%98%8E%EF%BC%9A%E7%BB%8F%E7%94%A8%E6%88%B7%E5%BB%BA%E8%AE%AE%EF%BC%8C%E6%96%B0%E5%A2%9E%E4%B8%8D%E8%92%9C%E5%AD%90%E4%BA%A4%E6%B5%81QQ%E7%BE%A4%EF%BC%9A419260983%EF%BC%8C%E6%AC%A2%E8%BF%8E%E5%A4%A7%E5%AE%B6%E5%8A%A0%E5%85%A5%E3%80%82%E2%80%94%E2%80%94%20%E4%B8%8D%E5%A6%82%EF%BC%8C2017.02)">[1]</span></a></sup>后,我在群中询问。并得到了大佬「 」的回复。<br><img src="/../img/image-8.png" alt="大佬的解答"></p><p>图中的链接是:<a href="https://zhufan.net/2020/10/14/referrer-policy%E9%82%A3%E4%BA%9B%E4%BA%8B/">Referrer Policy那些事 | 煮饭🍚</a></p><h2 id="Referrer-Policy"><a href="#Referrer-Policy" class="headerlink" title="Referrer-Policy"></a>Referrer-Policy</h2><p>发生了什么呢?浏览器开始用 <code>strict-origin-when-cross-origin</code> 替换之前的 <code>no-referrer-when-downgrade</code> 作为 <code>Referrer-Policy</code> 的默认值,而这个新策略破坏了向不蒜子发送的 <code>Referer</code> 头。</p><p>于是我设置了 <code>Referrer-Policy</code>。具体来说,我将下面的代码加入了我的博客:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs html"><span class="hljs-tag"><<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"referrer"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"no-referrer-when-downgrade"</span>></span><br></code></pre></td></tr></table></figure><p>还有一些设置 <code>Referrer-Policy</code> 的方法:</p><ol><li>在 HTTP Header 中添加:<code>Referrer-Policy: no-referrer-when-downgrade</code></li><li>在发起请求的 Element 中添加 <code>referrerpolicy="no-referrer-when-downgrade"</code> 属性<br>例如:<code><a href="http://example.com" referrerpolicy="no-referrer-when-downgrade"></code></li></ol><h2 id="穷途末路"><a href="#穷途末路" class="headerlink" title="穷途末路"></a>穷途末路</h2><p>事情并没有完,在 Safari 上,我的博客依然无法正常显示浏览量,这又是为什么呢?</p><p>在回答这个问题之前,先让我们解决一个前文从未提到的问题「为什么其他浏览器能正常显示?」。</p><h3 id="为什么其他浏览器能正常显示?"><a href="#为什么其他浏览器能正常显示?" class="headerlink" title="为什么其他浏览器能正常显示?"></a>为什么其他浏览器能正常显示?</h3><p>前文 <a href="https://zhufan.net/2020/10/14/referrer-policy%E9%82%A3%E4%BA%9B%E4%BA%8B/">Referrer Policy那些事 | 煮饭🍚</a> 中提到:</p><blockquote><p>之前的默认值是 no-referrer-when-downgrade,而现在变成了 strict-origin-when-cross-origin。经过查找,原来是chrome85以上做出了默认规则的改变。 <a href="https://developers.google.com/web/updates/2020/07/referrer-policy-new-chrome-default">A new default Referrer-Policy for Chrome - strict-origin-when-cross-origin - Chrome for Developers</a></p></blockquote><p>既然 Chrome 也作出了上述改变,为什么我的博客在 Chrome 中能正常显示呢?</p><p>要回答这个问题,让我们看看 busuanzi 的源码:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">var</span> bszCaller, bszTag;<br>!<span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">var</span> c, d, e, a = !<span class="hljs-number">1</span>, b = [];<br> ready = <span class="hljs-keyword">function</span>(<span class="hljs-params">c</span>) {<br> <span class="hljs-keyword">return</span> a || <span class="hljs-string">"interactive"</span> === <span class="hljs-variable language_">document</span>.<span class="hljs-property">readyState</span> || <span class="hljs-string">"complete"</span> === <span class="hljs-variable language_">document</span>.<span class="hljs-property">readyState</span> ? c.<span class="hljs-title function_">call</span>(<span class="hljs-variable language_">document</span>) : b.<span class="hljs-title function_">push</span>(<span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">return</span> c.<span class="hljs-title function_">call</span>(<span class="hljs-variable language_">this</span>)<br> }),<br> <span class="hljs-variable language_">this</span><br> }<br> ,<br> d = <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> a = <span class="hljs-number">0</span>, c = b.<span class="hljs-property">length</span>; c > a; a++)<br> b[a].<span class="hljs-title function_">apply</span>(<span class="hljs-variable language_">document</span>);<br> b = []<br> }<br> ,<br> e = <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) {<br> a || (a = !<span class="hljs-number">0</span>,<br> d.<span class="hljs-title function_">call</span>(<span class="hljs-variable language_">window</span>),<br> <span class="hljs-variable language_">document</span>.<span class="hljs-property">removeEventListener</span> ? <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">removeEventListener</span>(<span class="hljs-string">"DOMContentLoaded"</span>, e, !<span class="hljs-number">1</span>) : <span class="hljs-variable language_">document</span>.<span class="hljs-property">attachEvent</span> && (<span class="hljs-variable language_">document</span>.<span class="hljs-title function_">detachEvent</span>(<span class="hljs-string">"onreadystatechange"</span>, e),<br> <span class="hljs-variable language_">window</span> == <span class="hljs-variable language_">window</span>.<span class="hljs-property">top</span> && (<span class="hljs-built_in">clearInterval</span>(c),<br> c = <span class="hljs-literal">null</span>)))<br> }<br> ,<br> <span class="hljs-variable language_">document</span>.<span class="hljs-property">addEventListener</span> ? <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">addEventListener</span>(<span class="hljs-string">"DOMContentLoaded"</span>, e, !<span class="hljs-number">1</span>) : <span class="hljs-variable language_">document</span>.<span class="hljs-property">attachEvent</span> && (<span class="hljs-variable language_">document</span>.<span class="hljs-title function_">attachEvent</span>(<span class="hljs-string">"onreadystatechange"</span>, <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-regexp">/loaded|complete/</span>.<span class="hljs-title function_">test</span>(<span class="hljs-variable language_">document</span>.<span class="hljs-property">readyState</span>) && <span class="hljs-title function_">e</span>()<br> }),<br> <span class="hljs-variable language_">window</span> == <span class="hljs-variable language_">window</span>.<span class="hljs-property">top</span> && (c = <span class="hljs-built_in">setInterval</span>(<span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">try</span> {<br> a || <span class="hljs-variable language_">document</span>.<span class="hljs-property">documentElement</span>.<span class="hljs-title function_">doScroll</span>(<span class="hljs-string">"left"</span>)<br> } <span class="hljs-keyword">catch</span> (b) {<br> <span class="hljs-keyword">return</span><br> }<br> <span class="hljs-title function_">e</span>()<br> }, <span class="hljs-number">5</span>)))<br>}(),<br>bszCaller = {<br> <span class="hljs-attr">fetch</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">a, b</span>) {<br> <span class="hljs-keyword">var</span> c = <span class="hljs-string">"BusuanziCallback_"</span> + <span class="hljs-title class_">Math</span>.<span class="hljs-title function_">floor</span>(<span class="hljs-number">1099511627776</span> * <span class="hljs-title class_">Math</span>.<span class="hljs-title function_">random</span>());<br> <span class="hljs-variable language_">window</span>[c] = <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">evalCall</span>(b),<br> a = a.<span class="hljs-title function_">replace</span>(<span class="hljs-string">"=BusuanziCallback"</span>, <span class="hljs-string">"="</span> + c),<br> scriptTag = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">createElement</span>(<span class="hljs-string">"SCRIPT"</span>),<br> scriptTag.<span class="hljs-property">type</span> = <span class="hljs-string">"text/javascript"</span>,<br> scriptTag.<span class="hljs-property">defer</span> = !<span class="hljs-number">0</span>,<br> scriptTag.<span class="hljs-property">src</span> = a,<br> scriptTag.<span class="hljs-property">referrerPolicy</span> = <span class="hljs-string">"no-referrer-when-downgrade"</span>,<br> <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">getElementsByTagName</span>(<span class="hljs-string">"HEAD"</span>)[<span class="hljs-number">0</span>].<span class="hljs-title function_">appendChild</span>(scriptTag)<br> },<br> <span class="hljs-attr">evalCall</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">a</span>) {<br> <span class="hljs-keyword">return</span> <span class="hljs-keyword">function</span>(<span class="hljs-params">b</span>) {<br> <span class="hljs-title function_">ready</span>(<span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">try</span> {<br> <span class="hljs-title function_">a</span>(b),<br> scriptTag.<span class="hljs-property">parentElement</span>.<span class="hljs-title function_">removeChild</span>(scriptTag)<br> } <span class="hljs-keyword">catch</span> (c) {<br> bszTag.<span class="hljs-title function_">hides</span>()<br> }<br> })<br> }<br> }<br>},<br>bszCaller.<span class="hljs-title function_">fetch</span>(<span class="hljs-string">"//busuanzi.ibruce.info/busuanzi?jsonpCallback=BusuanziCallback"</span>, <span class="hljs-keyword">function</span>(<span class="hljs-params">a</span>) {<br> bszTag.<span class="hljs-title function_">texts</span>(a),<br> bszTag.<span class="hljs-title function_">shows</span>()<br>}),<br>bszTag = {<br> <span class="hljs-attr">bszs</span>: [<span class="hljs-string">"site_pv"</span>, <span class="hljs-string">"page_pv"</span>, <span class="hljs-string">"site_uv"</span>],<br> <span class="hljs-attr">texts</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">a</span>) {<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">bszs</span>.<span class="hljs-title function_">map</span>(<span class="hljs-keyword">function</span>(<span class="hljs-params">b</span>) {<br> <span class="hljs-keyword">var</span> c = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">getElementById</span>(<span class="hljs-string">"busuanzi_value_"</span> + b);<br> c && (c.<span class="hljs-property">innerHTML</span> = a[b])<br> })<br> },<br> <span class="hljs-attr">hides</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">bszs</span>.<span class="hljs-title function_">map</span>(<span class="hljs-keyword">function</span>(<span class="hljs-params">a</span>) {<br> <span class="hljs-keyword">var</span> b = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">getElementById</span>(<span class="hljs-string">"busuanzi_container_"</span> + a);<br> b && (b.<span class="hljs-property">style</span>.<span class="hljs-property">display</span> = <span class="hljs-string">"none"</span>)<br> })<br> },<br> <span class="hljs-attr">shows</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">bszs</span>.<span class="hljs-title function_">map</span>(<span class="hljs-keyword">function</span>(<span class="hljs-params">a</span>) {<br> <span class="hljs-keyword">var</span> b = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">getElementById</span>(<span class="hljs-string">"busuanzi_container_"</span> + a);<br> b && (b.<span class="hljs-property">style</span>.<span class="hljs-property">display</span> = <span class="hljs-string">"inline"</span>)<br> })<br> }<br>};<br></code></pre></td></tr></table></figure><p>其中,我们重点关注这段代码:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-attr">fetch</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">a, b</span>) {<br> <span class="hljs-keyword">var</span> c = <span class="hljs-string">"BusuanziCallback_"</span> + <span class="hljs-title class_">Math</span>.<span class="hljs-title function_">floor</span>(<span class="hljs-number">1099511627776</span> * <span class="hljs-title class_">Math</span>.<span class="hljs-title function_">random</span>());<br> <span class="hljs-variable language_">window</span>[c] = <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">evalCall</span>(b),<br> a = a.<span class="hljs-title function_">replace</span>(<span class="hljs-string">"=BusuanziCallback"</span>, <span class="hljs-string">"="</span> + c),<br> scriptTag = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">createElement</span>(<span class="hljs-string">"SCRIPT"</span>),<br> scriptTag.<span class="hljs-property">type</span> = <span class="hljs-string">"text/javascript"</span>,<br> scriptTag.<span class="hljs-property">defer</span> = !<span class="hljs-number">0</span>,<br> scriptTag.<span class="hljs-property">src</span> = a,<br> scriptTag.<span class="hljs-property">referrerPolicy</span> = <span class="hljs-string">"no-referrer-when-downgrade"</span>,<br> <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">getElementsByTagName</span>(<span class="hljs-string">"HEAD"</span>)[<span class="hljs-number">0</span>].<span class="hljs-title function_">appendChild</span>(scriptTag)<br>},<br></code></pre></td></tr></table></figure><p>回顾 <a href="#Referrer-Policy">Referrer-Policy</a> 部分,我们也可以通过在 Element 中添加 <code>referrerpolicy="no-referrer-when-downgrade"</code> 属性来设置 <code>Referrer-Policy</code>。</p><p>这段代码在使用 JSONP 解决跨域的问题时,创建了一个带有 <code>referrerpolicy</code> 属性的 Script Tag,以此解决了 Chrome 等浏览器上出现的问题。</p><h3 id="为什么-Safari-不能?"><a href="#为什么-Safari-不能?" class="headerlink" title="为什么 Safari 不能?"></a>为什么 Safari 不能?</h3><p>上面我们解释了为什么 Chrome 等浏览器能正常显示我的博客的浏览量,接下来我们将解释为什么 Safari 中仍然出现这种问题。</p><p><a href="https://webkit.org/blog/9661/preventing-tracking-prevention-tracking/#:~:text=Origin%2DOnly%20Referrer%20For%20All%20Third%2DParty%20Requests">Preventing Tracking Prevention Tracking | WebKit</a></p><blockquote><p><strong>Origin-Only Referrer For All Third-Party Requests</strong><br>ITP now downgrades all cross-site request referrer headers to just the page’s origin. Previously, this was only done for cross-site requests to classified domains.</p><p>As an example, a request to <a href="https://images.example/">https://images.example</a> that would previously contain the referrer header “<a href="https://store.example/baby/strollers/deluxe-stroller-navy-blue.html%E2%80%9D">https://store.example/baby/strollers/deluxe-stroller-navy-blue.html”</a> will now be reduced to just “<a href="https://store.example/%E2%80%9D">https://store.example/”</a>.</p></blockquote><p>原来,Safari 的 <strong>阻止跨站跟踪</strong> 功能会将跨站请求中的 <code>Referer</code> 头全部降级为页面的根路径。效果就像 <code>strict-origin-when-cross-origin</code>。这无疑对 busuanzi 的请求生效,因此开启了 <strong>阻止跨站跟踪</strong> 的 Safari 便会遇到这个问题。</p><p>显然要求每个用户关闭 <strong>阻止跨站跟踪</strong> 是奇怪的,在 busuanzi 作者主动修改 API 不再依赖 <code>Referer</code> 头前,似乎这成了一个无解的问题。</p><h2 id="我的解决方案"><a href="#我的解决方案" class="headerlink" title="我的解决方案"></a>我的解决方案</h2><p>我的解决方案是重构我的博客的访问量系统。自己写一个不依赖 <code>Referer</code> 头的 API,并将前端与访问量相关的代码重构。</p><p>我将会写一篇新的文章介绍这个 API,各位也可以直接抓包分析我的博客。这个 API 欢迎各位使用。但与 <a href="https://ibruce.info/">不如</a> 不同的是,我无法提供任何可用性保证。</p><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ol><li><a href="https://ibruce.info/2015/04/04/busuanzi/">不蒜子 | 不如</a></li><li><a href="https://zhufan.net/2020/10/14/referrer-policy%E9%82%A3%E4%BA%9B%E4%BA%8B/">Referrer Policy那些事 | 煮饭🍚</a></li><li><a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Referrer-Policy">Referrer-Policy - HTTP | MDNMDN Web DocsMDN logoMozilla logo</a></li><li><a href="https://github.com/fluid-dev/hexo-theme-fluid/issues/376">不蒜子在 Chrome 85 版本后所有页面统计是同一个数据 · Issue #376 · fluid-dev/hexo-theme-fluid · GitHub</a></li><li><a href="https://caniuse.com/referrer-policy">Referrer Policy | Can I use… Support tables for HTML5, CSS3, etc</a></li><li><a href="https://webkit.org/blog/9661/preventing-tracking-prevention-tracking/">Preventing Tracking Prevention Tracking | WebKit</a></li></ol><h2 id="注"><a href="#注" class="headerlink" title="注"></a>注</h2><section class="footnotes"><div class="footnote-list"><ol><li><span id="fn:1" class="footnote-text"><span>419260983,来自 busunazi 官网 <a href="https://ibruce.info/2015/04/04/busuanzi/#more:~:text=%E5%A3%B0%E6%98%8E%EF%BC%9A%E7%BB%8F%E7%94%A8%E6%88%B7%E5%BB%BA%E8%AE%AE%EF%BC%8C%E6%96%B0%E5%A2%9E%E4%B8%8D%E8%92%9C%E5%AD%90%E4%BA%A4%E6%B5%81QQ%E7%BE%A4%EF%BC%9A419260983%EF%BC%8C%E6%AC%A2%E8%BF%8E%E5%A4%A7%E5%AE%B6%E5%8A%A0%E5%85%A5%E3%80%82%E2%80%94%E2%80%94%20%E4%B8%8D%E5%A6%82%EF%BC%8C2017.02">不蒜子 | 不如</a><a href="#fnref:1" rev="footnote" class="footnote-backref"> ↩</a></span></span></li></ol></div></section>]]></content>
<tags>
<tag>Hexo</tag>
<tag>不蒜子</tag>
<tag>busuanzi</tag>
<tag>Fluid</tag>
<tag>cxzlw</tag>
</tags>
</entry>
<entry>
<title>Biology - Cell structure</title>
<link href="/2023/08/31/cell-structure/"/>
<url>/2023/08/31/cell-structure/</url>
<content type="html"><![CDATA[<h1 id="Cell-structure"><a href="#Cell-structure" class="headerlink" title="Cell structure"></a>Cell structure</h1><h2 id="Mind-map"><a href="#Mind-map" class="headerlink" title="Mind map"></a>Mind map</h2><pre><code class=" mermaid">mindmap root((Cell structure)) Organelles all typical cells have Cell membrane Controls movement in and out of cells. Outer membrane of cell Semi-permeable Cytoplasm Where chemical reactions take place. Surrounded by cell membrane Gel-like mixture containing solutes, organelles, and water Nucleus Contains DNA and controls the cell. Has a nuclear membrane, so DNA is not floating about Mitochondria Where aerobic respiration happens. Folds: create lots of surface area for reactions Ribosomes Allows protein synthesis Each cell contains thousands of them Make proteins by translating RNA codes Animal cell Cell membrane Cytoplasm Nucleus Mitochondria Ribosomes Plant cell Cell membrane Cytoplasm Nucleus Mitochondria Ribosomes Cell wall Rigid to keep the shape of the cell, strengthens the cell. Outermost layer Permeable: They don't select who comes in and who leaves Large Vacuole Cell sap to keep cell turgid. Membrane-bound sacs for storage, digestion, and waste removal Contains water solution Chloroplast Contain chlorophyll, which absorbs light energy for photosynthesis. In green parts of plants Prokaryotic cell Cell membrane Cytoplasm Ribosomes Circular DNA Instead of chromosomes, also called Nucleoid, is essential for controlling the activity and reproduction of the prokaryotic cell. Plasmid Small circles of DNA Cell wall Made of peptidoglycan not cellulose Differences Plant vs Animal Cell Wall Large Vacuole Chloroplasts Plant vs Prokaryotic Nucleus vs Nucleoid and Plasmid Cellulose vs Peptidoglycan</code></pre><h2 id="Organelles-all-typical-cells-have"><a href="#Organelles-all-typical-cells-have" class="headerlink" title="Organelles all typical cells have"></a>Organelles all typical cells have</h2><h3 id="Cell-membrane"><a href="#Cell-membrane" class="headerlink" title="Cell membrane"></a>Cell membrane</h3><p>Controls movement in and out of cells.</p><ul><li>Outer membrane of cell</li><li>Semi-permeable</li></ul><h3 id="Cytoplasm"><a href="#Cytoplasm" class="headerlink" title="Cytoplasm"></a>Cytoplasm</h3><p>Where chemical reactions take place.</p><ul><li>Surrounded by cell membrane</li><li>Gel-like mixture containing solutes, orangelles, and water</li></ul><h3 id="Nucleus"><a href="#Nucleus" class="headerlink" title="Nucleus"></a>Nucleus</h3><p>Contains DNA and controls the cell.</p><ul><li>Has a nuclear membrane, so DNA is not floating about</li></ul><h3 id="Mitochondria"><a href="#Mitochondria" class="headerlink" title="Mitochondria"></a>Mitochondria</h3><p>Where aerobic respiration happens.</p><ul><li>Folds: create lots of surface area for reactions</li></ul><h3 id="Ribosomes"><a href="#Ribosomes" class="headerlink" title="Ribosomes"></a>Ribosomes</h3><p>Allows protein synthesis</p><ul><li>Each cell contains thousands of them</li><li>Make proteins by translating RNA codes</li></ul><h2 id="Animal-cell"><a href="#Animal-cell" class="headerlink" title="Animal cell"></a>Animal cell</h2><p>Animal cell has all above.</p><h3 id="Diagram"><a href="#Diagram" class="headerlink" title="Diagram"></a>Diagram</h3><p><img src="/../img/animal.jpg" alt="Animal cell diagram"></p><h2 id="Plant-cell"><a href="#Plant-cell" class="headerlink" title="Plant cell"></a>Plant cell</h2><p>Plant cell especially also have:</p><h3 id="Cell-wall"><a href="#Cell-wall" class="headerlink" title="Cell wall"></a>Cell wall</h3><p>Rigid to keep the shape of the cell, strengthens the cell.</p><ul><li>Outermost layer</li><li>Permeable: They don’t select who comes in and who leaves</li></ul><h3 id="Large-Vacuole"><a href="#Large-Vacuole" class="headerlink" title="Large Vacuole"></a>Large Vacuole</h3><p>Cell sap to keep cell turgid.</p><ul><li>Membrane-bound sacs for storage, digestion, and waste removal</li><li>Contains water solution</li></ul><h3 id="Chloroplast"><a href="#Chloroplast" class="headerlink" title="Chloroplast"></a>Chloroplast</h3><p>Contain chlorophyll, which absorbs light energy for photosynthesis.</p><ul><li>In green parts of plants</li></ul><h3 id="Diagram-1"><a href="#Diagram-1" class="headerlink" title="Diagram"></a>Diagram</h3><p><img src="/../img/plant.jpg" alt="Plant cell diagram"></p><h2 id="Prokaryotic-cell"><a href="#Prokaryotic-cell" class="headerlink" title="Prokaryotic cell"></a>Prokaryotic cell</h2><p>Prokaryotic cell <strong>do not</strong> have Mitochondria and Nucleus but organelles below.</p><h3 id="Cell-wall-1"><a href="#Cell-wall-1" class="headerlink" title="Cell wall"></a>Cell wall</h3><p>Rigid to keep the shape of the cell, strengthens the cell.</p><ul><li>Made of <strong>peptidoglycan</strong> not cellulose</li></ul><h3 id="Circular-DNA"><a href="#Circular-DNA" class="headerlink" title="Circular DNA"></a>Circular DNA</h3><p>Instead of chromosomes, also called <em>Nucleoid</em>, is essential for controlling the acticity and reproduction of the<br>prokaryotic cell.</p><h3 id="Plasmid"><a href="#Plasmid" class="headerlink" title="Plasmid"></a>Plasmid</h3><p>Small circles of DNA.</p><h3 id="Diagram-2"><a href="#Diagram-2" class="headerlink" title="Diagram"></a>Diagram</h3><p><img src="/../img/prokaryotic.jpg" alt="Prokaryotic cell diagram"></p><h2 id="Differences"><a href="#Differences" class="headerlink" title="Differences"></a>Differences</h2><h3 id="Organelles-in-cells"><a href="#Organelles-in-cells" class="headerlink" title="Organelles in cells"></a>Organelles in cells</h3><table><thead><tr><th>Organelles \ Cells</th><th>Plant Cell</th><th>Animal Cell</th><th>Prokaryotic Cell</th></tr></thead><tbody><tr><td>Cell Wall</td><td>Yes</td><td></td><td></td></tr><tr><td>Cell Membrane</td><td>Yes</td><td>Yes</td><td>Yes</td></tr><tr><td>Chloroplasts</td><td>Yes</td><td></td><td></td></tr><tr><td>Cytoplasm</td><td>Yes</td><td>Yes</td><td>Yes</td></tr><tr><td>Mitochondria</td><td>Yes</td><td>Yes</td><td></td></tr><tr><td>Nucleus</td><td>Yes</td><td>Yes</td><td></td></tr><tr><td>Ribosome</td><td>Yes</td><td>Yes</td><td>Yes</td></tr><tr><td>Large Vacuole</td><td>Yes</td><td></td><td></td></tr><tr><td>Circular DNA</td><td></td><td></td><td>Yes</td></tr><tr><td>Plasmid</td><td></td><td></td><td>Yes</td></tr></tbody></table><h3 id="Some-differences-between-a-plant-cell-and-an-animal-cell"><a href="#Some-differences-between-a-plant-cell-and-an-animal-cell" class="headerlink" title="Some differences between a plant cell and an animal cell"></a>Some differences between a plant cell and an animal cell</h3><ol><li>A plant cell has cell wall, while an animal cell hasn’t.</li><li>A plant cell has large vacuole, while an animal cell hasn’t.</li><li>No animal cell has chloroplasts, but some plant cell do.</li></ol><h3 id="Some-differences-between-a-plant-cell-and-a-prokaryotic-cell"><a href="#Some-differences-between-a-plant-cell-and-a-prokaryotic-cell" class="headerlink" title="Some differences between a plant cell and a prokaryotic cell."></a>Some differences between a plant cell and a prokaryotic cell.</h3><ol><li>A plant cell has nucleus, and a prokaryotic cell has nucleoid and plasmid instead.</li><li>Cell wall in a plant cell is made of cellulose but peptidoglycan in a prokaryotic cell.</li></ol>]]></content>
</entry>
<entry>
<title>分享一个 Python 权限系统库的设计</title>
<link href="/2023/08/04/permission-system-design-share/"/>
<url>/2023/08/04/permission-system-design-share/</url>
<content type="html"><![CDATA[<p>最近在参与某 OJ 的开发,过程中我们需要一个权限系统。作为一个热爱 MC 的开发者,我很喜欢 luckperms 的设计,于是这个小东西就出来了。在这里给大家分享我们的权限系统设计。</p><h2 id="为什么不使用现成的库?"><a href="#为什么不使用现成的库?" class="headerlink" title="为什么不使用现成的库?"></a>为什么不使用现成的库?</h2><ol><li>如上文所说,我很喜欢 luckperms 的 <code>Group</code>,<code>Node</code>,<code>Route</code></li><li>我们希望整个项目使用 PonyORM</li><li>我们希望这个库最好不要与某个 Web Framework 强关联,例如现在我们在用的 <code>Flask</code>,以便我们应对可能的切换框架的情况</li></ol><h2 id="术语"><a href="#术语" class="headerlink" title="术语"></a>术语</h2><h3 id="权限组"><a href="#权限组" class="headerlink" title="权限组"></a>权限组</h3><p>权限组储存了以下信息</p><ul><li>权限组的名字</li><li>权限组的权重,这个权重只影响直属节点</li><li>权限组的成员,也就是用户</li><li>权限组继承的其他权限组</li><li>权限组直属的权限节点</li></ul><p>权限组的成员不一定要在创建时指定,可以为用户指定某个权限组,效果是一样的。</p><p>权限组可以继承自其他权限组。相同的权限,会取权重较高的权限节点的值。也就是说,会覆盖低权重的节点</p><p>一般情况下,继承自某个权限组的新权限组,权重应当更高,这样才能覆盖某些权限。同时,检查权限时,如果遇到相同权重却互相矛盾的权限节点,无法保证其结果。</p><h3 id="权限节点"><a href="#权限节点" class="headerlink" title="权限节点"></a>权限节点</h3><p>权限节点储存了以下信息</p><ul><li>一个权限 id,代表一个权限</li><li>一个 <code>bool</code> 值,代表是否拥有上述权限</li></ul><p>权限节点本身没有权重,其权重来源是直属的权限组。</p><p>值得一提的是,一般情况下你不需要明确为没有某种权限的权限组,添加值为 <code>False</code> 的权限节点。检查权限时,没有值为 <code>True</code> 的对应节点,相当于没有这个权限。</p><p>我们一般使用值为 <code>False</code> 的权限节点来覆盖父权限组下的某些权限。</p><h3 id="权限-id"><a href="#权限-id" class="headerlink" title="权限 id"></a>权限 id</h3><p>权限是一个概念,在这里我们以权限 id 的形式来代表某种权限。</p><p>这个 id 是一个字符串,其没有具体的命名规则。具体由使用者制定。但我们建议你使用形如 <code>user.login</code>,<code>problem.edit</code>,<code>problem.1001.edit</code> 的格式命名。</p><h2 id="使用方式"><a href="#使用方式" class="headerlink" title="使用方式"></a>使用方式</h2><h3 id="检查权限"><a href="#检查权限" class="headerlink" title="检查权限"></a>检查权限</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> permission <span class="hljs-keyword">import</span> check_permission<br><br>user: User = ... <span class="hljs-comment"># 自行实现获得 User 对象的代码</span><br><span class="hljs-built_in">print</span>(check_permission(user))<br><br></code></pre></td></tr></table></figure><h3 id="权限节点-1"><a href="#权限节点-1" class="headerlink" title="权限节点"></a>权限节点</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs python">user: PermissionGroup = ... <span class="hljs-comment"># 自行实现获得 PermissionGroup 对象的代码</span><br><br><span class="hljs-comment"># PermissionNode 没有 instance 方法</span><br><span class="hljs-comment"># 因此你需要自己避免在一个 PermissionGroup 下出现重复的 PermissionNode</span><br><span class="hljs-comment"># owner 是一个 PermissionGroup 对象,代表该节点属于这个权限组</span><br><span class="hljs-comment"># permission 是一个权限 id 字符串,检查权限时使用权限 id 而不是权限节点</span><br><span class="hljs-comment"># 代表同一个 permission 的 权限节点可能有多个,他们属于不同的权限组</span><br>this_node = PermissionNode(permission=<span class="hljs-string">"user.login"</span>, value=<span class="hljs-literal">True</span>, owner=user)<br><br>this_node.value = <span class="hljs-literal">False</span> <span class="hljs-comment"># 修改该权限节点的值,True 代表有这个权限,False代表没有</span><br><br></code></pre></td></tr></table></figure><h3 id="权限组-1"><a href="#权限组-1" class="headerlink" title="权限组"></a>权限组</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-comment"># instance 方法可以保证 name 相同时,每次运行都是同一个 PermissionGroup</span><br><span class="hljs-comment"># 方便你维护一个存储了你所有权限结构的文件</span><br><span class="hljs-comment"># 比如我们现在修改的是用户组</span><br>this_group = PermissionGroup.instance(name=<span class="hljs-string">"User"</span>, weight=<span class="hljs-number">1</span>)<br><br>parents = this_group.parents <span class="hljs-comment"># 该权限组继承的权限组们</span><br>parents.add(another_group) <span class="hljs-comment"># 使该权限组继承 another_group</span><br>parents.remove(another_group) <span class="hljs-comment"># 使该权限组不再继承 another_group</span><br><br>this_group.weight = <span class="hljs-number">1</span> <span class="hljs-comment"># 修改该权限组的权重</span><br><br>this_group.members.add(user) <span class="hljs-comment"># 向该权限组添加用户</span><br>this_group.members.remove(user) <span class="hljs-comment"># 从该权限组移除用户</span><br><br>this_group.nodes.add(permission_node) <span class="hljs-comment"># 向该权限组添加权限节点</span><br>this_group.nodes.remove(permission_node) <span class="hljs-comment"># 从该权限组移除权限节点</span><br><br></code></pre></td></tr></table></figure><h3 id="针对单个用户修改权限"><a href="#针对单个用户修改权限" class="headerlink" title="针对单个用户修改权限"></a>针对单个用户修改权限</h3><p>思路是给用户分配一个单独的高权限 Group,再给这个 Group 分配 Node</p><h2 id="代码分享"><a href="#代码分享" class="headerlink" title="代码分享"></a>代码分享</h2><h3 id="models-db-py"><a href="#models-db-py" class="headerlink" title="models/db.py"></a>models/db.py</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> pony.orm <span class="hljs-keyword">import</span> Database<br><br>db = Database()<br><br></code></pre></td></tr></table></figure><h3 id="models-user-py"><a href="#models-user-py" class="headerlink" title="models/user.py"></a>models/user.py</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> pony.orm <span class="hljs-keyword">import</span> Required, <span class="hljs-type">Set</span>, <span class="hljs-type">Optional</span><br><br><span class="hljs-keyword">from</span> .db <span class="hljs-keyword">import</span> db<br><br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">User</span>(db.Entity):<br> <span class="hljs-comment"># You should add fields you need here. </span><br> permission_groups = <span class="hljs-type">Set</span>(<span class="hljs-string">"PermissionGroup"</span>)<br><br></code></pre></td></tr></table></figure><h3 id="models-permission-group-py"><a href="#models-permission-group-py" class="headerlink" title="models/permission_group.py"></a>models/permission_group.py</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> pony.orm <span class="hljs-keyword">import</span> Required, <span class="hljs-type">Set</span>, db_session<br><br><span class="hljs-keyword">from</span> .db <span class="hljs-keyword">import</span> db<br><br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">PermissionGroup</span>(db.Entity):<br> name = Required(<span class="hljs-built_in">str</span>, unique=<span class="hljs-literal">True</span>)<br> weight = Required(<span class="hljs-built_in">int</span>)<br> nodes = <span class="hljs-type">Set</span>(<span class="hljs-string">"PermissionNode"</span>)<br> members = <span class="hljs-type">Set</span>(<span class="hljs-string">"User"</span>)<br> parents = <span class="hljs-type">Set</span>(<span class="hljs-string">"PermissionGroup"</span>, reverse=<span class="hljs-string">"childs"</span>)<br> childs = <span class="hljs-type">Set</span>(<span class="hljs-string">"PermissionGroup"</span>, reverse=<span class="hljs-string">"parents"</span>)<br><br><span class="hljs-meta"> @classmethod</span><br><span class="hljs-meta"> @db_session</span><br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">instance</span>(<span class="hljs-params">cls, name, weight=<span class="hljs-literal">None</span></span>):<br> <span class="hljs-string">"""</span><br><span class="hljs-string"> Return an PermissionGroup instance.</span><br><span class="hljs-string"></span><br><span class="hljs-string"> If a PermissionGroup with the name exists, it will directly return the group,</span><br><span class="hljs-string"> with new weight value. It is noticeable that, if weight is not given, it won't be changed.</span><br><span class="hljs-string"></span><br><span class="hljs-string"> Or, it will create a new PermissionGroup with the given name and weight value.</span><br><span class="hljs-string"> Notice that if the weight is not given here, an ValueError will be thrown.</span><br><span class="hljs-string"></span><br><span class="hljs-string"> """</span><br> result = cls.get(name=name)<br> <span class="hljs-keyword">if</span> result <span class="hljs-keyword">is</span> <span class="hljs-literal">None</span>:<br> <span class="hljs-keyword">if</span> weight <span class="hljs-keyword">is</span> <span class="hljs-literal">None</span>:<br> <span class="hljs-keyword">raise</span> ValueError<br> <span class="hljs-keyword">return</span> cls(name=name, weight=weight)<br> <span class="hljs-keyword">if</span> weight <span class="hljs-keyword">is</span> <span class="hljs-keyword">not</span> <span class="hljs-literal">None</span>:<br> result.weight = weight<br> <span class="hljs-keyword">return</span> result<br><br></code></pre></td></tr></table></figure><h3 id="models-permission-node-py"><a href="#models-permission-node-py" class="headerlink" title="models/permission_node.py"></a>models/permission_node.py</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> pony.orm <span class="hljs-keyword">import</span> Required, db_session<br><br><span class="hljs-keyword">from</span> .db <span class="hljs-keyword">import</span> db<br><span class="hljs-keyword">from</span> .permission_group <span class="hljs-keyword">import</span> PermissionGroup<br><br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">PermissionNode</span>(db.Entity):<br> permission = Required(<span class="hljs-built_in">str</span>)<br> value = Required(<span class="hljs-built_in">bool</span>)<br> owner = Required(PermissionGroup)<br><br></code></pre></td></tr></table></figure><h3 id="permission-init-py"><a href="#permission-init-py" class="headerlink" title="permission/__init__.py"></a>permission/__init__.py</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> queue <span class="hljs-keyword">import</span> Queue<br><br><span class="hljs-keyword">from</span> models <span class="hljs-keyword">import</span> User<br><span class="hljs-keyword">from</span> pony.orm <span class="hljs-keyword">import</span> select<br><br><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">check_permission</span>(<span class="hljs-params">user: User, permission</span>):<br> queue = Queue()<br> weight = <span class="hljs-built_in">float</span>(<span class="hljs-string">"-inf"</span>)<br> value = <span class="hljs-literal">False</span><br> <span class="hljs-keyword">for</span> group <span class="hljs-keyword">in</span> user.permission_groups:<br> queue.put(group)<br> <span class="hljs-keyword">while</span> <span class="hljs-keyword">not</span> queue.empty():<br> group = queue.get()<br> <span class="hljs-keyword">for</span> g <span class="hljs-keyword">in</span> group.parents:<br> queue.put(g)<br> <span class="hljs-keyword">if</span> group.weight < weight:<br> <span class="hljs-keyword">continue</span><br> values = select(node.value <span class="hljs-keyword">for</span> node <span class="hljs-keyword">in</span> group.nodes <span class="hljs-keyword">if</span> node.permission == permission)<br> <span class="hljs-keyword">for</span> v <span class="hljs-keyword">in</span> values:<br> value = v<br> weight = group.weight<br> <span class="hljs-keyword">return</span> value<br><br></code></pre></td></tr></table></figure><h2 id="代码许可"><a href="#代码许可" class="headerlink" title="代码许可"></a>代码许可</h2><p>如无特殊授权,以上代码均以 <a href="https://www.gnu.org/licenses/agpl-3.0.html">GNU AGPLv3</a> 授权</p>]]></content>
<tags>
<tag>cxzlw</tag>
<tag>权限系统</tag>
<tag>Python</tag>
</tags>
</entry>
<entry>
<title>Zerotier 自定义 Planet 后与标准节点互通</title>
<link href="/2023/07/06/zerotier-planet-convert/"/>
<url>/2023/07/06/zerotier-planet-convert/</url>
<content type="html"><![CDATA[<p>由于国内特殊的网络原因<sup id="fnref:1" class="footnote-ref"><a href="#fn:1" rel="footnote"><span class="hint--top hint--rounded" aria-label="不作评价">[1]</span></a></sup>,Zerotier 官方提供的 Planet 用户体验不佳。为此,不少人选择自建私有 Moon,甚至私有 Planet 服务器。然而,正如官方文档<sup id="fnref:2" class="footnote-ref"><a href="#fn:2" rel="footnote"><span class="hint--top hint--rounded" aria-label="[Introduction | ZeroTier Documentation](https://docs.zerotier.com/self-hosting/introduction#:~:text=If%20you%20are%20using%20a%20custom%20root%20setup%2C%20your%20nodes%20won%27t%20be%20able%20to%20find%20standard%20nodes.)如果你使用自定义根配置,你的节点将无法找到其他标准节点。">[2]</span></a></sup>所说,使用私有 Planet 服务器会使你的节点无法找到其他的标准节点。本文试图提出一种方案在使用私有 Planet 服务器的同时与标准节点通信。</p><h2 id="一、生成-moon-json"><a href="#一、生成-moon-json" class="headerlink" title="一、生成 moon.json"></a>一、生成 moon.json</h2><p>这步主要是为了一个模板:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs batch">cd C:\ProgramData\ZeroTier\One<br>zerotier-idtool initmoon identity.public >> planet.json<br></code></pre></td></tr></table></figure><p>得到的 json:</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs json"><span class="hljs-punctuation">{</span><br> <span class="hljs-attr">"id"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"xxx"</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"objtype"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"world"</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"roots"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span><br> <span class="hljs-punctuation">{</span><br> <span class="hljs-attr">"identity"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"xxx"</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"stableEndpoints"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span><span class="hljs-punctuation">]</span><br> <span class="hljs-punctuation">}</span><br> <span class="hljs-punctuation">]</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"signingKey"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"xxx"</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"signingKey_SECRET"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"xxx"</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"updatesMustBeSignedBy"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"xxx"</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"worldType"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"moon"</span><br><span class="hljs-punctuation">}</span><br></code></pre></td></tr></table></figure><h2 id="二、获得官方-Planet-的-identity-和-stableEndpoints"><a href="#二、获得官方-Planet-的-identity-和-stableEndpoints" class="headerlink" title="二、获得官方 Planet 的 identity 和 stableEndpoints"></a>二、获得官方 Planet 的 identity 和 stableEndpoints</h2><p>使用以下代码(照着 attic/world/mkworld.cpp 和 node/Topology.cpp 改的)</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><iostream></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node/C25519.hpp></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node/Identity.hpp></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node/InetAddress.hpp></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><node/World.hpp></span></span><br><br><span class="hljs-meta">#<span class="hljs-keyword">define</span> ZT_DEFAULT_WORLD_LENGTH 570 <span class="hljs-comment">// 这俩行来自 Topology.cpp</span></span><br><span class="hljs-type">static</span> <span class="hljs-type">const</span> <span class="hljs-type">unsigned</span> <span class="hljs-type">char</span> ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {<span class="hljs-number">0x01</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0x08</span>,<span class="hljs-number">0xea</span>,<span class="hljs-number">0xc9</span>,<span class="hljs-number">0x0a</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0x01</span>,<span class="hljs-number">0x7e</span>,<span class="hljs-number">0xe9</span>,<span class="hljs-number">0x57</span>,<span class="hljs-number">0x60</span>,<span class="hljs-number">0xcd</span>,<span class="hljs-number">0xb8</span>,<span class="hljs-number">0xb3</span>,<span class="hljs-number">0x88</span>,<span class="hljs-number">0xa4</span>,<span class="hljs-number">0x69</span>,<span class="hljs-number">0x22</span>,<span class="hljs-number">0x14</span>,<span class="hljs-number">0x91</span>,<span class="hljs-number">0xaa</span>,<span class="hljs-number">0x9a</span>,<span class="hljs-number">0xcd</span>,<span class="hljs-number">0x66</span>,<span class="hljs-number">0xcc</span>,<span class="hljs-number">0x76</span>,<span class="hljs-number">0x4c</span>,<span class="hljs-number">0xde</span>,<span class="hljs-number">0xfd</span>,<span class="hljs-number">0x56</span>,<span class="hljs-number">0x03</span>,<span class="hljs-number">0x9f</span>,<span class="hljs-number">0x10</span>,<span class="hljs-number">0x67</span>,<span class="hljs-number">0xae</span>,<span class="hljs-number">0x15</span>,<span class="hljs-number">0xe6</span>,<span class="hljs-number">0x9c</span>,<span class="hljs-number">0x6f</span>,<span class="hljs-number">0xb4</span>,<span class="hljs-number">0x2d</span>,<span class="hljs-number">0x7b</span>,<span class="hljs-number">0x55</span>,<span class="hljs-number">0x33</span>,<span class="hljs-number">0x0e</span>,<span class="hljs-number">0x3f</span>,<span class="hljs-number">0xda</span>,<span class="hljs-number">0xac</span>,<span class="hljs-number">0x52</span>,<span class="hljs-number">0x9c</span>,<span class="hljs-number">0x07</span>,<span class="hljs-number">0x92</span>,<span class="hljs-number">0xfd</span>,<span class="hljs-number">0x73</span>,<span class="hljs-number">0x40</span>,<span class="hljs-number">0xa6</span>,<span class="hljs-number">0xaa</span>,<span class="hljs-number">0x21</span>,<span class="hljs-number">0xab</span>,<span class="hljs-number">0xa8</span>,<span class="hljs-number">0xa4</span>,<span class="hljs-number">0x89</span>,<span class="hljs-number">0xfd</span>,<span class="hljs-number">0xae</span>,<span class="hljs-number">0xa4</span>,<span class="hljs-number">0x4a</span>,<span class="hljs-number">0x39</span>,<span class="hljs-number">0xbf</span>,<span class="hljs-number">0x2d</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0x65</span>,<span class="hljs-number">0x9a</span>,<span class="hljs-number">0xc9</span>,<span class="hljs-number">0xc8</span>,<span class="hljs-number">0x18</span>,<span class="hljs-number">0xeb</span>,<span class="hljs-number">0x36</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0x92</span>,<span class="hljs-number">0x76</span>,<span class="hljs-number">0x37</span>,<span class="hljs-number">0xef</span>,<span class="hljs-number">0x4d</span>,<span class="hljs-number">0x14</span>,<span class="hljs-number">0x04</span>,<span class="hljs-number">0xa4</span>,<span class="hljs-number">0x4d</span>,<span class="hljs-number">0x54</span>,<span class="hljs-number">0x46</span>,<span class="hljs-number">0x84</span>,<span class="hljs-number">0x85</span>,<span class="hljs-number">0x13</span>,<span class="hljs-number">0x79</span>,<span class="hljs-number">0x75</span>,<span class="hljs-number">0x1f</span>,<span class="hljs-number">0xaa</span>,<span class="hljs-number">0x79</span>,<span class="hljs-number">0xb4</span>,<span class="hljs-number">0xc4</span>,<span class="hljs-number">0xea</span>,<span class="hljs-number">0x85</span>,<span class="hljs-number">0x04</span>,<span class="hljs-number">0x01</span>,<span class="hljs-number">0x75</span>,<span class="hljs-number">0xea</span>,<span class="hljs-number">0x06</span>,<span class="hljs-number">0x58</span>,<span class="hljs-number">0x60</span>,<span class="hljs-number">0x48</span>,<span class="hljs-number">0x24</span>,<span class="hljs-number">0x02</span>,<span class="hljs-number">0xe1</span>,<span class="hljs-number">0xeb</span>,<span class="hljs-number">0x34</span>,<span class="hljs-number">0x20</span>,<span class="hljs-number">0x52</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0x0e</span>,<span class="hljs-number">0x62</span>,<span class="hljs-number">0x90</span>,<span class="hljs-number">0x06</span>,<span class="hljs-number">0x1a</span>,<span class="hljs-number">0x9b</span>,<span class="hljs-number">0xe0</span>,<span class="hljs-number">0xcd</span>,<span class="hljs-number">0x29</span>,<span class="hljs-number">0x3c</span>,<span class="hljs-number">0x8b</span>,<span class="hljs-number">0x55</span>,<span class="hljs-number">0xf1</span>,<span class="hljs-number">0xc3</span>,<span class="hljs-number">0xd2</span>,<span class="hljs-number">0x52</span>,<span class="hljs-number">0x48</span>,<span class="hljs-number">0x08</span>,<span class="hljs-number">0xaf</span>,<span class="hljs-number">0xc5</span>,<span class="hljs-number">0x49</span>,<span class="hljs-number">0x22</span>,<span class="hljs-number">0x08</span>,<span class="hljs-number">0x0e</span>,<span class="hljs-number">0x35</span>,<span class="hljs-number">0x39</span>,<span class="hljs-number">0xa7</span>,<span class="hljs-number">0x5a</span>,<span class="hljs-number">0xdd</span>,<span class="hljs-number">0xc3</span>,<span class="hljs-number">0xce</span>,<span class="hljs-number">0xf0</span>,<span class="hljs-number">0xf6</span>,<span class="hljs-number">0xad</span>,<span class="hljs-number">0x26</span>,<span class="hljs-number">0x0d</span>,<span class="hljs-number">0x58</span>,<span class="hljs-number">0x82</span>,<span class="hljs-number">0x93</span>,<span class="hljs-number">0xbb</span>,<span class="hljs-number">0x77</span>,<span class="hljs-number">0x86</span>,<span class="hljs-number">0xe7</span>,<span class="hljs-number">0x1e</span>,<span class="hljs-number">0xfa</span>,<span class="hljs-number">0x4b</span>,<span class="hljs-number">0x90</span>,<span class="hljs-number">0x57</span>,<span class="hljs-number">0xda</span>,<span class="hljs-number">0xd9</span>,<span class="hljs-number">0x86</span>,<span class="hljs-number">0x7a</span>,<span class="hljs-number">0xfe</span>,<span class="hljs-number">0x12</span>,<span class="hljs-number">0xdd</span>,<span class="hljs-number">0x04</span>,<span class="hljs-number">0xca</span>,<span class="hljs-number">0xfe</span>,<span class="hljs-number">0x9e</span>,<span class="hljs-number">0xfe</span>,<span class="hljs-number">0xb9</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0xcc</span>,<span class="hljs-number">0xde</span>,<span class="hljs-number">0xf7</span>,<span class="hljs-number">0x6b</span>,<span class="hljs-number">0xc7</span>,<span class="hljs-number">0xb9</span>,<span class="hljs-number">0x7d</span>,<span class="hljs-number">0xed</span>,<span class="hljs-number">0x90</span>,<span class="hljs-number">0x4e</span>,<span class="hljs-number">0xab</span>,<span class="hljs-number">0xc5</span>,<span class="hljs-number">0xdf</span>,<span class="hljs-number">0x09</span>,<span class="hljs-number">0x88</span>,<span class="hljs-number">0x6d</span>,<span class="hljs-number">0x9c</span>,<span class="hljs-number">0x15</span>,<span class="hljs-number">0x14</span>,<span class="hljs-number">0xa6</span>,<span class="hljs-number">0x10</span>,<span class="hljs-number">0x03</span>,<span class="hljs-number">0x6c</span>,<span class="hljs-number">0xb9</span>,<span class="hljs-number">0x13</span>,<span class="hljs-number">0x9c</span>,<span class="hljs-number">0xc2</span>,<span class="hljs-number">0x14</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0x1a</span>,<span class="hljs-number">0x29</span>,<span class="hljs-number">0x58</span>,<span class="hljs-number">0x97</span>,<span class="hljs-number">0x8e</span>,<span class="hljs-number">0xfc</span>,<span class="hljs-number">0xec</span>,<span class="hljs-number">0x15</span>,<span class="hljs-number">0x71</span>,<span class="hljs-number">0x2d</span>,<span class="hljs-number">0xd3</span>,<span class="hljs-number">0x94</span>,<span class="hljs-number">0x8c</span>,<span class="hljs-number">0x6e</span>,<span class="hljs-number">0x6b</span>,<span class="hljs-number">0x3a</span>,<span class="hljs-number">0x8e</span>,<span class="hljs-number">0x89</span>,<span class="hljs-number">0x3d</span>,<span class="hljs-number">0xf0</span>,<span class="hljs-number">0x1f</span>,<span class="hljs-number">0xf4</span>,<span class="hljs-number">0x93</span>,<span class="hljs-number">0xd1</span>,<span class="hljs-number">0xf8</span>,<span class="hljs-number">0xd9</span>,<span class="hljs-number">0x80</span>,<span class="hljs-number">0x6a</span>,<span class="hljs-number">0x86</span>,<span class="hljs-number">0x0c</span>,<span class="hljs-number">0x54</span>,<span class="hljs-number">0x20</span>,<span class="hljs-number">0x57</span>,<span class="hljs-number">0x1b</span>,<span class="hljs-number">0xf0</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0x02</span>,<span class="hljs-number">0x04</span>,<span class="hljs-number">0x68</span>,<span class="hljs-number">0xc2</span>,<span class="hljs-number">0x08</span>,<span class="hljs-number">0x86</span>,<span class="hljs-number">0x27</span>,<span class="hljs-number">0x09</span>,<span class="hljs-number">0x06</span>,<span class="hljs-number">0x26</span>,<span class="hljs-number">0x05</span>,<span class="hljs-number">0x98</span>,<span class="hljs-number">0x80</span>,<span class="hljs-number">0x02</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0x12</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0x30</span>,<span class="hljs-number">0x05</span>,<span class="hljs-number">0x71</span>,<span class="hljs-number">0x0e</span>,<span class="hljs-number">0x34</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0x51</span>,<span class="hljs-number">0x27</span>,<span class="hljs-number">0x09</span>,<span class="hljs-number">0x77</span>,<span class="hljs-number">0x8c</span>,<span class="hljs-number">0xde</span>,<span class="hljs-number">0x71</span>,<span class="hljs-number">0x90</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0x3f</span>,<span class="hljs-number">0x66</span>,<span class="hljs-number">0x81</span>,<span class="hljs-number">0xa9</span>,<span class="hljs-number">0x9e</span>,<span class="hljs-number">0x5a</span>,<span class="hljs-number">0xd1</span>,<span class="hljs-number">0x89</span>,<span class="hljs-number">0x5e</span>,<span class="hljs-number">0x9f</span>,<span class="hljs-number">0xba</span>,<span class="hljs-number">0x33</span>,<span class="hljs-number">0xe6</span>,<span class="hljs-number">0x21</span>,<span class="hljs-number">0x2d</span>,<span class="hljs-number">0x44</span>,<span class="hljs-number">0x54</span>,<span class="hljs-number">0xe1</span>,<span class="hljs-number">0x68</span>,<span class="hljs-number">0xbc</span>,<span class="hljs-number">0xec</span>,<span class="hljs-number">0x71</span>,<span class="hljs-number">0x12</span>,<span class="hljs-number">0x10</span>,<span class="hljs-number">0x1b</span>,<span class="hljs-number">0xf0</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0x95</span>,<span class="hljs-number">0x6e</span>,<span class="hljs-number">0xd8</span>,<span class="hljs-number">0xe9</span>,<span class="hljs-number">0x2e</span>,<span class="hljs-number">0x42</span>,<span class="hljs-number">0x89</span>,<span class="hljs-number">0x2c</span>,<span class="hljs-number">0xb6</span>,<span class="hljs-number">0xf2</span>,<span class="hljs-number">0xec</span>,<span class="hljs-number">0x41</span>,<span class="hljs-number">0x08</span>,<span class="hljs-number">0x81</span>,<span class="hljs-number">0xa8</span>,<span class="hljs-number">0x4a</span>,<span class="hljs-number">0xb1</span>,<span class="hljs-number">0x9d</span>,<span class="hljs-number">0xa5</span>,<span class="hljs-number">0x0e</span>,<span class="hljs-number">0x12</span>,<span class="hljs-number">0x87</span>,<span class="hljs-number">0xba</span>,<span class="hljs-number">0x3d</span>,<span class="hljs-number">0x92</span>,<span class="hljs-number">0x6c</span>,<span class="hljs-number">0x3a</span>,<span class="hljs-number">0x1f</span>,<span class="hljs-number">0x75</span>,<span class="hljs-number">0x5c</span>,<span class="hljs-number">0xcc</span>,<span class="hljs-number">0xf2</span>,<span class="hljs-number">0x99</span>,<span class="hljs-number">0xa1</span>,<span class="hljs-number">0x20</span>,<span class="hljs-number">0x70</span>,<span class="hljs-number">0x55</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0x02</span>,<span class="hljs-number">0x04</span>,<span class="hljs-number">0x67</span>,<span class="hljs-number">0xc3</span>,<span class="hljs-number">0x67</span>,<span class="hljs-number">0x42</span>,<span class="hljs-number">0x27</span>,<span class="hljs-number">0x09</span>,<span class="hljs-number">0x06</span>,<span class="hljs-number">0x26</span>,<span class="hljs-number">0x05</span>,<span class="hljs-number">0x98</span>,<span class="hljs-number">0x80</span>,<span class="hljs-number">0x04</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0xc3</span>,<span class="hljs-number">0x02</span>,<span class="hljs-number">0x54</span>,<span class="hljs-number">0xf2</span>,<span class="hljs-number">0xbc</span>,<span class="hljs-number">0xa1</span>,<span class="hljs-number">0xf7</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0x19</span>,<span class="hljs-number">0x27</span>,<span class="hljs-number">0x09</span>,<span class="hljs-number">0x62</span>,<span class="hljs-number">0xf8</span>,<span class="hljs-number">0x65</span>,<span class="hljs-number">0xae</span>,<span class="hljs-number">0x71</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0xe2</span>,<span class="hljs-number">0x07</span>,<span class="hljs-number">0x6c</span>,<span class="hljs-number">0x57</span>,<span class="hljs-number">0xde</span>,<span class="hljs-number">0x87</span>,<span class="hljs-number">0x0e</span>,<span class="hljs-number">0x62</span>,<span class="hljs-number">0x88</span>,<span class="hljs-number">0xd7</span>,<span class="hljs-number">0xd5</span>,<span class="hljs-number">0xe7</span>,<span class="hljs-number">0x40</span>,<span class="hljs-number">0x44</span>,<span class="hljs-number">0x08</span>,<span class="hljs-number">0xb1</span>,<span class="hljs-number">0x54</span>,<span class="hljs-number">0x5e</span>,<span class="hljs-number">0xfc</span>,<span class="hljs-number">0xa3</span>,<span class="hljs-number">0x7d</span>,<span class="hljs-number">0x67</span>,<span class="hljs-number">0xf7</span>,<span class="hljs-number">0x7b</span>,<span class="hljs-number">0x87</span>,<span class="hljs-number">0xe9</span>,<span class="hljs-number">0xe5</span>,<span class="hljs-number">0x41</span>,<span class="hljs-number">0x68</span>,<span class="hljs-number">0xc2</span>,<span class="hljs-number">0x5d</span>,<span class="hljs-number">0x3e</span>,<span class="hljs-number">0xf1</span>,<span class="hljs-number">0xa9</span>,<span class="hljs-number">0xab</span>,<span class="hljs-number">0xf2</span>,<span class="hljs-number">0x90</span>,<span class="hljs-number">0x5e</span>,<span class="hljs-number">0xa5</span>,<span class="hljs-number">0xe7</span>,<span class="hljs-number">0x85</span>,<span class="hljs-number">0xc0</span>,<span class="hljs-number">0x1d</span>,<span class="hljs-number">0xff</span>,<span class="hljs-number">0x23</span>,<span class="hljs-number">0x88</span>,<span class="hljs-number">0x7a</span>,<span class="hljs-number">0xd4</span>,<span class="hljs-number">0x23</span>,<span class="hljs-number">0x2d</span>,<span class="hljs-number">0x95</span>,<span class="hljs-number">0xc7</span>,<span class="hljs-number">0xa8</span>,<span class="hljs-number">0xfd</span>,<span class="hljs-number">0x2c</span>,<span class="hljs-number">0x27</span>,<span class="hljs-number">0x11</span>,<span class="hljs-number">0x1a</span>,<span class="hljs-number">0x72</span>,<span class="hljs-number">0xbd</span>,<span class="hljs-number">0x15</span>,<span class="hljs-number">0x93</span>,<span class="hljs-number">0x22</span>,<span class="hljs-number">0xdc</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0x02</span>,<span class="hljs-number">0x04</span>,<span class="hljs-number">0x32</span>,<span class="hljs-number">0x07</span>,<span class="hljs-number">0xfc</span>,<span class="hljs-number">0x8a</span>,<span class="hljs-number">0x27</span>,<span class="hljs-number">0x09</span>,<span class="hljs-number">0x06</span>,<span class="hljs-number">0x20</span>,<span class="hljs-number">0x01</span>,<span class="hljs-number">0x49</span>,<span class="hljs-number">0xf0</span>,<span class="hljs-number">0xd0</span>,<span class="hljs-number">0xdb</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0x02</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0x02</span>,<span class="hljs-number">0x27</span>,<span class="hljs-number">0x09</span>,<span class="hljs-number">0xca</span>,<span class="hljs-number">0xfe</span>,<span class="hljs-number">0x04</span>,<span class="hljs-number">0xeb</span>,<span class="hljs-number">0xa9</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0x6c</span>,<span class="hljs-number">0x6a</span>,<span class="hljs-number">0x9d</span>,<span class="hljs-number">0x1d</span>,<span class="hljs-number">0xea</span>,<span class="hljs-number">0x55</span>,<span class="hljs-number">0xc1</span>,<span class="hljs-number">0x61</span>,<span class="hljs-number">0x6b</span>,<span class="hljs-number">0xfe</span>,<span class="hljs-number">0x2a</span>,<span class="hljs-number">0x2b</span>,<span class="hljs-number">0x8f</span>,<span class="hljs-number">0x0f</span>,<span class="hljs-number">0xf9</span>,<span class="hljs-number">0xa8</span>,<span class="hljs-number">0xca</span>,<span class="hljs-number">0xca</span>,<span class="hljs-number">0xf7</span>,<span class="hljs-number">0x03</span>,<span class="hljs-number">0x74</span>,<span class="hljs-number">0xfb</span>,<span class="hljs-number">0x1f</span>,<span class="hljs-number">0x39</span>,<span class="hljs-number">0xe3</span>,<span class="hljs-number">0xbe</span>,<span class="hljs-number">0xf8</span>,<span class="hljs-number">0x1c</span>,<span class="hljs-number">0xbf</span>,<span class="hljs-number">0xeb</span>,<span class="hljs-number">0xef</span>,<span class="hljs-number">0x17</span>,<span class="hljs-number">0xb7</span>,<span class="hljs-number">0x22</span>,<span class="hljs-number">0x82</span>,<span class="hljs-number">0x68</span>,<span class="hljs-number">0xa0</span>,<span class="hljs-number">0xa2</span>,<span class="hljs-number">0xa2</span>,<span class="hljs-number">0x9d</span>,<span class="hljs-number">0x34</span>,<span class="hljs-number">0x88</span>,<span class="hljs-number">0xc7</span>,<span class="hljs-number">0x52</span>,<span class="hljs-number">0x56</span>,<span class="hljs-number">0x5c</span>,<span class="hljs-number">0x6c</span>,<span class="hljs-number">0x96</span>,<span class="hljs-number">0x5c</span>,<span class="hljs-number">0xbd</span>,<span class="hljs-number">0x65</span>,<span class="hljs-number">0x06</span>,<span class="hljs-number">0xec</span>,<span class="hljs-number">0x24</span>,<span class="hljs-number">0x39</span>,<span class="hljs-number">0x7c</span>,<span class="hljs-number">0xc8</span>,<span class="hljs-number">0xa5</span>,<span class="hljs-number">0xd9</span>,<span class="hljs-number">0xd1</span>,<span class="hljs-number">0x52</span>,<span class="hljs-number">0x85</span>,<span class="hljs-number">0xa8</span>,<span class="hljs-number">0x7f</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0x02</span>,<span class="hljs-number">0x04</span>,<span class="hljs-number">0x54</span>,<span class="hljs-number">0x11</span>,<span class="hljs-number">0x35</span>,<span class="hljs-number">0x9b</span>,<span class="hljs-number">0x27</span>,<span class="hljs-number">0x09</span>,<span class="hljs-number">0x06</span>,<span class="hljs-number">0x2a</span>,<span class="hljs-number">0x02</span>,<span class="hljs-number">0x6e</span>,<span class="hljs-number">0xa0</span>,<span class="hljs-number">0xd4</span>,<span class="hljs-number">0x05</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0x00</span>,<span class="hljs-number">0x99</span>,<span class="hljs-number">0x93</span>,<span class="hljs-number">0x27</span>,<span class="hljs-number">0x09</span>};<br><br><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> ZeroTier;<br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span><br><span class="hljs-function"></span>{<br>World world;<br>world.<span class="hljs-built_in">deserialize</span>(<span class="hljs-built_in">Buffer</span><ZT_DEFAULT_WORLD_LENGTH>(ZT_DEFAULT_WORLD, ZT_DEFAULT_WORLD_LENGTH), <span class="hljs-number">0</span>);<br><br><span class="hljs-keyword">for</span> (<span class="hljs-type">const</span> <span class="hljs-keyword">auto</span>& root : world.<span class="hljs-built_in">roots</span>()) {<br><span class="hljs-type">char</span> buf[ZT_IDENTITY_STRING_BUFFER_LENGTH];<br>std::cout << root.identity.<span class="hljs-built_in">toString</span>(<span class="hljs-literal">false</span>, buf) << <span class="hljs-string">"\n"</span>;<br><span class="hljs-keyword">for</span> (<span class="hljs-type">const</span> <span class="hljs-keyword">auto</span>& sp : root.stableEndpoints) {<br><span class="hljs-type">char</span> buf2[ZT_IDENTITY_STRING_BUFFER_LENGTH];<br>std::cout << sp.<span class="hljs-built_in">toString</span>(buf2) << <span class="hljs-string">"\n"</span>;<br>}<br>std::cout << <span class="hljs-string">"\n"</span>;<br>}<br>}<br></code></pre></td></tr></table></figure><p>以上代码发布在<a href="https://github.com/cxzlw/ZeroTierOne/blob/dev/attic/world/read_planet.cpp">ZeroTierOne/attic/world/read_planet.cpp at dev · cxzlw/ZeroTierOne · GitHub</a>。</p><p>运行结果如下:</p><figure class="highlight apache"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs apache"><span class="hljs-attribute">cafe9efeb9</span>:<span class="hljs-number">0</span>:ccdef76bc7b97ded904eabc5df09886d9c1514a610036cb9139cc214001a2958978efcec15712dd3948c6e6b3a8e893df01ff493d1f8d9806a860c5420571bf0<br><span class="hljs-attribute">104</span>.<span class="hljs-number">194</span>.<span class="hljs-number">8</span>.<span class="hljs-number">134</span>/<span class="hljs-number">9993</span><br><span class="hljs-attribute">2605</span>:<span class="hljs-number">9880</span>:<span class="hljs-number">200</span>:<span class="hljs-number">1200</span>:<span class="hljs-number">30</span>:<span class="hljs-number">571</span>:e34:<span class="hljs-number">51</span>/<span class="hljs-number">9993</span><br><br><span class="hljs-attribute">778cde7190</span>:<span class="hljs-number">0</span>:<span class="hljs-number">3</span>f6681a99e5ad1895e9fba33e6212d4454e168bcec7112101bf000956ed8e92e42892cb6f2ec410881a84ab19da50e1287ba3d926c3a1f755cccf299a1207055<br><span class="hljs-attribute">103</span>.<span class="hljs-number">195</span>.<span class="hljs-number">103</span>.<span class="hljs-number">66</span>/<span class="hljs-number">9993</span><br><span class="hljs-attribute">2605</span>:<span class="hljs-number">9880</span>:<span class="hljs-number">400</span>:c3:<span class="hljs-number">254</span>:f2bc:a1f7:<span class="hljs-number">19</span>/<span class="hljs-number">9993</span><br><br><span class="hljs-attribute">62f865ae71</span>:<span class="hljs-number">0</span>:e2076c57de870e6288d7d5e7404408b1545efca37d67f77b87e9e54168c25d3ef1a9abf2905ea5e785c01dff23887ad4232d95c7a8fd2c27111a72bd159322dc<br><span class="hljs-attribute">50</span>.<span class="hljs-number">7</span>.<span class="hljs-number">252</span>.<span class="hljs-number">138</span>/<span class="hljs-number">9993</span><br><span class="hljs-attribute">2001</span>:<span class="hljs-number">49</span>f0:d0db:<span class="hljs-number">2</span>::<span class="hljs-number">2</span>/<span class="hljs-number">9993</span><br><br><span class="hljs-attribute">cafe04eba9</span>:<span class="hljs-number">0</span>:<span class="hljs-number">6</span>c6a9d1dea55c1616bfe2a2b8f0ff9a8cacaf70374fb1f39e3bef81cbfebef17b7228268a0a2a29d3488c752565c6c965cbd6506ec24397cc8a5d9d15285a87f<br><span class="hljs-attribute">84</span>.<span class="hljs-number">17</span>.<span class="hljs-number">53</span>.<span class="hljs-number">155</span>/<span class="hljs-number">9993</span><br><span class="hljs-attribute">2a02</span>:<span class="hljs-number">6</span>ea0:d405::<span class="hljs-number">9993</span>/<span class="hljs-number">9993</span><br></code></pre></td></tr></table></figure><h2 id="三、按照上述结果修改-moon-json"><a href="#三、按照上述结果修改-moon-json" class="headerlink" title="三、按照上述结果修改 moon.json"></a>三、按照上述结果修改 moon.json</h2><p>大概修改成这样</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><code class="hljs json"><span class="hljs-punctuation">{</span><br> <span class="hljs-attr">"id"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"cafe9efeb9"</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"objtype"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"world"</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"roots"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span><br> <span class="hljs-punctuation">{</span><br> <span class="hljs-attr">"identity"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"cafe9efeb9:0:ccdef76bc7b97ded904eabc5df09886d9c1514a610036cb9139cc214001a2958978efcec15712dd3948c6e6b3a8e893df01ff493d1f8d9806a860c5420571bf0"</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"stableEndpoints"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span><span class="hljs-string">"104.194.8.134/9993"</span><span class="hljs-punctuation">,</span> <span class="hljs-string">"2605:9880:200:1200:30:571:e34:51/9993"</span><span class="hljs-punctuation">]</span><br> <span class="hljs-punctuation">}</span><span class="hljs-punctuation">,</span> <br> <span class="hljs-punctuation">{</span><br> <span class="hljs-attr">"identity"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"778cde7190:0:3f6681a99e5ad1895e9fba33e6212d4454e168bcec7112101bf000956ed8e92e42892cb6f2ec410881a84ab19da50e1287ba3d926c3a1f755cccf299a1207055"</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"stableEndpoints"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span><span class="hljs-string">"103.195.103.66/9993"</span><span class="hljs-punctuation">,</span> <span class="hljs-string">"2605:9880:400:c3:254:f2bc:a1f7:19/9993"</span><span class="hljs-punctuation">]</span><br> <span class="hljs-punctuation">}</span><span class="hljs-punctuation">,</span> <br> <span class="hljs-punctuation">{</span><br> <span class="hljs-attr">"identity"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"62f865ae71:0:e2076c57de870e6288d7d5e7404408b1545efca37d67f77b87e9e54168c25d3ef1a9abf2905ea5e785c01dff23887ad4232d95c7a8fd2c27111a72bd159322dc"</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"stableEndpoints"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span><span class="hljs-string">"50.7.252.138/9993"</span><span class="hljs-punctuation">,</span> <span class="hljs-string">"2001:49f0:d0db:2::2/9993"</span><span class="hljs-punctuation">]</span><br> <span class="hljs-punctuation">}</span><span class="hljs-punctuation">,</span> <br> <span class="hljs-punctuation">{</span><br> <span class="hljs-attr">"identity"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"cafe04eba9:0:6c6a9d1dea55c1616bfe2a2b8f0ff9a8cacaf70374fb1f39e3bef81cbfebef17b7228268a0a2a29d3488c752565c6c965cbd6506ec24397cc8a5d9d15285a87f"</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"stableEndpoints"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span><span class="hljs-string">"84.17.53.155/9993"</span><span class="hljs-punctuation">,</span> <span class="hljs-string">"2a02:6ea0:d405::9993/9993"</span><span class="hljs-punctuation">]</span><br> <span class="hljs-punctuation">}</span><br> <span class="hljs-punctuation">]</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"signingKey"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"xxx"</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"signingKey_SECRET"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"xxx"</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"updatesMustBeSignedBy"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"xxx"</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"worldType"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"moon"</span><br><span class="hljs-punctuation">}</span><br></code></pre></td></tr></table></figure><h2 id="四、生成-moon-文件"><a href="#四、生成-moon-文件" class="headerlink" title="四、生成 .moon 文件"></a>四、生成 .moon 文件</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">zerotier-idtool genmoon moon.json<br></code></pre></td></tr></table></figure><h2 id="五、使用-moon-文件"><a href="#五、使用-moon-文件" class="headerlink" title="五、使用 .moon 文件"></a>五、使用 .moon 文件</h2><p>在 Zerotier 目录<sup id="fnref:3" class="footnote-ref"><a href="#fn:3" rel="footnote"><span class="hint--top hint--rounded" aria-label="Linux 是 `/var/lib/zerotier-one`,Windows 是 `C:\ProgramData\ZeroTier\One\`。">[3]</span></a></sup>下新建文件夹 moons.d。</p><p>把生成的 xxxxxxxxxxxxxxxx.moon 放到你的 moons.d文件夹。</p><p>重启 Zerotier 服务(不会重启的建议重启电脑)。</p><p>这样就好了,你可以开始享用你的自定义 Planet 带来的低延迟体验和官方 Planet 上大量的节点了。</p><h2 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h2><p>在这篇文章中,我们通过将 Zerotier 自带的 Planet 转为 Moon 来进行连接,以帮助使用自定义 Planet 的节点与官方 Planet 上的节点进行通信。这方便了我们在使用低延迟的自建 Planet 的同时与大量标准节点进行通信。</p><h2 id="注"><a href="#注" class="headerlink" title="注"></a>注</h2><section class="footnotes"><div class="footnote-list"><ol><li><span id="fn:1" class="footnote-text"><span>不作评价<a href="#fnref:1" rev="footnote" class="footnote-backref"> ↩</a></span></span></li><li><span id="fn:2" class="footnote-text"><span><a href="https://docs.zerotier.com/self-hosting/introduction#:~:text=If%20you%20are%20using%20a%20custom%20root%20setup%2C%20your%20nodes%20won%27t%20be%20able%20to%20find%20standard%20nodes.">Introduction | ZeroTier Documentation</a>如果你使用自定义根配置,你的节点将无法找到其他标准节点。<a href="#fnref:2" rev="footnote" class="footnote-backref"> ↩</a></span></span></li><li><span id="fn:3" class="footnote-text"><span>Linux 是 <code>/var/lib/zerotier-one</code>,Windows 是 <code>C:\ProgramData\ZeroTier\One\</code>。<a href="#fnref:3" rev="footnote" class="footnote-backref"> ↩</a></span></span></li></ol></div></section>]]></content>
<tags>
<tag>cxzlw</tag>
<tag>Zerotier</tag>
<tag>自建 Planet</tag>
</tags>
</entry>
<entry>
<title>聊聊知乎盐选反爬 (回答页篇)</title>
<link href="/2023/07/05/zhihu-aac-old/"/>
<url>/2023/07/05/zhihu-aac-old/</url>
<content type="html"><![CDATA[<p>最近,知乎上线了针对专栏<sup id="fnref:1" class="footnote-ref"><a href="#fn:1" rel="footnote"><span class="hint--top hint--rounded" aria-label="专栏反爬现已更新,故本文只以回答反爬为演示。">[1]</span></a></sup>中盐选文章的反爬系统,随后该系统也被运用在知乎回答页面中的盐选文章上。具体表现为爬取的文章内容中出现大量的错乱词汇。而在本篇文章中,我们将一步步带领各位解开这些乱码。在这个过程中,我们将对字体反爬有更深入的认识,并学到运用字体反爬时需要注意的问题。</p><h2 id="一、知乎反爬效果"><a href="#一、知乎反爬效果" class="headerlink" title="一、知乎反爬效果"></a>一、知乎反爬效果</h2><p>来自知乎回答<a href="https://www.zhihu.com/question/41922324/answer/3073556909">不被爱是一种什么样的感受? - 知乎</a></p><p><img src="/../img/image.webp" alt="乱码示意图"> </p><p>如图所示,在页面源码中出现了大量乱码,例如(原字,错字):<sup id="fnref:2" class="footnote-ref"><a href="#fn:2" rel="footnote"><span class="hint--top hint--rounded" aria-label="由于知乎回答页反爬使用了两套字体,故本文所有截图,代码运行结果等内容可能与实际不符。你可以选择以实际为主或刷新页面直到页面显示的内容与本文一致。">[2]</span></a></sup></p><ul><li>中 -> 在</li><li>是 -> 时</li><li>上 -> 大</li></ul><p>这些乱码使得文章可读性大大下降,那么乱码是怎么产生的?又如何解决这个问题呢?</p><h2 id="二、找寻乱码真凶"><a href="#二、找寻乱码真凶" class="headerlink" title="二、找寻乱码真凶"></a>二、找寻乱码真凶</h2><p>观察上述现象,页面源码中的字,在被显示到页面后,居然变成了正确的字。因此我们初步推断知乎在该页面运用了字体反爬。</p><p>接下来我们打开 F12 -> Network 页面,选择 Font,观察知乎加载的字体。</p><p><img src="/../img/image-1.png" alt="知乎加载的字体"></p><p>右键选择 Open in new tab 将字体保存下来。</p><p><img src="/../img/image-2.png" alt="下载的字体文件"></p><p>将字体后缀名改为 .ttf <sup id="fnref:3" class="footnote-ref"><a href="#fn:3" rel="footnote"><span class="hint--top hint--rounded" aria-label=".ttf 是因为 `data:font/ttf;...` 代表该字体是 ttf 格式的。">[3]</span></a></sup> 并打开。</p><div class="group-image-container"><div class="group-image-row"><div class="group-image-wrap"><img src="/../img/image-3.png" alt="正常字体"></div><div class="group-image-wrap"><img src="/../img/image-4.png" alt="反爬字体"></div></div></div><figcaption aria-hidden="true" class="image-caption">左:正常字体 右:反爬字体</figcaption><p>与正常字体对比,我们下载的字体明显替换了部分字体,这便是知乎用于反爬的字体了。接下来我们将分析这个字体并给出应对方案。</p><h2 id="三、致命缺陷"><a href="#三、致命缺陷" class="headerlink" title="三、致命缺陷"></a>三、致命缺陷</h2><p>字体反爬的根本原理是替换原本的字为一个新字,再用字体将新字渲染为原字,这样对程序而言就只见到新字而不是旧字了,而用户看到的还是原本的内容。因此只要找到新字与原字间的对应关系便可解决该反爬。而要找到这个对应关系,抓住字体中各个字形的特征是必不可少的一环。</p><p>我们打开 <a href="https://fontdrop.info/">FontDrop!</a> 加载字体,向下翻,观察字形的特征。</p><p><img src="/../img/image-5.png" alt="字体中的字形"></p><p>我们发现字形的 Glyph 为 uni662F 而 Unicode 为 65F6,接下来我们试着查询这两个十六进制数对应的字:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs python">glyph = <span class="hljs-string">"\u662F"</span><br>unicode = <span class="hljs-string">"\u65F6"</span><br><span class="hljs-built_in">print</span>(glyph, unicode)<br><span class="hljs-comment"># output: 是 时</span><br></code></pre></td></tr></table></figure><p>正好,上文提到,「是」在源码中被替换为了「时」。知乎在反爬字体中保留了原字与新字的对应关系,为我们提供了一个极为便捷的捷径。我们可以直接读取这个对应关系,而不是比对每个字的笔画<sup id="fnref:4" class="footnote-ref"><a href="#fn:4" rel="footnote"><span class="hint--top hint--rounded" aria-label="基于笔画比对的反爬破解见该文章:[字体反爬之汽车之家_51CTO博客_汽车之家字体反爬](https://blog.51cto.com/u_15289428/2992542)(话说这篇文章和下面注 9 是一个网站吧)">[4]</span></a></sup>。然而,这也是其字体反爬系统的致命缺陷,各位在自己的网站运用字体反爬时也要注意这一点。</p><p>至此,字形的特征与对应关系都被我们分析出了,接下来我们将编写程序从字体中提取对应关系。</p><h2 id="四、提取对应关系"><a href="#四、提取对应关系" class="headerlink" title="四、提取对应关系"></a>四、提取对应关系</h2><p>要提取各个字间的对应关系,首先我们需要安装 fontTools <sup id="fnref:5" class="footnote-ref"><a href="#fn:5" rel="footnote"><span class="hint--top hint--rounded" aria-label="fontTools文档:[fontTools Docs — fontTools Documentation](https://fonttools.readthedocs.io/en/latest/)">[5]</span></a></sup>。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">pip install fonttools<br></code></pre></td></tr></table></figure><p>用 <code>ttLib.TTFont(filename)</code> 打开字体:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> fontTools <span class="hljs-keyword">import</span> ttLib<br><br>font = ttLib.TTFont(<span class="hljs-built_in">input</span>(<span class="hljs-string">"Input font filename: "</span>))<br></code></pre></td></tr></table></figure><p>初始化一个存储对应关系的字典:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs python">zhihu_dict = {}<br></code></pre></td></tr></table></figure><p>遍历字形,获得其 Glyph 与 Unicode,并写入字典(注意这里的Glyph对应的字可能不是标准的字,比如是康熙部首<sup id="fnref:6" class="footnote-ref"><a href="#fn:6" rel="footnote"><span class="hint--top hint--rounded" aria-label="康熙部首相关文章:[康熙部首导致的字典查询异常](https://mp.weixin.qq.com/s?src=11×tamp=1688488134&ver=4630&signature=JXLh7up18JREGzu-hyDHNVu4-yW-RQnmOFTegveHvhlbDBrcwfMRe9c0b15eJPVo5VFZ-BkntaZvQ1EOGDIdWZ4*dM*9NMTwroaqkGu17aagpE6SDr8v2FgsrmKGus4Z&new=1)">[6]</span></a></sup>,因此我们要对其标准化<sup id="fnref:7" class="footnote-ref"><a href="#fn:7" rel="footnote"><span class="hint--top hint--rounded" aria-label="标准化相关文章:[化异为同,Python 在背后帮你做的转换](https://mp.weixin.qq.com/s?src=11×tamp=1688488134&ver=4630&signature=JXLh7up18JREGzu-hyDHNVu4-yW-RQnmOFTegveHvhnpJwhWtfcrbfZyZ0LrFFbzVDaXDT2onRWaIWo*r2Sv9Tg*ZBiuWotp9WQdbrawvxGLj0T5U-xC2fnssc4lEsLl&new=1#:~:text=%E5%8F%AF%E4%BB%A5%E7%9C%8B%E5%88%B0%EF%BC%8C%E6%89%8B%E5%86%99%E5%AD%97%E7%AC%A6%F0%9D%91%93%E9%80%9A%E8%BF%87%20NFKC%20%E6%A0%87%E5%87%86%E8%BD%AC%E6%8D%A2%E4%BB%A5%E5%90%8E%EF%BC%8C%E5%B0%B1%E6%98%AF%E6%99%AE%E9%80%9A%E7%9A%84%E5%AD%97%E6%AF%8Df%EF%BC%8C%E6%89%80%E4%BB%A5%E5%9C%A8%20Python%20%E9%87%8C%E9%9D%A2%EF%BC%8C%E5%A6%82%E6%9E%9C%E4%BD%9C%E4%B8%BA%E5%8F%98%E9%87%8F%E5%90%8D%EF%BC%8C%E8%BF%99%E4%B8%A4%E4%B8%AA%E5%AD%97%E7%AC%A6%E6%98%AF%E4%B8%80%E6%A0%B7%E7%9A%84%E3%80%82)">[7]</span></a></sup>):</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> unicodedata <span class="hljs-keyword">import</span> normalize<br><br>cmap = font.getBestCmap()<br><br><span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> cmap.items():<br> zhihu_dict[<span class="hljs-built_in">chr</span>(x[<span class="hljs-number">0</span>])] = normalize(<span class="hljs-string">"NFKC"</span>, <span class="hljs-built_in">chr</span>(<span class="hljs-built_in">int</span>(x[<span class="hljs-number">1</span>][<span class="hljs-number">3</span>:], <span class="hljs-number">16</span>)))<br><br><span class="hljs-built_in">print</span>(zhihu_dict) <span class="hljs-comment"># {'一': '不', ......, '这': '发'}</span><br></code></pre></td></tr></table></figure><p>(这里的 cmap 是一个 dict,是字形的 {Unicode: Glyph}<sup id="fnref:8" class="footnote-ref"><a href="#fn:8" rel="footnote"><span class="hint--top hint--rounded" aria-label="其中 Unicode 为 `int` 而 Glyph 为形如 uni4E0D 的 `str`">[8]</span></a></sup>)</p><p>接下来,我们将使用得到的对应关系将带乱码的文章转为正常文章。</p><h2 id="五、去除乱码"><a href="#五、去除乱码" class="headerlink" title="五、去除乱码"></a>五、去除乱码</h2><p>这段代码很简单,不作解释。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs python">raw_content = <span class="hljs-string">"在间那块奶酪夹心,时饼干被的喜爱了灵魂。"</span><br>new_content = raw_content.translate(<span class="hljs-built_in">str</span>.maketrans(zhihu_dict))<br><span class="hljs-built_in">print</span>(new_content) <span class="hljs-comment"># 中间那块奶酪夹心,是饼干被人喜爱的灵魂。</span><br></code></pre></td></tr></table></figure><h2 id="六、全部代码"><a href="#六、全部代码" class="headerlink" title="六、全部代码"></a>六、全部代码</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">from</span> fontTools <span class="hljs-keyword">import</span> ttLib<br><span class="hljs-keyword">from</span> unicodedata <span class="hljs-keyword">import</span> normalize<br><br>font = ttLib.TTFont(<span class="hljs-string">"DynamicFonts30.ttf"</span>)<br><br>zhihu_dict = {}<br>cmap = font.getBestCmap()<br><br><span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> cmap.items():<br> zhihu_dict[<span class="hljs-built_in">chr</span>(x[<span class="hljs-number">0</span>])] = normalize(<span class="hljs-string">"NFKC"</span>, <span class="hljs-built_in">chr</span>(<span class="hljs-built_in">int</span>(x[<span class="hljs-number">1</span>][<span class="hljs-number">3</span>:], <span class="hljs-number">16</span>)))<br><br><span class="hljs-built_in">print</span>(zhihu_dict) <span class="hljs-comment"># {'一': '不', ......, '这': '发'}</span><br><br>raw_content = <span class="hljs-string">"在间那块奶酪夹心,时饼干被的喜爱了灵魂。"</span><br>new_content = raw_content.translate(<span class="hljs-built_in">str</span>.maketrans(zhihu_dict))<br><span class="hljs-built_in">print</span>(new_content) <span class="hljs-comment"># 中间那块奶酪夹心,是饼干被人喜爱的灵魂。</span><br></code></pre></td></tr></table></figure><div class="note note-warning"> <p>温馨提示:上面字体文件名记得换成你自己下载的字体文件名</p> </div><h2 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h2><p>在本文的带领下,我们粗略地了解了知乎所使用的反爬技术,分析了其使用的反爬字体,找出了原字与新字的对应关系,最终将带乱码的文章转为了正常文章。其中,知乎使用的反爬字体没有去掉 Unicode 与 Glyph 的对应关系,虽然这使我们更轻松地得到了对应关系,但是对于知乎而言,这种错误无疑是致命的,因此,在字体反爬的实际运用中,我们更需要避免这种错误。<sup id="fnref:9" class="footnote-ref"><a href="#fn:9" rel="footnote"><span class="hint--top hint--rounded" aria-label="关于如何创造更坚固的字体反爬系统,可以参考这篇文章:[反爬终极方案总结—字体反爬 - 知乎](https://zhuanlan.zhihu.com/p/37838586)(值得一提的是这篇文章就被发表在在知乎上 2333)">[9]</span></a></sup></p><p>知乎也在该反爬系统部署到回答页不久以后升级了其专栏反爬系统,本文所介绍的致命缺陷已被修复<sup id="fnref:10" class="footnote-ref"><a href="#fn:10" rel="footnote"><span class="hint--top hint--rounded" aria-label="值得表扬 ( •̀ ω •́ )y">[10]</span></a></sup>,而解码新反爬系统的内容,就留到本系列的下篇吧。</p><p>(敬请期待)</p><h2 id="友情链接"><a href="#友情链接" class="headerlink" title="友情链接"></a>友情链接</h2><ul><li><a href="https://cdycc.cn/">C的云存储 - C的云存储所有作品均由用户提供上传分享,仅供网友学习交流!若您的权利被侵害,请联系 357158361@qq.com</a></li><li><a href="https://github.com/cxzlw/zhihuDecrypt">GitHub - cxzlw/zhihuDecrypt</a></li><li><a href="https://github.com/cxzlw/zhihuDecryptApp">GitHub - cxzlw/zhihuDecryptApp: The app to decrypt zhihu’s encrypted (probably not) passages.</a></li></ul><hr><section class="footnotes"><div class="footnote-list"><ol><li><span id="fn:1" class="footnote-text"><span>专栏反爬现已更新,故本文只以回答反爬为演示。<a href="#fnref:1" rev="footnote" class="footnote-backref"> ↩</a></span></span></li><li><span id="fn:2" class="footnote-text"><span>由于知乎回答页反爬使用了两套字体,故本文所有截图,代码运行结果等内容可能与实际不符。你可以选择以实际为主或刷新页面直到页面显示的内容与本文一致。<a href="#fnref:2" rev="footnote" class="footnote-backref"> ↩</a></span></span></li><li><span id="fn:3" class="footnote-text"><span>.ttf 是因为 <code>data:font/ttf;...</code> 代表该字体是 ttf 格式的。<a href="#fnref:3" rev="footnote" class="footnote-backref"> ↩</a></span></span></li><li><span id="fn:4" class="footnote-text"><span>基于笔画比对的反爬破解见该文章:<a href="https://blog.51cto.com/u_15289428/2992542">字体反爬之汽车之家_51CTO博客_汽车之家字体反爬</a>(话说这篇文章和下面注 9 是一个网站吧)<a href="#fnref:4" rev="footnote" class="footnote-backref"> ↩</a></span></span></li><li><span id="fn:5" class="footnote-text"><span>fontTools文档:<a href="https://fonttools.readthedocs.io/en/latest/">fontTools Docs — fontTools Documentation</a><a href="#fnref:5" rev="footnote" class="footnote-backref"> ↩</a></span></span></li><li><span id="fn:6" class="footnote-text"><span>康熙部首相关文章:<a href="https://mp.weixin.qq.com/s?src=11×tamp=1688488134&ver=4630&signature=JXLh7up18JREGzu-hyDHNVu4-yW-RQnmOFTegveHvhlbDBrcwfMRe9c0b15eJPVo5VFZ-BkntaZvQ1EOGDIdWZ4*dM*9NMTwroaqkGu17aagpE6SDr8v2FgsrmKGus4Z&new=1">康熙部首导致的字典查询异常</a><a href="#fnref:6" rev="footnote" class="footnote-backref"> ↩</a></span></span></li><li><span id="fn:7" class="footnote-text"><span>标准化相关文章:<a href="https://mp.weixin.qq.com/s?src=11×tamp=1688488134&ver=4630&signature=JXLh7up18JREGzu-hyDHNVu4-yW-RQnmOFTegveHvhnpJwhWtfcrbfZyZ0LrFFbzVDaXDT2onRWaIWo*r2Sv9Tg*ZBiuWotp9WQdbrawvxGLj0T5U-xC2fnssc4lEsLl&new=1#:~:text=%E5%8F%AF%E4%BB%A5%E7%9C%8B%E5%88%B0%EF%BC%8C%E6%89%8B%E5%86%99%E5%AD%97%E7%AC%A6%F0%9D%91%93%E9%80%9A%E8%BF%87%20NFKC%20%E6%A0%87%E5%87%86%E8%BD%AC%E6%8D%A2%E4%BB%A5%E5%90%8E%EF%BC%8C%E5%B0%B1%E6%98%AF%E6%99%AE%E9%80%9A%E7%9A%84%E5%AD%97%E6%AF%8Df%EF%BC%8C%E6%89%80%E4%BB%A5%E5%9C%A8%20Python%20%E9%87%8C%E9%9D%A2%EF%BC%8C%E5%A6%82%E6%9E%9C%E4%BD%9C%E4%B8%BA%E5%8F%98%E9%87%8F%E5%90%8D%EF%BC%8C%E8%BF%99%E4%B8%A4%E4%B8%AA%E5%AD%97%E7%AC%A6%E6%98%AF%E4%B8%80%E6%A0%B7%E7%9A%84%E3%80%82">化异为同,Python 在背后帮你做的转换</a><a href="#fnref:7" rev="footnote" class="footnote-backref"> ↩</a></span></span></li><li><span id="fn:8" class="footnote-text"><span>其中 Unicode 为 <code>int</code> 而 Glyph 为形如 uni4E0D 的 <code>str</code><a href="#fnref:8" rev="footnote" class="footnote-backref"> ↩</a></span></span></li><li><span id="fn:9" class="footnote-text"><span>关于如何创造更坚固的字体反爬系统,可以参考这篇文章:<a href="https://zhuanlan.zhihu.com/p/37838586">反爬终极方案总结—字体反爬 - 知乎</a>(值得一提的是这篇文章就被发表在在知乎上 2333)<a href="#fnref:9" rev="footnote" class="footnote-backref"> ↩</a></span></span></li><li><span id="fn:10" class="footnote-text"><span>值得表扬 ( •̀ ω •́ )y<a href="#fnref:10" rev="footnote" class="footnote-backref"> ↩</a></span></span></li></ol></div></section>]]></content>
<tags>
<tag>cxzlw</tag>
<tag>Python</tag>
<tag>知乎</tag>
<tag>反爬</tag>
<tag>逆向</tag>
<tag>爬虫</tag>
</tags>
</entry>
</search>