<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Jacky3</title>
        <link>https://paragraph.com/@jacky3</link>
        <description>Gopher、Full-Stack、Web3/AI/Privatization

Travel、Walk、Think、Freedom</description>
        <lastBuildDate>Fri, 13 Nov 2026 10:40:02 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <image>
            <title>Jacky3</title>
            <url>https://img.paragraph.com/cdn-cgi/image/format=auto/https://storage.googleapis.com/papyrus_images/030fc32ee0c4f0364790edc7bb46b2a40f43d1a3a541c5aa2c7460367e9aa798.jpg</url>
            <link>https://paragraph.com/@jacky3</link>
        </image>
        <copyright>All rights reserved</copyright>
        <item>
            <title><![CDATA[A privatized web3 security model - SelfWeb3]]></title>
            <link>https://paragraph.com/@jacky3/a-privatized-web3-security-model-selfweb3</link>
            <guid>trF7NA4TbYF9SudxsALU</guid>
            <pubDate>Tue, 26 Sep 2023 09:24:31 GMT</pubDate>
            <description><![CDATA[研究动机2009年1月3日，在位于芬兰赫尔辛基的服务器上，至今匿名的神秘技术极客中本聪（Satoshi Nakamoto）生成了第一个比特币区块，自此去中心化的区块链技术以一种纯粹依靠算法建立信任机制的方式开始不断发展，这是革命性的，因为我们日常生活中频繁的交易活动都是基于对交易双方或者第三方机构的信任，这种信任背书强烈的受到不可控因素的影响，包括不透明的内部金融结算，中心化节点故障以及最致命的人为因素干扰，而分布式账本以及去中心化网络所支撑的电子支付系统不需要信任任何人或者服务商即可完成无法被篡改的点对点交易，这是令人极其兴奋的，大刀阔斧砍掉人为因素的同时引入经济激励机制实现自动化运作，虽然相比于传统中心化解决方案很完美，但也存在着缺陷，随着可编程智能合约的支持以及整个web3生态的迅猛发展，一个最基本的问题始终没有得到解决，即A与B的交易确实实现了点对点零信任，最终分布式记账的透明性以及无法被篡改的安全性，却无法证明A与B的合法性, 也就是说怎么证明参与交易的双方真的就是他本人，你当然可以说私钥安全存储是用户自己的事，或许对于那种纯粹手动式的基于双方确认实现共识撮合的点对点交...]]></description>
            <content:encoded><![CDATA[<h1 id="h-" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">研究动机</h1><h3 id="h-200913satoshi-nakamotoweb3abab-web3kycweb3" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2009年1月3日，在位于芬兰赫尔辛基的服务器上，至今匿名的神秘技术极客中本聪（Satoshi Nakamoto）生成了第一个比特币区块，自此去中心化的区块链技术以一种纯粹依靠算法建立信任机制的方式开始不断发展，这是革命性的，因为我们日常生活中频繁的交易活动都是基于对交易双方或者第三方机构的信任，这种信任背书强烈的受到不可控因素的影响，包括不透明的内部金融结算，中心化节点故障以及最致命的人为因素干扰，而分布式账本以及去中心化网络所支撑的电子支付系统不需要信任任何人或者服务商即可完成无法被篡改的点对点交易，这是令人极其兴奋的，大刀阔斧砍掉人为因素的同时引入经济激励机制实现自动化运作，虽然相比于传统中心化解决方案很完美，但也存在着缺陷，随着可编程智能合约的支持以及整个web3生态的迅猛发展，一个最基本的问题始终没有得到解决，即A与B的交易确实实现了点对点零信任，最终分布式记账的透明性以及无法被篡改的安全性，却无法证明A与B的合法性, 也就是说怎么证明参与交易的双方真的就是他本人，你当然可以说私钥安全存储是用户自己的事，或许对于那种纯粹手动式的基于双方确认实现共识撮合的点对点交易而言是合适的，但既然要在基于代币经济模型的基础上自动化，合法性的问题就必不可少，不然只会因为人为因素的干扰变得极其危险，因为任何助记词和私钥并不能真正一对一的绑定到人类本身，也就是说，真正影响web3渗透率的关键因素未必就是生态的繁荣程度或者用户投机的狂热程度，而是最起码的安全性保障，点对点交易的隐私保护也不是意味着与作为入口的合法性存在矛盾，因为只是针对身份证明的有效性而并非个人信息，所以合法性的验证根本不需要以中心化KYC为基准，相反更应该在用户自己掌控隐私的前提下动态授权链上行为，只有真正意义上的链上私有化，web3才更有可能与你自己有关，或许当年那位至今匿名的神秘技术极客也思考过这个问题，只是奈何没有更彻底的解决方案。</h3><h1 id="h-" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">解决方案</h1><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://img.paragraph.com/cdn-cgi/image/format=auto/https://storage.googleapis.com/papyrus_images/30b808fda97b9c98c94a98f57f9be4d3f4a189b228a93ec5e8450c490c11ae5f.png" alt="selfweb3-secure" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">selfweb3-secure</figcaption></figure><h2 id="h-web3" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">如何将web3账户与用户自己一对一绑定</h2><p>在所有使用钱包助记词和私钥作为入口的解决方案中，链上生态单纯的依赖于用户钱包，一旦助记词或者私钥被盗，链上数据将完全没有安全性可言，包括拥有私钥即可对链上数据的完全访问权限，以及任何形式的链上操作行为，这其中主要是web3账户恢复和链上操作两个问题最为严重，恢复机制竟然不需要用户自己动态授权，仅凭明文字符串就可以控制整个账户，再一个链上操作问题，就好比银行账户的所有资金仅仅输入一个密码就可以随意转走，但如果在支持智能合约的链上敏感操作需要进一步的验证，比如存在一种中心化的服务商，专门为用户提供链上事件监控服务，一旦出现敏感操作就先进行链上拦截，再触发web2的动态授权机制，验证通过后更新合约状态进行放行，这样就算助记词或私钥被盗安全性也比完全一股脑的信任钱包好太多，但由于链上状态传递到链下的延迟以及合约状态更新造成的成本问题，这种方案可行性存在问题，如果感兴趣可以参考实验性的开源项目SelfAuth: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/refiotr/selfAuth">https://github.com/refiotr/selfAuth</a>, 而更为彻底更加安全的做法，是真正将web3账户绑定到用户自己，并且针对链上状态更新操作强制进行合法性验证，这也是selfWeb3项目构建的最直接目的，以及迫切想要解决的链上安全问题。</p><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">链下动态授权</h3><p>要解决一对一绑定，首先需要对用户身份合法性进行验证，在合法性验证方向上更深入的研究可以参考Vitalik关于人格生物特征证明的的文章: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://vitalik.ca/general/2023/07/24/biometric.html">https://vitalik.ca/general/2023/07/24/biometric.html</a>, ok, 我们的方案开始并不专注在这一块，而是构建一种链下私有授权和链上动态验证的可扩展框架，由于去中心化的透明性以及智能合约的局限性导致链上针对用户身份的动态验证非常棘手，相反我们的思路是依靠web2成熟的动态授权技术方案，通过链上链下协作对动态授权的合法性进行强制验证，以一种类似零知识证明的方式由链下针对动态授权合法性进行陈述，并生成相应证明，在多方担保签名后交由链上合约进行动态验证，具体授权方式包括Email, TOTP, WebAuthn等，为了进一步加强私有授权的合法性，多种动态授权依据具体业务场景进行关联组合，同时由于授权和验证机制在链下完成，其中涉及到的关键数据由存储在链上合约的私有密钥进行加密维护，具体包括TOTP基于时间的密钥种子，WebAuthn密钥等，在动态解密并计算出共享密钥后才能成功提取出相应的加解密密钥，进而以去中心化的方式完成动态授权的验证。</p><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">链下关联验证</h3><p>所谓的关联验证是指多种动态授权组合后由web2服务完成关联有效性的验证，由私密随机数和web2随机数分别与时间戳timestamp异或后生成动态随机数并完成交换，在每次动态授权校验通过后对该随机数进行具体步长递增，再由web2服务根据关联路径进行随机数回溯递减以及再次异或的形式验证是否与web2Nonce一致，通过后生成链上关联验证的合法性陈述，目的是作为用户身份合法性验证的担保方审核，所以只是目前的一种中心化实现方式，后续可能会调整到完全去中心化的解决方案，因为真正需要web2中心化服务参与的只是作为担保方成员，在用户授权的情况下参与多方签名，而在签名之前所有动态授权和关联验证流程完全可以在私有的去中心化环境完成，这样做的好处是既可以保证关联验证脱离中心化环境运行，也可以通过更多拥有可靠信任背书的中心化服务商加强多方签名验证的安全性，当然引入多方签名服务商的前提是由用户自己自由授权并需要有相应的经济激励以及灾难性的惩罚机制，在完成关联有效性验证后，再由web2服务不对外的私钥进行签名，同动态解密出的私有私钥签名一起打包，用以证明用户完成的关联授权合法性，同时针对签名消息生成动态的默克尔树证明用于链上针对重放攻击的验证。</p><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">链上动态验证</h3><p>由于去中心化的透明性以及智能合约的局限性，目前的验证方案类似于零知识证明的验证，也是针对链下某种陈述生成证明后的验证，但链上成本仅包括部署合约时提供的web2服务私有地址，用户自己的唯一地址, 以及用于重放攻击验证的默克尔树根哈希，后续可能会在零知识证明方向进行深度研究后考虑是否进行调整，但目的是一致的，都是针对链下的合法性事实进行陈述，用于在链上证明链下某种行为的有效性，在完成多方签名的验证后，为了防止同一签名进行多次验证，采用默克尔树动态验证叶子合法性进行实现，但这种方式在每次验证后都需要更新链上存储的默克尔树根哈希，所以只适合针对链上状态更新的验证，相反进行链上数据查询的操作只会验证钱包签名是否合法，这也是为了防止用于关联验证的签名泄漏，同时针对敏感操作联合钱包签名一起加强链上合约验证的安全性，再一个考虑到多方签名的重要性，任何一方都必须在保证私有加密和存储的基础上，进行各自不可见的私密签名，之所以采用多方签名，并不是简单的通过多个维度加强验证的安全性，而是在相互制约的前提下进行组合验证，同时由于web2服务成熟的动态授权和安全防护技术方案，这种链上多方担保签名和重放攻击的验证方式支持在用户自己授权的前提下拓展到更复杂的群体性共识，用于向链上强力证明用户唯一身份的合法性，并且遵循只能是动态的验证原则，而不是基于某种合法性凭证的静态验证。</p><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">如何确保一对一绑定的安全性</h2><p>在针对用户身份合法性的验证逻辑中，如果完全在链上校验是最安全的，但这是自相矛盾的，因为既要保证用于授权的私有信息保密，又无法改变链上环境透明性的限制，而零知识证明也仅仅只是一种用于实现链上验证的方式，同样需要在私有动态授权的前提下才真正有效，不然你真的能保证是用户自己授权生成的证明？所以为了保证合法性验证的有效，包括动态授权，授权验证，关联性验证以及多方签名四个环节需要高度的安全性保障，其中私有动态授权依赖于私有密钥的安全防护，授权验证在去中心化环境中由隐私计算节点提供安全保障，而关联性校验和非私有的的动态签名由私有化的零信任web2服务提供支持。</p><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">私有密钥安全性</h3><p>在将web3账户与用户自己一对一绑定的实现方案中，涉及到私有密钥和私有数据的安全性问题，如果这两部分数据的安全性得不到保证，根本谈不上真正意义上的绑定，而要解决私有密钥的安全性，首先是私有密钥设计问题，由于需要用到私有私钥selfPrivate进行签名担保，也需要参与动态计算共享密钥用于TOTP验证和WebAuthn密钥提取，所以对它的保护极其重要，在充分考虑到各种因素的干扰后，采用三方互不信任的方式对私有私钥selfPrivate进行混合加密，在引入私有的第二个密钥selfKey后，第一层先针对selfKey，由web2服务私钥与web3公钥动态计算出的共享密钥web2DHKey以及用户钱包进行先后加密共同保证selfKey的安全性，第二层再通过selfKey和用户自行输入的密码selfPass混合加密selfPrivate, 这样其实针对selfPrivate的保护存在三个维度的控制，即web2服务、用户钱包和用户自行输入的密码，之所以需要用户自行输入密码，是为了防止一旦钱包和web2服务中的任何一方存在被攻击丢失控制权的情况下，私有私钥selfPrivate依旧安全，而自行输入的密码也支持重新设置以及受到web2服务和钱包的双重约束，为了进一步加强密钥安全性，包括TOTP密钥重置，SelfPass重置，以及钱包重新绑定等密钥重置都需要邮件的有效性和验证码动态验证通过，其中有效性是指用于重置的邮件必须与注册时输入的一致，一致性的判断以在丢弃web3私钥的情况下由web3公钥对邮件进行签名验证为准，同时需要在链上完成多方签名担保验证和默克尔树验证，其次在抛弃中心化存储以及减轻用户心智负担的综合考量后，采用链上合约支持私有密钥的防篡改存储，selfPrivate和selfKey在selfPass重置或者钱包重新绑定后支持链上更新，同时需要在链上完成多方签名担保验证和默克尔树验证。</p><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">隐私计算安全性</h3><p>为了向web3证明用户自己身份的合法性，用于直接验证用户身份的动态授权同样需要以去中心化的方式运行，否则在中心化服务持有私有信息的情况下完全可以伪造动态授权的结果，所以在目前的实现方案中由无法被篡改的链上环境维护私有密钥密文，存储服务持久化私有数据密文，以及在去中心化的环境中为用户身份链下验证和证明生成提供明文计算服务，这样虽然可以保证用户隐私并不会受到中心化环境各种因素的影响，但用于提供明文计算服务的隐私计算节点却需要更强有力的安全防护，在目前的实现方案中，隐私计算节点采用WebAssembly技术嵌入在浏览器网页中运行，为了尽可能对私有数据进行保护，实现逻辑中仅仅针对密文进行缓存，每次进行动态授权或者验证等都需要重新解密再计算，同时针对wasm文件合法性，暂时在动态计算文件hash值后由链上合约动态验证合法性进行保证，后续将重点针对去中心化环境和安全性进行优化升级。</p><h3 id="h-web2" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">web2服务私有化</h3><p>由于用户身份采用链下多方签名担保代替链上直接验证，担保内容的合法性以及签名的安全性就直接影响到整个验证是否有效，试想如何才能保证web2服务无法伪造签名内容的情况下进行担保，同时还不能对外公开服务内部的私钥，之所以需要web2服务保持内部私钥的私密性，是为了针对多种动态授权组合是否有效的担保，就算以去中心化的方式完成关联性校验，也同样需要获得web2服务的认可并授权，否则web2服务参与多方签名就毫无意义，而如何防止伪造关键在于web2服务私钥是否安全，在目前的实现方案中，通过混合加密以及由隐私计算节点校验web2服务有效性的方式提供支持，先由web2服务不对外的密钥加密再由selfPass加密，并且由web2服务和web3去中心化存储平台分别持久化，用于保证web2服务和隐私计算节点均无法独立解密，也就是说web2服务必须由用户自己授权才能提供私有化服务，否则没有私钥无法动态生成担保签名，而隐私计算节点校验web2服务有效性的目的是确认web2私钥的提取确实经过了混合解密，防止web2服务私钥被盗后进行非法使用，另一方面，为了验证针对web2服务的用户身份验证，WebAuthn不仅作为私有动态授权的一部分，同时也用于web2服务私有化验证，由于隐私计算节点和web2服务交互全部采用网络密钥交叉计算出的共享密钥进行点对点加密通讯，web2服务保持无状态运行暂时并不提供会话缓存，相当于一种中心化的私有服务节点。</p><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">私有数据存储安全性</h3><p>私有数据是非私有密钥信息在加密后进行安全存储的部分，包括混合加密后的web2服务私钥密文，用户自行输入的密码selfPass密文, 用于TOTP验证的密钥种子密文，webAuthn密钥密文，进行关联验证时采用的私密随机数以及web3公钥等，为了以去中心化的web3模式运行，在私有密钥加密的基础上再通过钱包加密后存储到web3存储平台，同时在启用web2服务的情况下，部分加密的私有数据在web2服务密钥再次加密后进行备份存储，不包括私密随机数密文，之所以采用混合存储架构，是为了规避中心化服务可能导致的私有数据非法访问或者不可用等情况，同时也是基于中心化服务的高效率提供web2环境的用户体验，由用户钱包，私有密钥和web2服务三方共同维护私有数据的安全性。</p><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">优化升级</h2><p>由于链上动态验证的引入，用户钱包仅仅作为与web3进行交互的工具入口，但同样作为用户身份合法性证明的一部分，只是并非唯一，钱包签名也需要参与关联验证流程，针对系统业务层，由用户钱包、链下动态授权和关联验证以及链上动态验证和重放攻击验证进行保障，就系统整体的安全性而言，包括用户钱包、用户自行输入的密码、web2服务私钥、私密随机数以及私有密钥等多个维度共同维护，之所以在目前的方案中引入web2服务，是为了保证担保审核方一定程度的私密，也是在私有化方向上不断迭代优化的基础，同时由于去中心化固有的特性，为了将零信任web2服务和web3生态嵌入进私有化架构，后续可能会在硬件钱包服务或者非web网页形式等方面进行集成优化，如果需要进一步了解系统架构以及实现源码，请参考官方开源仓库: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/refitor/selfweb3">https://github.com/refitor/selfweb3</a>。</p>]]></content:encoded>
            <author>jacky3@newsletter.paragraph.com (Jacky3)</author>
            <enclosure url="https://img.paragraph.com/cdn-cgi/image/format=auto/https://storage.googleapis.com/papyrus_images/8e77ed3da385953389265e0ebe111cd3d3e2a742b8056262ecd71592ffd5a746.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[工具-超大文件下载器(支持pget失败自动重启和断点续传)]]></title>
            <link>https://paragraph.com/@jacky3/pget</link>
            <guid>FA7E2vLcVWhXIUQlsLZX</guid>
            <pubDate>Thu, 10 Aug 2023 07:19:01 GMT</pubDate>
            <description><![CDATA[一种超大文件下载器，基于pget支持失败自动重启和断点续传，超级无敌巨好用，哈哈import os import sys import time import signal Running = True def run_signal(signum, frame): global Running Running = False def pget(): return os.system(sys.argv[1]) def pget_loop(): global Running while Running: if pget() == 0: Running = False print('pget execute successed......') else: print('pget execute failed, sleep 1s and try again......') time.sleep(1) # example: python3 ./pget.py "pget https://google.com" if __name__ == "__main__": signal.signal...]]></description>
            <content:encoded><![CDATA[<p>一种超大文件下载器，基于pget支持失败自动重启和断点续传，超级无敌巨好用，哈哈</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://img.paragraph.com/cdn-cgi/image/format=auto/https://storage.googleapis.com/papyrus_images/efa0f87f575a4955d871aa9f6c831a16a112e884ca26755fb37468d2572b14a0.jpg" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><pre data-type="codeBlock" text="import os
import sys
import time
import signal

Running = True

def run_signal(signum, frame):
    global Running
    Running = False

def pget():
    return os.system(sys.argv[1])

def pget_loop():
    global Running
    while Running:
        if pget() == 0:
            Running = False
            print(&apos;pget execute successed......&apos;)
        else:
            print(&apos;pget execute failed, sleep 1s and try again......&apos;)
            time.sleep(1)

# example: python3 ./pget.py &quot;pget https://google.com&quot;
if __name__ == &quot;__main__&quot;:
    signal.signal(signal.SIGINT, run_signal)
    pget_loop()
"><code><span class="hljs-keyword">import</span> os
<span class="hljs-keyword">import</span> sys
<span class="hljs-keyword">import</span> time
<span class="hljs-keyword">import</span> signal

Running = <span class="hljs-literal">True</span>

<span class="hljs-keyword">def</span> <span class="hljs-title function_">run_signal</span>(<span class="hljs-params">signum, frame</span>):
    <span class="hljs-keyword">global</span> Running
    Running = <span class="hljs-literal">False</span>

<span class="hljs-keyword">def</span> <span class="hljs-title function_">pget</span>():
    <span class="hljs-keyword">return</span> os.system(sys.argv[<span class="hljs-number">1</span>])

<span class="hljs-keyword">def</span> <span class="hljs-title function_">pget_loop</span>():
    <span class="hljs-keyword">global</span> Running
    <span class="hljs-keyword">while</span> Running:
        <span class="hljs-keyword">if</span> pget() == <span class="hljs-number">0</span>:
            Running = <span class="hljs-literal">False</span>
            <span class="hljs-built_in">print</span>(<span class="hljs-string">'pget execute successed......'</span>)
        <span class="hljs-keyword">else</span>:
            <span class="hljs-built_in">print</span>(<span class="hljs-string">'pget execute failed, sleep 1s and try again......'</span>)
            time.sleep(<span class="hljs-number">1</span>)

<span class="hljs-comment"># example: python3 ./pget.py "pget https://google.com"</span>
<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    signal.signal(signal.SIGINT, run_signal)
    pget_loop()
</code></pre><h2 id="h-installation" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Installation</h2><blockquote><ul><li><p>python3</p></li></ul></blockquote><blockquote><ul><li><p>pget: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/refitor/pget">pget</a></p></li></ul></blockquote><h2 id="h-usage" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Usage</h2><pre data-type="codeBlock" text="python3 ./pget.py &quot;pget https://google.com&quot;
"><code>python3 ./pget.py <span class="hljs-string">"pget https://google.com"</span>
</code></pre>]]></content:encoded>
            <author>jacky3@newsletter.paragraph.com (Jacky3)</author>
        </item>
        <item>
            <title><![CDATA[重构-私有数据selfdata]]></title>
            <link>https://paragraph.com/@jacky3/selfdata</link>
            <guid>RpDfHJmzw662hHZNkDlI</guid>
            <pubDate>Thu, 10 Aug 2023 06:58:55 GMT</pubDate>
            <description><![CDATA[一些关于selfdata的重构优化笔记selfdata ---> selfdata + relay1. relay节点重构，仅调整为提供三方面的服务:1.1. 提供文件中转服务，为私有数据提供网络同步功能, 需要增加中转类型, 包括同步和API两种类型 1.2. 提供消息分发服务，为私有数据提供定向和广播传送, 作为消息调度枢纽，后续为私有推送提供服务 1.3. 提供对外API服务，为授权的第三方应用提供私有数据提取功能，初期仅支持文件内容和k/v数据提取功能 2. relay节点不提供web配置服务, 所有运行所需要的配置全部由私有数据节点selfdata进行配置和同步更新3. selfdata节点重构，撤销命令行，改为由web可视化提供所有功能，包括以下各方面服务:3.1. web部分资源增删改查，所有操作更新到内存文件系统 3.2. web部分提供可视化入口进行数据加密并持久化存储 3.3. web部分提供网络同步入口进行私有数据分发(包括文件和消息) 3.4. web部分提供系统配置功能，包括本地和relay节点两部分, 目前实现的版本需要以此进行拆分 //// 私有数据...]]></description>
            <content:encoded><![CDATA[<p>一些关于selfdata的重构优化笔记</p><h3 id="h-selfdata-greater-selfdata-relay" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">selfdata ---&gt; selfdata + relay</h3><h5 id="h-1-relay" class="text-lg font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">1. relay节点重构，仅调整为提供三方面的服务:</h5><pre data-type="codeBlock" text="1.1. 提供文件中转服务，为私有数据提供网络同步功能, 需要增加中转类型, 包括同步和API两种类型
1.2. 提供消息分发服务，为私有数据提供定向和广播传送, 作为消息调度枢纽，后续为私有推送提供服务
1.3. 提供对外API服务，为授权的第三方应用提供私有数据提取功能，初期仅支持文件内容和k/v数据提取功能
"><code><span class="hljs-number">1.1</span>. 提供文件中转服务，为私有数据提供网络同步功能, 需要增加中转类型, 包括同步和API两种类型
<span class="hljs-number">1.2</span>. 提供消息分发服务，为私有数据提供定向和广播传送, 作为消息调度枢纽，后续为私有推送提供服务
<span class="hljs-number">1.3</span>. 提供对外API服务，为授权的第三方应用提供私有数据提取功能，初期仅支持文件内容和k<span class="hljs-operator">/</span>v数据提取功能
</code></pre><h4 id="h-2-relayweb-selfdata" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">2. relay节点不提供web配置服务, 所有运行所需要的配置全部由私有数据节点selfdata进行配置和同步更新</h4><h4 id="h-3-selfdataweb" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">3. selfdata节点重构，撤销命令行，改为由web可视化提供所有功能，包括以下各方面服务:</h4><pre data-type="codeBlock" text="3.1. web部分资源增删改查，所有操作更新到内存文件系统
3.2. web部分提供可视化入口进行数据加密并持久化存储
3.3. web部分提供网络同步入口进行私有数据分发(包括文件和消息)
3.4. web部分提供系统配置功能，包括本地和relay节点两部分, 目前实现的版本需要以此进行拆分
"><code><span class="hljs-number">3.1</span>. web部分资源增删改查，所有操作更新到内存文件系统
<span class="hljs-number">3.2</span>. web部分提供可视化入口进行数据加密并持久化存储
<span class="hljs-number">3.3</span>. web部分提供网络同步入口进行私有数据分发(包括文件和消息)
<span class="hljs-number">3.4</span>. web部分提供系统配置功能，包括本地和relay节点两部分, 目前实现的版本需要以此进行拆分
</code></pre><pre data-type="codeBlock" text="//// 私有数据授权
//// 1. 提供请求授权信息，包括发起方id, 接收方id, ip等
//// 2. 实时向接收方发送授权请求链接，通过链接确认的方式进行动态授权
//// 3. 授权通过后记录双方id, 并生成唯一通讯传输码用于croc传输
////
//// 发送
//// 1. 先对客户端发送方和接收方id进行验证，判断是否存在传输映射对
//// 2. 再根据id和authCode判断当前操作是否为自己发起
//// 3. 生成唯一传输码，用于发送和接收，并记录到内存
//// 3. 返回加密传输码和对方公钥，由客户端调用croc发起传输请求
//// 接收
//// 1. 先根据客户端id判断是否存在以自己为接收方的传输映射对，并提取传输码
//// 2. 再根据id和authCode判断当前操作是否为自己发起
//// 3. 清理唯一传输码，更新内存缓存, 保证每次传输唯一
//// 4. 返回加密传输码和对方公钥，由客户端调用croc发起传输请求
////
//// 1. 由于croc传输数据全部用公私钥加解密, 可考虑唯一传输码调整成在请求授权的时候进行生成, 撤销每次传输都动态生成, 避免分布式环境下频繁传输存在数据库竞争更新的情况
//// 2. 先暂时中心化对方式实现，后期考虑分布式实现， 仅仅保证核心数据库同步即可, 共识问题由本地验证并由自己动态授权既可完成
////
//// 本地
//// 1. selfdata新增同步模式, 开启后根据客户端id和动态授权码先从云端拉取所有资源列表(id和auchCode用于验证是否为自己)， 同时每一条记录都映射与其对应的relay节点
//// 2. 在获取到云端资源列表之后, 再进行下一步的读取操作(包括本地和云端), 读取操作需要新增文本消息和文件两种
//// 3. 在获取到云端资源列表之后, 再根据资源列表选择发送到哪一个客户端
////
//// web
//// 1. 需要新增管理页面, 展示用户自己的所有客户端列表(显示客户端id, 用户信息(邮箱手机号等), relay节点, ip, 地区， 授权列表, 传输日志)
////1.1. 授权列表为匹配授权成功后的客户端信息列表(包括id, 用户信息(邮箱手机号等), ip, 地区, relay节点等， 开启关闭删除操作)
////1.2. 按条件检索后续再考虑
"><code>/<span class="hljs-regexp">//</span><span class="hljs-regexp">/ 私有数据授权
/</span><span class="hljs-regexp">//</span><span class="hljs-regexp">/ 1. 提供请求授权信息，包括发起方id, 接收方id, ip等
/</span><span class="hljs-regexp">//</span><span class="hljs-regexp">/ 2. 实时向接收方发送授权请求链接，通过链接确认的方式进行动态授权
/</span><span class="hljs-regexp">//</span><span class="hljs-regexp">/ 3. 授权通过后记录双方id, 并生成唯一通讯传输码用于croc传输
/</span><span class="hljs-regexp">//</span><span class="hljs-regexp">/
/</span><span class="hljs-regexp">//</span><span class="hljs-regexp">/ 发送
/</span><span class="hljs-regexp">//</span><span class="hljs-regexp">/ 1. 先对客户端发送方和接收方id进行验证，判断是否存在传输映射对
/</span><span class="hljs-regexp">//</span><span class="hljs-regexp">/ 2. 再根据id和authCode判断当前操作是否为自己发起
/</span><span class="hljs-regexp">//</span><span class="hljs-regexp">/ 3. 生成唯一传输码，用于发送和接收，并记录到内存
/</span><span class="hljs-regexp">//</span><span class="hljs-regexp">/ 3. 返回加密传输码和对方公钥，由客户端调用croc发起传输请求
/</span><span class="hljs-regexp">//</span><span class="hljs-regexp">/ 接收
/</span><span class="hljs-regexp">//</span><span class="hljs-regexp">/ 1. 先根据客户端id判断是否存在以自己为接收方的传输映射对，并提取传输码
/</span><span class="hljs-regexp">//</span><span class="hljs-regexp">/ 2. 再根据id和authCode判断当前操作是否为自己发起
/</span><span class="hljs-regexp">//</span><span class="hljs-regexp">/ 3. 清理唯一传输码，更新内存缓存, 保证每次传输唯一
/</span><span class="hljs-regexp">//</span><span class="hljs-regexp">/ 4. 返回加密传输码和对方公钥，由客户端调用croc发起传输请求
/</span><span class="hljs-regexp">//</span><span class="hljs-regexp">/
/</span><span class="hljs-regexp">//</span><span class="hljs-regexp">/ 1. 由于croc传输数据全部用公私钥加解密, 可考虑唯一传输码调整成在请求授权的时候进行生成, 撤销每次传输都动态生成, 避免分布式环境下频繁传输存在数据库竞争更新的情况
/</span><span class="hljs-regexp">//</span><span class="hljs-regexp">/ 2. 先暂时中心化对方式实现，后期考虑分布式实现， 仅仅保证核心数据库同步即可, 共识问题由本地验证并由自己动态授权既可完成
/</span><span class="hljs-regexp">//</span><span class="hljs-regexp">/
/</span><span class="hljs-regexp">//</span><span class="hljs-regexp">/ 本地
/</span><span class="hljs-regexp">//</span><span class="hljs-regexp">/ 1. selfdata新增同步模式, 开启后根据客户端id和动态授权码先从云端拉取所有资源列表(id和auchCode用于验证是否为自己)， 同时每一条记录都映射与其对应的relay节点
/</span><span class="hljs-regexp">//</span><span class="hljs-regexp">/ 2. 在获取到云端资源列表之后, 再进行下一步的读取操作(包括本地和云端), 读取操作需要新增文本消息和文件两种
/</span><span class="hljs-regexp">//</span><span class="hljs-regexp">/ 3. 在获取到云端资源列表之后, 再根据资源列表选择发送到哪一个客户端
/</span><span class="hljs-regexp">//</span><span class="hljs-regexp">/
/</span><span class="hljs-regexp">//</span><span class="hljs-regexp">/ web
/</span><span class="hljs-regexp">//</span><span class="hljs-regexp">/ 1. 需要新增管理页面, 展示用户自己的所有客户端列表(显示客户端id, 用户信息(邮箱手机号等), relay节点, ip, 地区， 授权列表, 传输日志)
/</span><span class="hljs-regexp">//</span><span class="hljs-regexp">/1.1. 授权列表为匹配授权成功后的客户端信息列表(包括id, 用户信息(邮箱手机号等), ip, 地区, relay节点等， 开启关闭删除操作)
/</span><span class="hljs-regexp">//</span><span class="hljs-regexp">/1.2. 按条件检索后续再考虑
</span></code></pre><h3 id="h-2021-11-21" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2021-11-21</h3><pre data-type="codeBlock" text="// 重构
/*
1. 统一调整为全部密文存储，内存解密, 极简版本加解密和动态授权源码开源, 支持自行开发接入
2. 极简版本保持目前仅仅加解密功能，新增内存命令行管理, 不支持网络传输, 加密数据仅仅只面向同一个客户端可进行加解密(可自行实现网络传输)
3. 专业版核心收费部分支持分布式环境网络传输, 支持跨平台任意私有数据版本客户端解密, 加密仅支持专业版及以上(仅仅只是中转节点代理转发加密数据, 无服务器)
4. 专业版管理授粉部分支持web可视化管理，包括私有数据管理, 公私钥管理, 中转节点管理, 动态授权管理(包括授权认证和公钥对换)等
5. 收费部分, 专业版通过唯一支付授权码可下载任意版本客户端
6. 专业版稳定后, 后续可考虑接入硬件部分

开发
1. 需要在客户端本地环境生成db文件用于管理, 所有入库内容全部通过公钥加密, 即使数据库丢失仅仅只是管理数据丢失并且无法打开使用, 不影响任何私有数据
2. 动态授权部分, 需要调整到rwcore(可考虑重命名), 动态授权可选择由云端发, 也支持直接在客户端本地发送, 代码开源
3. 客户端打包不再需要写入用户邮箱或者手机号, 调整为客户端第一次初始化时指定, 指定包括动态授权ID(邮箱, 手机号, gotify等), 辅助邮箱等信息
4. 支持客户端本地修改邮箱, 但需要原动态授权通过, 如果原动态授权不可用并且存在辅助邮箱, 则可通过辅助邮箱进行认证授权, 否则客户端将彻底无法使用
5. 为了保证体验, 后续可支持由授权客户端发起辅助, 即客户端发起数据传送, 如果能正常解密达到指定数量即可进行动态授权修改

开源组件
1. 上传: https://github.com/tus/tusd
2. 下载: https://github.com/melbahja/got
*/
"><code>// 重构
/*
<span class="hljs-bullet">1.</span> 统一调整为全部密文存储，内存解密, 极简版本加解密和动态授权源码开源, 支持自行开发接入
<span class="hljs-bullet">2.</span> 极简版本保持目前仅仅加解密功能，新增内存命令行管理, 不支持网络传输, 加密数据仅仅只面向同一个客户端可进行加解密(可自行实现网络传输)
<span class="hljs-bullet">3.</span> 专业版核心收费部分支持分布式环境网络传输, 支持跨平台任意私有数据版本客户端解密, 加密仅支持专业版及以上(仅仅只是中转节点代理转发加密数据, 无服务器)
<span class="hljs-bullet">4.</span> 专业版管理授粉部分支持web可视化管理，包括私有数据管理, 公私钥管理, 中转节点管理, 动态授权管理(包括授权认证和公钥对换)等
<span class="hljs-bullet">5.</span> 收费部分, 专业版通过唯一支付授权码可下载任意版本客户端
<span class="hljs-bullet">6.</span> 专业版稳定后, 后续可考虑接入硬件部分

开发
<span class="hljs-bullet">1.</span> 需要在客户端本地环境生成db文件用于管理, 所有入库内容全部通过公钥加密, 即使数据库丢失仅仅只是管理数据丢失并且无法打开使用, 不影响任何私有数据
<span class="hljs-bullet">2.</span> 动态授权部分, 需要调整到rwcore(可考虑重命名), 动态授权可选择由云端发, 也支持直接在客户端本地发送, 代码开源
<span class="hljs-bullet">3.</span> 客户端打包不再需要写入用户邮箱或者手机号, 调整为客户端第一次初始化时指定, 指定包括动态授权ID(邮箱, 手机号, gotify等), 辅助邮箱等信息
<span class="hljs-bullet">4.</span> 支持客户端本地修改邮箱, 但需要原动态授权通过, 如果原动态授权不可用并且存在辅助邮箱, 则可通过辅助邮箱进行认证授权, 否则客户端将彻底无法使用
<span class="hljs-bullet">5.</span> 为了保证体验, 后续可支持由授权客户端发起辅助, 即客户端发起数据传送, 如果能正常解密达到指定数量即可进行动态授权修改

开源组件
<span class="hljs-bullet">1.</span> 上传: https://github.com/tus/tusd
<span class="hljs-bullet">2.</span> 下载: https://github.com/melbahja/got
<span class="hljs-emphasis">*/
</span></code></pre><h3 id="h-2021-11-23" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2021-11-23</h3><pre data-type="codeBlock" text="// 1. 解决客户端数据暴露在云端的问题,
// 支持输入动态授权ID在线生成跨平台活数据，对数据的任何操作将触发动态授权
// 支持selfdata客户端自动生成活数据同步到云端, 云端只有在自己授权的情况下才能拿到元数据
// 客户端同步的数据包括邮箱和公钥, 任何更新操作将触发动态授权, 对邮箱或公钥使用将触发特定授权(需要提供请求参数)
// 对于授权发送, 由活数据内部提供, 外部只需要提供用途和携带的数据即可, 避免数据暴露到外部
// 目前需要提供的接口:
// 1. 数据获取(在线链接授权校验), 更新数据需要重新生成
// 2. 根据输入的密钥解密出元数据, 进行提取
// 私有活数据(rsdata), web和api(后续看情况, 本地使用密钥先加密再上传), 根据平台架构官方云端生成
//
// selfdata客户端通信及加解密
// 1. selfdata的私有活数据存储于云端, 为二进制形式(随云端一同分发), 数据由客户端提供
// 2. selfdata的私有活数据通过云端AES密钥加密数据(访问需要动态授权), 使用自己的动态随机密钥加密通讯数据
// 3. 由于动态授权在私有活数据内部进行, 任何授权操作以及参数校验提取操作全部在私有活数据内部进行
// 私有活数据提供的接口:
// 1. 根据输入的云端AES密钥解密出元数据
// 2. 数据更新, 数据获取(在线链接授权校验), 由action指定(update, export).
// 3. 使用自己的通信密钥解密出请求数据
// 4. 客户端动态授权(仅发送授权码)
// 5. 客户端公钥对换(在线链接授权校验, 交叉加密)

// 第一次初始化数据的问题, 通过云端AES加解密, 在客户端第一次初始化时对云端进行严格的校验, 比如文件hash, ip, 地区, 官方校验等, 触发在线链接授权校验

/*
重构
0. 云端不再负责公钥对换, 全部迁移到本地客户端, 云端仅仅存储客户端无法篡改的数据以及数据转发, 云端所有数据全部公钥加密, 所有公私钥全部在本地客户端
1. 极简版本selfdata保持目前作为工具支持读写操作生成私有数据, 不支持网络传输(解密导出不再导出zip, 直接解压出原数据), rwcore插件导入收费
2. 专业版selfdata调整为私有数据的升级版，支持本地内存加解密(仅密文存储), 本地cli命令行管理, 跨平台任意客户端点对点私有数据分发(99/永久)
3. 增值服务部分, 支持web可视化管理, 支持以服务运行模式的私有数据中心, 支持定制私有硬件(绝密管理)(全部按增值服务收费)
*/
"><code><span class="hljs-comment">// 1. 解决客户端数据暴露在云端的问题,</span>
<span class="hljs-comment">// 支持输入动态授权ID在线生成跨平台活数据，对数据的任何操作将触发动态授权</span>
<span class="hljs-comment">// 支持selfdata客户端自动生成活数据同步到云端, 云端只有在自己授权的情况下才能拿到元数据</span>
<span class="hljs-comment">// 客户端同步的数据包括邮箱和公钥, 任何更新操作将触发动态授权, 对邮箱或公钥使用将触发特定授权(需要提供请求参数)</span>
<span class="hljs-comment">// 对于授权发送, 由活数据内部提供, 外部只需要提供用途和携带的数据即可, 避免数据暴露到外部</span>
<span class="hljs-comment">// 目前需要提供的接口:</span>
<span class="hljs-comment">// 1. 数据获取(在线链接授权校验), 更新数据需要重新生成</span>
<span class="hljs-comment">// 2. 根据输入的密钥解密出元数据, 进行提取</span>
<span class="hljs-comment">// 私有活数据(rsdata), web和api(后续看情况, 本地使用密钥先加密再上传), 根据平台架构官方云端生成</span>
<span class="hljs-comment">//</span>
<span class="hljs-comment">// selfdata客户端通信及加解密</span>
<span class="hljs-comment">// 1. selfdata的私有活数据存储于云端, 为二进制形式(随云端一同分发), 数据由客户端提供</span>
<span class="hljs-comment">// 2. selfdata的私有活数据通过云端AES密钥加密数据(访问需要动态授权), 使用自己的动态随机密钥加密通讯数据</span>
<span class="hljs-comment">// 3. 由于动态授权在私有活数据内部进行, 任何授权操作以及参数校验提取操作全部在私有活数据内部进行</span>
<span class="hljs-comment">// 私有活数据提供的接口:</span>
<span class="hljs-comment">// 1. 根据输入的云端AES密钥解密出元数据</span>
<span class="hljs-comment">// 2. 数据更新, 数据获取(在线链接授权校验), 由action指定(update, export).</span>
<span class="hljs-comment">// 3. 使用自己的通信密钥解密出请求数据</span>
<span class="hljs-comment">// 4. 客户端动态授权(仅发送授权码)</span>
<span class="hljs-comment">// 5. 客户端公钥对换(在线链接授权校验, 交叉加密)</span>

<span class="hljs-comment">// 第一次初始化数据的问题, 通过云端AES加解密, 在客户端第一次初始化时对云端进行严格的校验, 比如文件hash, ip, 地区, 官方校验等, 触发在线链接授权校验</span>

<span class="hljs-comment">/*
重构
0. 云端不再负责公钥对换, 全部迁移到本地客户端, 云端仅仅存储客户端无法篡改的数据以及数据转发, 云端所有数据全部公钥加密, 所有公私钥全部在本地客户端
1. 极简版本selfdata保持目前作为工具支持读写操作生成私有数据, 不支持网络传输(解密导出不再导出zip, 直接解压出原数据), rwcore插件导入收费
2. 专业版selfdata调整为私有数据的升级版，支持本地内存加解密(仅密文存储), 本地cli命令行管理, 跨平台任意客户端点对点私有数据分发(99/永久)
3. 增值服务部分, 支持web可视化管理, 支持以服务运行模式的私有数据中心, 支持定制私有硬件(绝密管理)(全部按增值服务收费)
*/</span>
</code></pre><h3 id="h-2021-11-24" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2021-11-24</h3><pre data-type="codeBlock" text="// 公钥不公开: 对换流程需要两个客户端和云端配合才能完成交换, 涉及交换准备(获取一个接收方客户端定的交换密钥), 发送方打包,放入接收方缓存, 接收方授权, 接收方打包, 公钥放入发送方缓存
// 发送方收到后再打包公钥, 公钥放入接收方缓存
// 公钥和邮箱公开到云端: 发送方发起对换请求, 接收方授权, 云端根据id使用双方公钥交叉加密并放入各自缓存
// 仅仅公钥公开到云端: 发送方发起对换请求, 云端将发送方公钥交叉加密放入接收方缓存, 接收方本地授权, 直接推送到发送方缓存
"><code><span class="hljs-comment">// 公钥不公开: 对换流程需要两个客户端和云端配合才能完成交换, 涉及交换准备(获取一个接收方客户端定的交换密钥), 发送方打包,放入接收方缓存, 接收方授权, 接收方打包, 公钥放入发送方缓存</span>
<span class="hljs-comment">// 发送方收到后再打包公钥, 公钥放入接收方缓存</span>
<span class="hljs-comment">// 公钥和邮箱公开到云端: 发送方发起对换请求, 接收方授权, 云端根据id使用双方公钥交叉加密并放入各自缓存</span>
<span class="hljs-comment">// 仅仅公钥公开到云端: 发送方发起对换请求, 云端将发送方公钥交叉加密放入接收方缓存, 接收方本地授权, 直接推送到发送方缓存</span>
</code></pre>]]></content:encoded>
            <author>jacky3@newsletter.paragraph.com (Jacky3)</author>
            <enclosure url="https://img.paragraph.com/cdn-cgi/image/format=auto/https://storage.googleapis.com/papyrus_images/1c7da60d46f16f590998d3da2b81c6367e4872dcd511cd61c9b1e79732dcf1d0.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[随想-selfdata + relay]]></title>
            <link>https://paragraph.com/@jacky3/selfdata-relay</link>
            <guid>TkYlj2uSTKHcRx17QgY9</guid>
            <pubDate>Thu, 10 Aug 2023 06:50:14 GMT</pubDate>
            <description><![CDATA[一些关于点对点加密通讯的思考: selfdata + relay# ====================================Thinking1============================================= c->s: 1. c.netPriv + s.netPub ===> key 2. data + key ===> edata s->c: 1. s.netPriv + c.netPub ===> key 2. data + key ===> edata c1->s: 1. c1.id + c1.id ==> eid1 2. c1.netPub + (c-s).key ===> s.pubc1 c2->s: 1. c2.id + c2.id ===> eid2 3. c2.netPub + (c-s).key ===> s.pubc2 c1->c2: 1. c2->s(pull): (c1.id + c1.id) ===> (eid1 + s.pubc1) 2. c2->c2(...): c2.dataPub + (c2.netPri...]]></description>
            <content:encoded><![CDATA[<p>一些关于点对点加密通讯的思考: selfdata + relay</p><pre data-type="codeBlock" text="# ====================================Thinking1=============================================
c-&gt;s: 
1. c.netPriv + s.netPub ===&gt; key
2. data + key ===&gt; edata

s-&gt;c:
1. s.netPriv + c.netPub ===&gt; key
2. data + key ===&gt; edata


c1-&gt;s:
1. c1.id + c1.id ==&gt; eid1
2. c1.netPub + (c-s).key ===&gt; s.pubc1

c2-&gt;s:
1. c2.id + c2.id ===&gt; eid2
3. c2.netPub + (c-s).key ===&gt; s.pubc2

c1-&gt;c2:
1. c2-&gt;s(pull): (c1.id + c1.id) ===&gt; (eid1 + s.pubc1)
2. c2-&gt;c2(...): c2.dataPub + (c2.netPriv + s.pubc1).key ===&gt; c2sdata
3. c2-&gt;s(push): eid1 + c2sdata + s.pubc2(swap+sign) ===&gt; c1.mq
4. c1-&gt;s(pull): (c1.id + c1.id) ===&gt; eid2 + c2sdata + s.pubc2
5. c1-&gt;c1(...): c2sdata + (c1.netPriv + s.pubc2).key ===&gt; c2.dataPub
6. c1-&gt;c1(...): c1.datapub + (c1.netPriv + s.pubc2).key ===&gt; c1sdata
7. c1-&gt;s(push): eid2 + c1sdata + s.pubc1(swap+sign) ===&gt; c2.mq
8. c2-&gt;s(pull): (c2.id + c2.id) ===&gt; eid2 + c1sdata + s.pubc1
9. c2-&gt;c2(...): c1sdata + (c2.netPriv + s.pubc1).key ===&gt; c1.dataPub
# ====================================Thinking1=============================================

# ====================================Thinking2=============================================
just only for c1&lt;-&gt;c2
1. c1.random + c2.netPub ===&gt; erandom
2. (c1.netPriv + c2.netPub).key + c1.random  ===&gt; netKey
3. (c2.netPriv + c1.netPub).key + (erandom + c2.netPriv).random ===&gt; netKey

push/pull list
1. public: (c1.id + c1.id).key, (public + c1.netPub + selfEncryptedKey).value
2. c1&lt;-&gt;c2: (c1.id + netKey).key, (c2/c3/c4.id + c2/c3/c4.netPub + public + c2/c3/c4sdata + netKey).value
3. self.list: (c1.id + c1.dataPub).key, (data + c1.dataPub)
4. c&lt;-&gt;s: cdata + s.pub ===&gt; sedata + s.priv ===&gt; sdata + c.pub ===&gt; cedata + c.priv ===&gt; c.data
# ====================================Thinking3=============================================

# ====================================Thinking3=============================================
1. self&lt;-&gt;self: selfdata + relay, relay.store: memory.map + memory.filesystem(open source)

// 考虑是否需要
1.1. memory.filesystem: c1.fname + s.netPub ===&gt; efname + s.netPriv ===&gt; s.fname ===&gt; memory.fs
1.2. memory.filesystem: efname + s.netPriv ===&gt; s.fname + c2.netPub ===&gt;  efname ===&gt; s.downloadURL
1.3. memory.filesystem: efname + c2.netPriv ===&gt; s.fname + s.netPub ===&gt; efname ===&gt; c2.downloadURL

2. rc1&lt;-&gt;rc2: selfdata + relay, relay.store: swap + redis + p2p.file(open source)

3. sdc1&lt;-&gt;sdc2: selfdata + gossip/p2p(blockchain)  
# ====================================Thinking3=============================================

# ====================================Thinking4=============================================
1. key for mq: (c1.id + c1.id).key + (name.id + name.id).key + (email.id + email.id).key
2. split for key: &quot;-&quot;
# ====================================Thinking4=============================================
"><code># <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span>Thinking1<span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span>
c<span class="hljs-operator">-</span><span class="hljs-operator">></span>s: 
<span class="hljs-number">1.</span> c.netPriv <span class="hljs-operator">+</span> s.netPub <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">></span> key
<span class="hljs-number">2.</span> data <span class="hljs-operator">+</span> key <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">></span> edata

s<span class="hljs-operator">-</span><span class="hljs-operator">></span>c:
<span class="hljs-number">1.</span> s.netPriv <span class="hljs-operator">+</span> c.netPub <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">></span> key
<span class="hljs-number">2.</span> data <span class="hljs-operator">+</span> key <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">></span> edata


c1<span class="hljs-operator">-</span><span class="hljs-operator">></span>s:
<span class="hljs-number">1.</span> c1.id <span class="hljs-operator">+</span> c1.id <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">></span> eid1
<span class="hljs-number">2.</span> c1.netPub <span class="hljs-operator">+</span> (c<span class="hljs-operator">-</span>s).key <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">></span> s.pubc1

c2<span class="hljs-operator">-</span><span class="hljs-operator">></span>s:
<span class="hljs-number">1.</span> c2.id <span class="hljs-operator">+</span> c2.id <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">></span> eid2
<span class="hljs-number">3.</span> c2.netPub <span class="hljs-operator">+</span> (c<span class="hljs-operator">-</span>s).key <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">></span> s.pubc2

c1<span class="hljs-operator">-</span><span class="hljs-operator">></span>c2:
<span class="hljs-number">1.</span> c2<span class="hljs-operator">-</span><span class="hljs-operator">></span>s(pull): (c1.id <span class="hljs-operator">+</span> c1.id) <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">></span> (eid1 <span class="hljs-operator">+</span> s.pubc1)
<span class="hljs-number">2.</span> c2<span class="hljs-operator">-</span><span class="hljs-operator">></span>c2(...): c2.dataPub <span class="hljs-operator">+</span> (c2.netPriv <span class="hljs-operator">+</span> s.pubc1).key <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">></span> c2sdata
<span class="hljs-number">3.</span> c2<span class="hljs-operator">-</span><span class="hljs-operator">></span>s(push): eid1 <span class="hljs-operator">+</span> c2sdata <span class="hljs-operator">+</span> s.pubc2(swap<span class="hljs-operator">+</span>sign) <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">></span> c1.mq
<span class="hljs-number">4.</span> c1<span class="hljs-operator">-</span><span class="hljs-operator">></span>s(pull): (c1.id <span class="hljs-operator">+</span> c1.id) <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">></span> eid2 <span class="hljs-operator">+</span> c2sdata <span class="hljs-operator">+</span> s.pubc2
<span class="hljs-number">5.</span> c1<span class="hljs-operator">-</span><span class="hljs-operator">></span>c1(...): c2sdata <span class="hljs-operator">+</span> (c1.netPriv <span class="hljs-operator">+</span> s.pubc2).key <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">></span> c2.dataPub
<span class="hljs-number">6.</span> c1<span class="hljs-operator">-</span><span class="hljs-operator">></span>c1(...): c1.datapub <span class="hljs-operator">+</span> (c1.netPriv <span class="hljs-operator">+</span> s.pubc2).key <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">></span> c1sdata
<span class="hljs-number">7.</span> c1<span class="hljs-operator">-</span><span class="hljs-operator">></span>s(push): eid2 <span class="hljs-operator">+</span> c1sdata <span class="hljs-operator">+</span> s.pubc1(swap<span class="hljs-operator">+</span>sign) <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">></span> c2.mq
<span class="hljs-number">8.</span> c2<span class="hljs-operator">-</span><span class="hljs-operator">></span>s(pull): (c2.id <span class="hljs-operator">+</span> c2.id) <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">></span> eid2 <span class="hljs-operator">+</span> c1sdata <span class="hljs-operator">+</span> s.pubc1
<span class="hljs-number">9.</span> c2<span class="hljs-operator">-</span><span class="hljs-operator">></span>c2(...): c1sdata <span class="hljs-operator">+</span> (c2.netPriv <span class="hljs-operator">+</span> s.pubc1).key <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">></span> c1.dataPub
# <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span>Thinking1<span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span>

# <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span>Thinking2<span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span>
just only <span class="hljs-keyword">for</span> c1<span class="hljs-operator">&#x3C;</span><span class="hljs-operator">-</span><span class="hljs-operator">></span>c2
<span class="hljs-number">1.</span> c1.random <span class="hljs-operator">+</span> c2.netPub <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">></span> erandom
<span class="hljs-number">2.</span> (c1.netPriv <span class="hljs-operator">+</span> c2.netPub).key <span class="hljs-operator">+</span> c1.random  <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">></span> netKey
<span class="hljs-number">3.</span> (c2.netPriv <span class="hljs-operator">+</span> c1.netPub).key <span class="hljs-operator">+</span> (erandom <span class="hljs-operator">+</span> c2.netPriv).random <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">></span> netKey

push<span class="hljs-operator">/</span>pull list
<span class="hljs-number">1.</span> <span class="hljs-keyword">public</span>: (c1.id <span class="hljs-operator">+</span> c1.id).key, (<span class="hljs-keyword">public</span> <span class="hljs-operator">+</span> c1.netPub <span class="hljs-operator">+</span> selfEncryptedKey).<span class="hljs-built_in">value</span>
<span class="hljs-number">2.</span> c1<span class="hljs-operator">&#x3C;</span><span class="hljs-operator">-</span><span class="hljs-operator">></span>c2: (c1.id <span class="hljs-operator">+</span> netKey).key, (c2<span class="hljs-operator">/</span>c3<span class="hljs-operator">/</span>c4.id <span class="hljs-operator">+</span> c2<span class="hljs-operator">/</span>c3<span class="hljs-operator">/</span>c4.netPub <span class="hljs-operator">+</span> <span class="hljs-keyword">public</span> <span class="hljs-operator">+</span> c2<span class="hljs-operator">/</span>c3<span class="hljs-operator">/</span>c4sdata <span class="hljs-operator">+</span> netKey).<span class="hljs-built_in">value</span>
<span class="hljs-number">3.</span> <span class="hljs-built_in">self</span>.list: (c1.id <span class="hljs-operator">+</span> c1.dataPub).key, (data <span class="hljs-operator">+</span> c1.dataPub)
<span class="hljs-number">4.</span> c<span class="hljs-operator">&#x3C;</span><span class="hljs-operator">-</span><span class="hljs-operator">></span>s: cdata <span class="hljs-operator">+</span> s.pub <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">></span> sedata <span class="hljs-operator">+</span> s.priv <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">></span> sdata <span class="hljs-operator">+</span> c.pub <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">></span> cedata <span class="hljs-operator">+</span> c.priv <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">></span> c.data
# <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span>Thinking3<span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span>

# <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span>Thinking3<span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span>
<span class="hljs-number">1.</span> <span class="hljs-built_in">self</span><span class="hljs-operator">&#x3C;</span><span class="hljs-operator">-</span><span class="hljs-operator">></span><span class="hljs-built_in">self</span>: selfdata <span class="hljs-operator">+</span> relay, relay.store: <span class="hljs-keyword">memory</span>.map <span class="hljs-operator">+</span> <span class="hljs-keyword">memory</span>.filesystem(open source)

<span class="hljs-comment">// 考虑是否需要</span>
<span class="hljs-number">1.1</span>. memory.filesystem: c1.fname <span class="hljs-operator">+</span> s.netPub <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">></span> efname <span class="hljs-operator">+</span> s.netPriv <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">></span> s.fname <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">></span> <span class="hljs-keyword">memory</span>.fs
<span class="hljs-number">1.2</span>. memory.filesystem: efname <span class="hljs-operator">+</span> s.netPriv <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">></span> s.fname <span class="hljs-operator">+</span> c2.netPub <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">></span>  efname <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">></span> s.downloadURL
<span class="hljs-number">1.3</span>. memory.filesystem: efname <span class="hljs-operator">+</span> c2.netPriv <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">></span> s.fname <span class="hljs-operator">+</span> s.netPub <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">></span> efname <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">></span> c2.downloadURL

<span class="hljs-number">2.</span> rc1<span class="hljs-operator">&#x3C;</span><span class="hljs-operator">-</span><span class="hljs-operator">></span>rc2: selfdata <span class="hljs-operator">+</span> relay, relay.store: swap <span class="hljs-operator">+</span> redis <span class="hljs-operator">+</span> p2p.file(open source)

<span class="hljs-number">3.</span> sdc1<span class="hljs-operator">&#x3C;</span><span class="hljs-operator">-</span><span class="hljs-operator">></span>sdc2: selfdata <span class="hljs-operator">+</span> gossip<span class="hljs-operator">/</span>p2p(blockchain)  
# <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span>Thinking3<span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span>

# <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span>Thinking4<span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span>
<span class="hljs-number">1.</span> key <span class="hljs-keyword">for</span> mq: (c1.id <span class="hljs-operator">+</span> c1.id).key <span class="hljs-operator">+</span> (name.id <span class="hljs-operator">+</span> name.id).key <span class="hljs-operator">+</span> (email.id <span class="hljs-operator">+</span> email.id).key
<span class="hljs-number">2.</span> split <span class="hljs-keyword">for</span> key: <span class="hljs-string">"-"</span>
# <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span>Thinking4<span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span>
</code></pre><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">核心源码</h2><pre data-type="codeBlock" text="package rsrelay

import (
    &quot;fmt&quot;
    &quot;io/ioutil&quot;
    &quot;net/http&quot;
)

func doCheckPermission(r *http.Request) (string, string, []string) {
    dparams, err := decodeNetParams(WebParams(r).Get(&quot;param&quot;), v_sysPrivateKey)
    if err != nil || len(dparams) &lt; 3 {
        LogPrint(&quot;decodeNetParams failed, detail: %+v&quot;, err, &quot;error&quot;)
        return &quot;&quot;, &quot;&quot;, nil
    }

    selfPub := &quot;&quot;
    if bytes := getBytes(dparams[0]); len(bytes) &gt; 0 {
        selfPub = string(bytes[0])
    }
    if selfPub == &quot;&quot; {
        if dparams[0] == dparams[len(dparams) - 1] {
            selfPub = WebParams(r).Get(&quot;data&quot;)
        } else {
            LogPrint(&quot;getPublicKey failed, selfID: &quot; + dparams[0], &quot;error&quot;)
            return &quot;&quot;, &quot;&quot;, nil
        }
    }
    if tokenVerify(dparams[1], dparams[2], []byte(selfPub), []byte(v_sysPrivateKey)) != nil {
        LogPrint(&quot;tokenVerify failed, selfID: &quot; + dparams[0], &quot;error&quot;)
        return &quot;&quot;, &quot;&quot;, nil
    }
    return dparams[0], selfPub, dparams
}

func doResponseOK(w http.ResponseWriter, r *http.Request, selfPub string, datas ...[]byte) {
    respBytes := make([][]byte, 0)
    token, signature := tokenCreate([]byte(selfPub), []byte(v_sysPrivateKey))
    respBytes = append(respBytes, token, signature)
    respBytes = append(respBytes, datas...)
    ResponseOk(w, r, WebOk(respBytes))
}

// GET /api/data/pull
// param: [selfID, token, signature], data: demo
func WebDataPull(w http.ResponseWriter, r *http.Request) {
    if selfID, selfPub, dparams := doCheckPermission(r); dparams != nil &amp;&amp; selfPub != &quot;&quot; &amp;&amp; selfID != &quot;&quot; {
        if pullBytes, err := doWebPullForBytes(r, selfID, selfPub, WebParams(r).Get(&quot;data&quot;)); err != nil {
            ResponseError(w, r, err.Error())
        } else {
            doResponseOK(w, r, selfPub, pullBytes...)
            vBytesCache.Delete(WebParams(r).Get(&quot;data&quot;))
        }
    }
    ResponseError(w, r, &quot;permission denied&quot;)
}

// GET /api/data/push
// param: [selfID, token, signature], data: demo
func WebDataPush(w http.ResponseWriter, r *http.Request) {
    if selfID, selfPub, dparams := doCheckPermission(r); dparams != nil &amp;&amp; selfPub != &quot;&quot; &amp;&amp; selfID != &quot;&quot; {
        recvIds := dparams[3:]
        failedIds := make([][]byte, 0)
        for i := 0; i &lt; len(recvIds); i++ {
            if err := doWebPushForBytes(r, selfID, selfPub, recvIds[i]); err != nil {
                failedIds = append(failedIds, []byte(recvIds[i]))
                LogPrint(err.Error(), &quot;error&quot;)
            }
        }
        doResponseOK(w, r, selfPub, failedIds...)
        return
    }
    ResponseError(w, r, &quot;permission denied&quot;)
}

func doWebPushForBytes(r *http.Request, selfID, selfPub, pushID string) error {
    // cache for bytes
    buf := []byte(WebParams(r).Get(&quot;data&quot;))
    if len(buf) == 0 {
        bytes, err := ioutil.ReadAll(r.Body)
        if err != nil {
            return err
        }
        buf = bytes[:]
    }
    if len(buf) == 0 {
        return fmt.Errorf(&quot;invalid push bytes, recvID: %s&quot;, pushID)
    }
    addBytes(pushID, buf[:])
    //infoLog(&quot;upload text successed, push: %s, size: %d&quot;, pushID, len(buf))
    return nil
}

func doWebPullForBytes(r *http.Request, selfID, sdPub, pullID string) ([][]byte, error) {
    return getBytes(pullID), nil
}
"><code>package rsrelay

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"fmt"</span>
    <span class="hljs-string">"io/ioutil"</span>
    <span class="hljs-string">"net/http"</span>
)

<span class="hljs-title">func</span> <span class="hljs-title">doCheckPermission</span>(<span class="hljs-title">r</span> <span class="hljs-operator">*</span><span class="hljs-title">http</span>.<span class="hljs-title">Request</span>) (<span class="hljs-title"><span class="hljs-keyword">string</span></span>, <span class="hljs-title"><span class="hljs-keyword">string</span></span>, []<span class="hljs-title"><span class="hljs-keyword">string</span></span>) {
    <span class="hljs-title">dparams</span>, <span class="hljs-title">err</span> :<span class="hljs-operator">=</span> <span class="hljs-title">decodeNetParams</span>(<span class="hljs-title">WebParams</span>(<span class="hljs-title">r</span>).<span class="hljs-title">Get</span>(<span class="hljs-string">"param"</span>), <span class="hljs-title">v_sysPrivateKey</span>)
    <span class="hljs-title"><span class="hljs-keyword">if</span></span> <span class="hljs-title">err</span> <span class="hljs-operator">!</span><span class="hljs-operator">=</span> <span class="hljs-title">nil</span> <span class="hljs-operator">|</span><span class="hljs-operator">|</span> <span class="hljs-title">len</span>(<span class="hljs-title">dparams</span>) <span class="hljs-operator">&#x3C;</span> 3 {
        <span class="hljs-title">LogPrint</span>(<span class="hljs-string">"decodeNetParams failed, detail: %+v"</span>, <span class="hljs-title">err</span>, <span class="hljs-string">"error"</span>)
        <span class="hljs-title"><span class="hljs-keyword">return</span></span> <span class="hljs-string">""</span>, <span class="hljs-string">""</span>, <span class="hljs-title">nil</span>
    }

    <span class="hljs-title">selfPub</span> :<span class="hljs-operator">=</span> <span class="hljs-string">""</span>
    <span class="hljs-title"><span class="hljs-keyword">if</span></span> <span class="hljs-title"><span class="hljs-keyword">bytes</span></span> :<span class="hljs-operator">=</span> <span class="hljs-title">getBytes</span>(<span class="hljs-title">dparams</span>[0]); len(<span class="hljs-keyword">bytes</span>) <span class="hljs-operator">></span> <span class="hljs-number">0</span> {
        selfPub <span class="hljs-operator">=</span> <span class="hljs-keyword">string</span>(<span class="hljs-keyword">bytes</span>[<span class="hljs-number">0</span>])
    }
    <span class="hljs-keyword">if</span> selfPub <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-string">""</span> {
        <span class="hljs-keyword">if</span> dparams[<span class="hljs-number">0</span>] <span class="hljs-operator">=</span><span class="hljs-operator">=</span> dparams[len(dparams) <span class="hljs-operator">-</span> <span class="hljs-number">1</span>] {
            selfPub <span class="hljs-operator">=</span> WebParams(r).Get(<span class="hljs-string">"data"</span>)
        } <span class="hljs-keyword">else</span> {
            LogPrint(<span class="hljs-string">"getPublicKey failed, selfID: "</span> <span class="hljs-operator">+</span> dparams[<span class="hljs-number">0</span>], <span class="hljs-string">"error"</span>)
            <span class="hljs-keyword">return</span> <span class="hljs-string">""</span>, <span class="hljs-string">""</span>, nil
        }
    }
    <span class="hljs-keyword">if</span> tokenVerify(dparams[<span class="hljs-number">1</span>], dparams[<span class="hljs-number">2</span>], []<span class="hljs-keyword">byte</span>(selfPub), []<span class="hljs-keyword">byte</span>(v_sysPrivateKey)) <span class="hljs-operator">!</span><span class="hljs-operator">=</span> nil {
        LogPrint(<span class="hljs-string">"tokenVerify failed, selfID: "</span> <span class="hljs-operator">+</span> dparams[<span class="hljs-number">0</span>], <span class="hljs-string">"error"</span>)
        <span class="hljs-keyword">return</span> <span class="hljs-string">""</span>, <span class="hljs-string">""</span>, nil
    }
    <span class="hljs-keyword">return</span> dparams[<span class="hljs-number">0</span>], selfPub, dparams
}

func doResponseOK(w http.ResponseWriter, r <span class="hljs-operator">*</span>http.Request, selfPub <span class="hljs-keyword">string</span>, datas ...[]<span class="hljs-keyword">byte</span>) {
    respBytes :<span class="hljs-operator">=</span> make([][]<span class="hljs-keyword">byte</span>, <span class="hljs-number">0</span>)
    token, signature :<span class="hljs-operator">=</span> tokenCreate([]<span class="hljs-keyword">byte</span>(selfPub), []<span class="hljs-keyword">byte</span>(v_sysPrivateKey))
    respBytes <span class="hljs-operator">=</span> append(respBytes, token, signature)
    respBytes <span class="hljs-operator">=</span> append(respBytes, datas...)
    ResponseOk(w, r, WebOk(respBytes))
}

<span class="hljs-comment">// GET /api/data/pull</span>
<span class="hljs-comment">// param: [selfID, token, signature], data: demo</span>
func WebDataPull(w http.ResponseWriter, r <span class="hljs-operator">*</span>http.Request) {
    <span class="hljs-keyword">if</span> selfID, selfPub, dparams :<span class="hljs-operator">=</span> doCheckPermission(r); dparams <span class="hljs-operator">!</span><span class="hljs-operator">=</span> nil <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span> selfPub <span class="hljs-operator">!</span><span class="hljs-operator">=</span> <span class="hljs-string">""</span> <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span> selfID <span class="hljs-operator">!</span><span class="hljs-operator">=</span> <span class="hljs-string">""</span> {
        <span class="hljs-keyword">if</span> pullBytes, err :<span class="hljs-operator">=</span> doWebPullForBytes(r, selfID, selfPub, WebParams(r).Get(<span class="hljs-string">"data"</span>)); err <span class="hljs-operator">!</span><span class="hljs-operator">=</span> nil {
            ResponseError(w, r, err.Error())
        } <span class="hljs-keyword">else</span> {
            doResponseOK(w, r, selfPub, pullBytes...)
            vBytesCache.Delete(WebParams(r).Get(<span class="hljs-string">"data"</span>))
        }
    }
    ResponseError(w, r, <span class="hljs-string">"permission denied"</span>)
}

<span class="hljs-comment">// GET /api/data/push</span>
<span class="hljs-comment">// param: [selfID, token, signature], data: demo</span>
func WebDataPush(w http.ResponseWriter, r <span class="hljs-operator">*</span>http.Request) {
    <span class="hljs-keyword">if</span> selfID, selfPub, dparams :<span class="hljs-operator">=</span> doCheckPermission(r); dparams <span class="hljs-operator">!</span><span class="hljs-operator">=</span> nil <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span> selfPub <span class="hljs-operator">!</span><span class="hljs-operator">=</span> <span class="hljs-string">""</span> <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span> selfID <span class="hljs-operator">!</span><span class="hljs-operator">=</span> <span class="hljs-string">""</span> {
        recvIds :<span class="hljs-operator">=</span> dparams[<span class="hljs-number">3</span>:]
        failedIds :<span class="hljs-operator">=</span> make([][]<span class="hljs-keyword">byte</span>, <span class="hljs-number">0</span>)
        <span class="hljs-keyword">for</span> i :<span class="hljs-operator">=</span> <span class="hljs-number">0</span>; i <span class="hljs-operator">&#x3C;</span> len(recvIds); i<span class="hljs-operator">+</span><span class="hljs-operator">+</span> {
            <span class="hljs-keyword">if</span> err :<span class="hljs-operator">=</span> doWebPushForBytes(r, selfID, selfPub, recvIds[i]); err <span class="hljs-operator">!</span><span class="hljs-operator">=</span> nil {
                failedIds <span class="hljs-operator">=</span> append(failedIds, []<span class="hljs-keyword">byte</span>(recvIds[i]))
                LogPrint(err.Error(), <span class="hljs-string">"error"</span>)
            }
        }
        doResponseOK(w, r, selfPub, failedIds...)
        <span class="hljs-keyword">return</span>
    }
    ResponseError(w, r, <span class="hljs-string">"permission denied"</span>)
}

func doWebPushForBytes(r <span class="hljs-operator">*</span>http.Request, selfID, selfPub, pushID <span class="hljs-keyword">string</span>) <span class="hljs-function"><span class="hljs-keyword">error</span> </span>{
    <span class="hljs-comment">// cache for bytes</span>
    buf :<span class="hljs-operator">=</span> []<span class="hljs-keyword">byte</span>(WebParams(r).Get(<span class="hljs-string">"data"</span>))
    <span class="hljs-keyword">if</span> len(buf) <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">0</span> {
        <span class="hljs-keyword">bytes</span>, err :<span class="hljs-operator">=</span> ioutil.ReadAll(r.Body)
        <span class="hljs-keyword">if</span> err <span class="hljs-operator">!</span><span class="hljs-operator">=</span> nil {
            <span class="hljs-keyword">return</span> err
        }
        buf <span class="hljs-operator">=</span> <span class="hljs-keyword">bytes</span>[:]
    }
    <span class="hljs-keyword">if</span> len(buf) <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">0</span> {
        <span class="hljs-keyword">return</span> fmt.Errorf(<span class="hljs-string">"invalid push bytes, recvID: %s"</span>, pushID)
    }
    addBytes(pushID, buf[:])
    <span class="hljs-comment">//infoLog("upload text successed, push: %s, size: %d", pushID, len(buf))</span>
    <span class="hljs-keyword">return</span> nil
}

func doWebPullForBytes(r <span class="hljs-operator">*</span>http.Request, selfID, sdPub, pullID <span class="hljs-keyword">string</span>) ([][]<span class="hljs-keyword">byte</span>, <span class="hljs-function"><span class="hljs-keyword">error</span>) </span>{
    <span class="hljs-keyword">return</span> getBytes(pullID), nil
}
</code></pre>]]></content:encoded>
            <author>jacky3@newsletter.paragraph.com (Jacky3)</author>
            <enclosure url="https://img.paragraph.com/cdn-cgi/image/format=auto/https://storage.googleapis.com/papyrus_images/30baac075a7194d28c79483d55d532f002cc443ec8ca84438982e765fac83f3a.png" length="0" type="image/png"/>
        </item>
    </channel>
</rss>