探索web3,热爱编程,热爱区块链! 努力通过技术实现睡后收入!
探索web3,热爱编程,热爱区块链! 努力通过技术实现睡后收入!

Subscribe to PictorHugo

Subscribe to PictorHugo
Share Dialog
Share Dialog
<100 subscribers
<100 subscribers
在我学过的知识中,计算机知识是最开放最容易获取的。在计算机领域中,前端技术又是更开放的一个存在,因为浏览器的存在,你可以随意查看一些大项目的前端源代码而不需要谁给你任何权限,故在前端领域中逆向某个项目是最容易的了。逆向这个词,可以简单理解为根据结果推导过程,一般解密也就是对未开放源码的程序进行的,因为没有源码,我们只能对程序本身进行解密等操作,从而猜测其实现是什么。今天的主角CyberConnect作为一个社交图谱的web3应用,目前其对用户主要开放的就是cyberconnect.me这个站点。逆向部分就是cyberconnect的follow,查看follwers、followings,注册等功能。根据逆向的代码还实现了一个简易版本的cyberconnect前端,链接如下。
https://easycyberconnect.000webhostapp.com/
目前支持搜索某个地址所有的followers、followings,不只是前50个哦,而且支持follow那些未关注的followers。假设你是一个大v,有很多人关注(followers可能达到了10000+),现在你想回关一些followers,现在无论是通过cyberconnect.me还是galaxy,还是
目前都没办法很方便的去操作。我上面的easycyberconnect也就是解决了这个痛点。
除了解决自己的痛点外,自己做这个事情也是以学习为目的。自己作为一个年轻的程序员,对任何新技术都还抱有着热情,而且光有热情还是不够的,还要参与进来。那么通过一个个小的项目,从做中学,是一个很好的开始。希望自己可以坚持,我也会将自己的学习过程分享给大家。
https://github.com/PictorHugo/EasyCyberConnect
大部分朋友可能并不关注实现的细节,这里我把源代码开源出来,从而也让大家使用起来更放心。因为这个项目只是一个纯前端的实现,我将它架设在了000webhostapp上,这样也不需要掏任何服务器费用。想尝试丝滑般关注体验的朋友,可以尝试下下面的链接。
https://easycyberconnect.000webhostapp.com/
这一部分记录了我对cyberconnect的研究,属于自己对学习过程的一个记录与整理。不感兴趣的朋友可以直接跳过。
在逆向前我要划定自己逆向的范围,因为cyberconnect确实是个很庞大的项目,像无头苍蝇一样到处看,必定是不行的。我逆向的目的如下:
查看超过top 50外的followers和followings
如何follow某个用户
确定了范围,接下来就要看具体方法了。从程序员的角度看,cyberconnect app也就是客户端就是一个前端程序,而且现在普遍的前端与后端交互的方式就是REST API。那么,我们只要获得,上面目的 中对应功能的REST API,并且了解REST API的各个参数是如何获得的,那么这个任务也就完成了。
我们从galaxy的前端入手(原因是galaxy比较快一点),先了解下是如何获得top 50的followers的,那么也许可以猜测出如何查看超过top50的followers。这里就要利用chrome的一个强大的抓包功能(在galaxy.eco页面上单击鼠标右键 → 点击inspect或者检查 → 切换到Network或者网络),通过这个抓包功能我们能看到每个从前端发送出去的HTTP/HTTPs请求,那么只要耐心,我们一定可以找到一些线索。
下面就是我找到本次任务中API的过程
打开浏览器抓包功能
打开galaxy.eco/galaxyid这个页面
查看每一个请求的响应,看看是否有包含followers的信息

通过以上方法,和一点耐心,终于找到了这个API,具体的API格式如下。这里可以看到比较重要的就是API BODY部分,如果理解了这一部分那么完成本task就不是问题了。API BODY又分为两个部分,一部分是query,这里使用的一种与graphql相关的语句,具体的作用就是查询后端服务器的哪些数据,因为我们没法看到后端的实现是什么,那么这一部分大概率先保持原状。初步理解这个graphql语句就当成一个函数,我们给它某些输入参数,这个函数就会返回一个JSON结构的数据,里面包含有followers和followings。另一部分是variables,目前看里面只有两个参数,分别是address和first,address就是当前的cyberconnect账户,first结合response结果也很好理解,也就是显示前50个数据。那么到这里我们也就有个想法,是不是修改first对应的值就可以了呢?比如改成100?我尝试后改成100还是不行,仍然只显示前50个数据。不过通过抓包发现cyberconnect的主站点上,在调用这个API的时候还多加了一个参数after,这个成为了本问题的突破口。
REST API请求:
HTTP METHOD: POST
API PATH: api.cybertino.io/connect
API BODY:
{
"query": "query GetIdentity($address: String!, $first: Int, $after: String) {\n identity(address: $address) {\n address\n ens\n social {\n twitter\n __typename\n }\n followerCount(namespace: \"\")\n followingCount(namespace: \"\")\n followers(first: $first, after: $after, namespace: \"\") {\n pageInfo {\n ...PageInfo\n __typename\n }\n list {\n ...Connect\n __typename\n }\n __typename\n }\n __typename\n }\n}\n\nfragment PageInfo on PageInfo {\n startCursor\n endCursor\n hasNextPage\n hasPreviousPage\n __typename\n}\n\nfragment Connect on Connect {\n address\n ens\n alias\n namespace\n __typename\n}\n",
"variables": {
"address": "0x037aa2a37b06699f9ea40c4830275620d367fefa",
"first": 50
}
}
REST API响应 (… 代表下面内容基本与上面一致,为了简洁考虑所以省略了):
{
"data": {
"identity": {
"address": "0x037aa2a37b06699f9ea40c4830275620d367fefa",
"ens": "pictorhugo.eth",
"social": {
"twitter": "PictorHugo",
"__typename": "Social"
},
"followerCount": 196,
"followingCount": 238,
"followings": {
"pageInfo": {
"startCursor": "0",
"endCursor": "49",
"hasNextPage": true,
"hasPreviousPage": false,
"__typename": "PageInfo"
},
"list": [
{
"address": "0xeefc6347cb77bbc878dd4ea0a616da69d7bc67f3",
"ens": "",
"alias": "",
"namespace": "Galaxy",
"__typename": "Connect"
},
...
],
"__typename": "ConnectionIdentityPage"
},
"followers": {
"pageInfo": {
"startCursor": "0",
"endCursor": "49",
"hasNextPage": true,
"hasPreviousPage": false,
"__typename": "PageInfo"
},
"list": [
{
"address": "0xee857065cbe599febfa772e96c17996deacd7830",
"ens": "",
"alias": "",
"namespace": "CyberConnect",
"__typename": "Connect"
},
...
],
"__typename": "ConnectionIdentityPage"
},
"__typename": "UserIdentity"
}
}
}
这个就是从cyberconnect上查找到带after参数的接口,其实这个信息也可以通过graphql语句得到,但因为一开始不是很熟悉它的语法没有注意到。

经过一些尝试,这个after参数里填写的也是一个地址string,而且通过这个after就可以实现翻页功能。具体意思就是,当after为空的时候,查找前first个数据,假设分别是,follower1,follower2,… folower50。在下一次执行查询语句的时候,将上一次的follower50的address填入after,first仍然是50,那么就可以查找到top50后面的数据。
想获取follow某个用户的API很容易,不用像task1里那样,从整个抓包数据中一点点过滤。因为我们只需要触发一下follow这个操作,那么接下来抓去到的请求一定与follow操作相关。抓去到的API如下。
REST API请求:
HTTP METHOD: POST
API PATH: api.cybertino.io/connect
API BODY:
{
"operationName": "connect",
"query": "mutation connect($input: UpdateConnectionInput!) {connect(input: $input) {result}}",
"variables": {
"input": {
"fromAddr": "0x037aa2a37b06699f9ea40c4830275620d367fefa",
"toAddr": "0xf601d1f8e82fc71514e88bc2b0a26d8a305f9985",
"alias": "",
"namespace": "Galaxy",
"signature": "...",
"signingKey": "...",
"operation": "{\"name\":\"follow\",\"from\":\"0x037aa2a37b06699f9ea40c4830275620d367fefa\",\"to\":\"0xf601d1f8e82fc71514e88bc2b0a26d8a305f9985\",\"namespace\":\"Galaxy\",\"network\":\"ETH\",\"timestamp\":1653799783858,\"alias\":\"\"}",
"network": "ETH",
"type": "FOLLOW"
}
}
}
REST API响应:
{
"data": {
"connect": {
"result": "SUCCESS"
}
}
}
这个API的获取难度非常低,但难点在于如何知道API请求中各个参数都应该怎样填写。下面让我们来按个分析一下。
operation,的值为connect,这应该代表follow操作的意思,因为我也同时抓去到了unfollow的请求,其中operation的值为disconnect。
query,其值依然是一个graphql语句,我们暂且不去理解细节。
下面分析variables中input里的各个参数。
fromAddr,其值是连接cyberconnect的钱包地址
toAddr,将要关注的钱包地址
alias,暂时不清楚作用
signature,将某些数据经过浏览器生成的私钥(为了方便,后面称其为私钥a)签名后的字符串,具体计算逻辑查看下面`signature与signingKey计算逻辑`那一节。
signingKey,私钥a对应的公钥经过hash后的值,具体可以查看`signature与signingKey计算逻辑`。
operation,包括follow动作的发起人,将要follow的人等信息,具体和上面介绍过的都差不多,只是没有signature和signingKey等参数。
network,目前应该可以填写ETH和Solana两种。
type,是操作的名字。
浏览完上面每个参数的介绍后,我们可以发现,大部分参数都是很好获取的,比如network,type等,都是固定填写就好。但signingKey与signature就不太好理解了,下面让我们重点关注这两个参数。
为了获得这两个参数的计算逻辑,我使用了两种方法,一种是归纳法,一种是查看源码法。
归纳法:
我尝试了多次的follow操作,发现signingKey是一直不变的,从而可以断定这是一个存储在本地的值,那么也就很有可能是连接本网站的钱包地址经过hash后得到的值(后面被证明是错误的,请继续看)。但是signature却次次不一样,一种可能的猜测是,每次计算签名的时候加入了时间戳信息。
查看源码法: 光靠归纳的方法去猜测肯定是不行了,还是得看源码,这也是前端代码的一个好处,那么接下来的问题就是:
查看哪个具体文件的源码
如何看源码
第一个问题,chrome的抓包功能帮我们解决了,下面截图中有一列叫做initiator,这里就代表了这个请求发起的时候所对应的代码。


但当我们打开这个源码的时候却发现是这样的,基本上不具有任何可读性,这个时候我们可以通过点击左下角的按钮从而格`{}`式化源码文件,但也只能是让格式变的好看点,各种变量名仍然是不具有可读性的。下面就只能靠耐性了,说实在的,接下来是有点枯燥的,因为只能一点点去钻研这类minified(前端的代码压缩)过的代码,我下面抽取一段,分享一下基本的思路。下面就是当用户出发follow按键的时候会触发的函数,其核心逻辑就在switch case语句中,如果熟悉js的async/await代码实现原理的朋友看下面的代码应该并不陌生,或者大家可以查看下面这篇文章。其是就是一种状态机的转换。我下面实际的说一下,首先当a.lable为0的时候执行相应的语句,其返回值为this.getAddress(),当a.label为1的时候执行相应的语句,并且通过a.sent可以获得a.label为0时候的返回值,接下来就以此类推。
http://codereform.com/blog/post/es6-generators-and-asyncawait-in-typescript/
通过上面的方式,我通读了这一部分的代码,总结了一个follow过程的流程图给大家。具体的代码大家可以查我已经开源的代码。

研究这一部分后,主要获得一个信息,就是对数据进行签名的私钥并不是连接钱包的账户的私钥,而是前端自己生成的一个公钥和私钥对。这样确实也能让follow操作更丝滑一点,因为每次都要用户自己签名一次就去follow一个人还是挺费劲的。
在我以为理解了signature的计算后就能自己脱离cyberconnect前端去follow用户的时候,我发现cyberconnect还是返回了一个error,不能让我成功follow,仔细推测后,发现有个流程被我漏掉了,就是当前端无法从indexed db超找到keypair的时候其实是会发送一个registerKey的请求,因为我漏掉了这个请求所以follow会失败。下面就是register key的REST API。
REST API请求:
HTTP METHOD: POST
API PATH: api.cybertino.io/connect
API BODY:
{
"operationName": "registerKey",
"query": "mutation registerKey($input: RegisterKeyInput!) {\n registerKey(input: $input) {\n result\n }\n }",
"variables": {
"input": {
"address": "0x037aa2a37b06699f9ea40c4830275620d367fefa",
"message": "I authorize CyberConnect from this device using signing key:....",
"signature": "....",
"network": "ETH"
}
}
}
那么到此,我们也基本上理解了如何去通过REST API去follow一个用户。
在我学过的知识中,计算机知识是最开放最容易获取的。在计算机领域中,前端技术又是更开放的一个存在,因为浏览器的存在,你可以随意查看一些大项目的前端源代码而不需要谁给你任何权限,故在前端领域中逆向某个项目是最容易的了。逆向这个词,可以简单理解为根据结果推导过程,一般解密也就是对未开放源码的程序进行的,因为没有源码,我们只能对程序本身进行解密等操作,从而猜测其实现是什么。今天的主角CyberConnect作为一个社交图谱的web3应用,目前其对用户主要开放的就是cyberconnect.me这个站点。逆向部分就是cyberconnect的follow,查看follwers、followings,注册等功能。根据逆向的代码还实现了一个简易版本的cyberconnect前端,链接如下。
https://easycyberconnect.000webhostapp.com/
目前支持搜索某个地址所有的followers、followings,不只是前50个哦,而且支持follow那些未关注的followers。假设你是一个大v,有很多人关注(followers可能达到了10000+),现在你想回关一些followers,现在无论是通过cyberconnect.me还是galaxy,还是
目前都没办法很方便的去操作。我上面的easycyberconnect也就是解决了这个痛点。
除了解决自己的痛点外,自己做这个事情也是以学习为目的。自己作为一个年轻的程序员,对任何新技术都还抱有着热情,而且光有热情还是不够的,还要参与进来。那么通过一个个小的项目,从做中学,是一个很好的开始。希望自己可以坚持,我也会将自己的学习过程分享给大家。
https://github.com/PictorHugo/EasyCyberConnect
大部分朋友可能并不关注实现的细节,这里我把源代码开源出来,从而也让大家使用起来更放心。因为这个项目只是一个纯前端的实现,我将它架设在了000webhostapp上,这样也不需要掏任何服务器费用。想尝试丝滑般关注体验的朋友,可以尝试下下面的链接。
https://easycyberconnect.000webhostapp.com/
这一部分记录了我对cyberconnect的研究,属于自己对学习过程的一个记录与整理。不感兴趣的朋友可以直接跳过。
在逆向前我要划定自己逆向的范围,因为cyberconnect确实是个很庞大的项目,像无头苍蝇一样到处看,必定是不行的。我逆向的目的如下:
查看超过top 50外的followers和followings
如何follow某个用户
确定了范围,接下来就要看具体方法了。从程序员的角度看,cyberconnect app也就是客户端就是一个前端程序,而且现在普遍的前端与后端交互的方式就是REST API。那么,我们只要获得,上面目的 中对应功能的REST API,并且了解REST API的各个参数是如何获得的,那么这个任务也就完成了。
我们从galaxy的前端入手(原因是galaxy比较快一点),先了解下是如何获得top 50的followers的,那么也许可以猜测出如何查看超过top50的followers。这里就要利用chrome的一个强大的抓包功能(在galaxy.eco页面上单击鼠标右键 → 点击inspect或者检查 → 切换到Network或者网络),通过这个抓包功能我们能看到每个从前端发送出去的HTTP/HTTPs请求,那么只要耐心,我们一定可以找到一些线索。
下面就是我找到本次任务中API的过程
打开浏览器抓包功能
打开galaxy.eco/galaxyid这个页面
查看每一个请求的响应,看看是否有包含followers的信息

通过以上方法,和一点耐心,终于找到了这个API,具体的API格式如下。这里可以看到比较重要的就是API BODY部分,如果理解了这一部分那么完成本task就不是问题了。API BODY又分为两个部分,一部分是query,这里使用的一种与graphql相关的语句,具体的作用就是查询后端服务器的哪些数据,因为我们没法看到后端的实现是什么,那么这一部分大概率先保持原状。初步理解这个graphql语句就当成一个函数,我们给它某些输入参数,这个函数就会返回一个JSON结构的数据,里面包含有followers和followings。另一部分是variables,目前看里面只有两个参数,分别是address和first,address就是当前的cyberconnect账户,first结合response结果也很好理解,也就是显示前50个数据。那么到这里我们也就有个想法,是不是修改first对应的值就可以了呢?比如改成100?我尝试后改成100还是不行,仍然只显示前50个数据。不过通过抓包发现cyberconnect的主站点上,在调用这个API的时候还多加了一个参数after,这个成为了本问题的突破口。
REST API请求:
HTTP METHOD: POST
API PATH: api.cybertino.io/connect
API BODY:
{
"query": "query GetIdentity($address: String!, $first: Int, $after: String) {\n identity(address: $address) {\n address\n ens\n social {\n twitter\n __typename\n }\n followerCount(namespace: \"\")\n followingCount(namespace: \"\")\n followers(first: $first, after: $after, namespace: \"\") {\n pageInfo {\n ...PageInfo\n __typename\n }\n list {\n ...Connect\n __typename\n }\n __typename\n }\n __typename\n }\n}\n\nfragment PageInfo on PageInfo {\n startCursor\n endCursor\n hasNextPage\n hasPreviousPage\n __typename\n}\n\nfragment Connect on Connect {\n address\n ens\n alias\n namespace\n __typename\n}\n",
"variables": {
"address": "0x037aa2a37b06699f9ea40c4830275620d367fefa",
"first": 50
}
}
REST API响应 (… 代表下面内容基本与上面一致,为了简洁考虑所以省略了):
{
"data": {
"identity": {
"address": "0x037aa2a37b06699f9ea40c4830275620d367fefa",
"ens": "pictorhugo.eth",
"social": {
"twitter": "PictorHugo",
"__typename": "Social"
},
"followerCount": 196,
"followingCount": 238,
"followings": {
"pageInfo": {
"startCursor": "0",
"endCursor": "49",
"hasNextPage": true,
"hasPreviousPage": false,
"__typename": "PageInfo"
},
"list": [
{
"address": "0xeefc6347cb77bbc878dd4ea0a616da69d7bc67f3",
"ens": "",
"alias": "",
"namespace": "Galaxy",
"__typename": "Connect"
},
...
],
"__typename": "ConnectionIdentityPage"
},
"followers": {
"pageInfo": {
"startCursor": "0",
"endCursor": "49",
"hasNextPage": true,
"hasPreviousPage": false,
"__typename": "PageInfo"
},
"list": [
{
"address": "0xee857065cbe599febfa772e96c17996deacd7830",
"ens": "",
"alias": "",
"namespace": "CyberConnect",
"__typename": "Connect"
},
...
],
"__typename": "ConnectionIdentityPage"
},
"__typename": "UserIdentity"
}
}
}
这个就是从cyberconnect上查找到带after参数的接口,其实这个信息也可以通过graphql语句得到,但因为一开始不是很熟悉它的语法没有注意到。

经过一些尝试,这个after参数里填写的也是一个地址string,而且通过这个after就可以实现翻页功能。具体意思就是,当after为空的时候,查找前first个数据,假设分别是,follower1,follower2,… folower50。在下一次执行查询语句的时候,将上一次的follower50的address填入after,first仍然是50,那么就可以查找到top50后面的数据。
想获取follow某个用户的API很容易,不用像task1里那样,从整个抓包数据中一点点过滤。因为我们只需要触发一下follow这个操作,那么接下来抓去到的请求一定与follow操作相关。抓去到的API如下。
REST API请求:
HTTP METHOD: POST
API PATH: api.cybertino.io/connect
API BODY:
{
"operationName": "connect",
"query": "mutation connect($input: UpdateConnectionInput!) {connect(input: $input) {result}}",
"variables": {
"input": {
"fromAddr": "0x037aa2a37b06699f9ea40c4830275620d367fefa",
"toAddr": "0xf601d1f8e82fc71514e88bc2b0a26d8a305f9985",
"alias": "",
"namespace": "Galaxy",
"signature": "...",
"signingKey": "...",
"operation": "{\"name\":\"follow\",\"from\":\"0x037aa2a37b06699f9ea40c4830275620d367fefa\",\"to\":\"0xf601d1f8e82fc71514e88bc2b0a26d8a305f9985\",\"namespace\":\"Galaxy\",\"network\":\"ETH\",\"timestamp\":1653799783858,\"alias\":\"\"}",
"network": "ETH",
"type": "FOLLOW"
}
}
}
REST API响应:
{
"data": {
"connect": {
"result": "SUCCESS"
}
}
}
这个API的获取难度非常低,但难点在于如何知道API请求中各个参数都应该怎样填写。下面让我们来按个分析一下。
operation,的值为connect,这应该代表follow操作的意思,因为我也同时抓去到了unfollow的请求,其中operation的值为disconnect。
query,其值依然是一个graphql语句,我们暂且不去理解细节。
下面分析variables中input里的各个参数。
fromAddr,其值是连接cyberconnect的钱包地址
toAddr,将要关注的钱包地址
alias,暂时不清楚作用
signature,将某些数据经过浏览器生成的私钥(为了方便,后面称其为私钥a)签名后的字符串,具体计算逻辑查看下面`signature与signingKey计算逻辑`那一节。
signingKey,私钥a对应的公钥经过hash后的值,具体可以查看`signature与signingKey计算逻辑`。
operation,包括follow动作的发起人,将要follow的人等信息,具体和上面介绍过的都差不多,只是没有signature和signingKey等参数。
network,目前应该可以填写ETH和Solana两种。
type,是操作的名字。
浏览完上面每个参数的介绍后,我们可以发现,大部分参数都是很好获取的,比如network,type等,都是固定填写就好。但signingKey与signature就不太好理解了,下面让我们重点关注这两个参数。
为了获得这两个参数的计算逻辑,我使用了两种方法,一种是归纳法,一种是查看源码法。
归纳法:
我尝试了多次的follow操作,发现signingKey是一直不变的,从而可以断定这是一个存储在本地的值,那么也就很有可能是连接本网站的钱包地址经过hash后得到的值(后面被证明是错误的,请继续看)。但是signature却次次不一样,一种可能的猜测是,每次计算签名的时候加入了时间戳信息。
查看源码法: 光靠归纳的方法去猜测肯定是不行了,还是得看源码,这也是前端代码的一个好处,那么接下来的问题就是:
查看哪个具体文件的源码
如何看源码
第一个问题,chrome的抓包功能帮我们解决了,下面截图中有一列叫做initiator,这里就代表了这个请求发起的时候所对应的代码。


但当我们打开这个源码的时候却发现是这样的,基本上不具有任何可读性,这个时候我们可以通过点击左下角的按钮从而格`{}`式化源码文件,但也只能是让格式变的好看点,各种变量名仍然是不具有可读性的。下面就只能靠耐性了,说实在的,接下来是有点枯燥的,因为只能一点点去钻研这类minified(前端的代码压缩)过的代码,我下面抽取一段,分享一下基本的思路。下面就是当用户出发follow按键的时候会触发的函数,其核心逻辑就在switch case语句中,如果熟悉js的async/await代码实现原理的朋友看下面的代码应该并不陌生,或者大家可以查看下面这篇文章。其是就是一种状态机的转换。我下面实际的说一下,首先当a.lable为0的时候执行相应的语句,其返回值为this.getAddress(),当a.label为1的时候执行相应的语句,并且通过a.sent可以获得a.label为0时候的返回值,接下来就以此类推。
http://codereform.com/blog/post/es6-generators-and-asyncawait-in-typescript/
通过上面的方式,我通读了这一部分的代码,总结了一个follow过程的流程图给大家。具体的代码大家可以查我已经开源的代码。

研究这一部分后,主要获得一个信息,就是对数据进行签名的私钥并不是连接钱包的账户的私钥,而是前端自己生成的一个公钥和私钥对。这样确实也能让follow操作更丝滑一点,因为每次都要用户自己签名一次就去follow一个人还是挺费劲的。
在我以为理解了signature的计算后就能自己脱离cyberconnect前端去follow用户的时候,我发现cyberconnect还是返回了一个error,不能让我成功follow,仔细推测后,发现有个流程被我漏掉了,就是当前端无法从indexed db超找到keypair的时候其实是会发送一个registerKey的请求,因为我漏掉了这个请求所以follow会失败。下面就是register key的REST API。
REST API请求:
HTTP METHOD: POST
API PATH: api.cybertino.io/connect
API BODY:
{
"operationName": "registerKey",
"query": "mutation registerKey($input: RegisterKeyInput!) {\n registerKey(input: $input) {\n result\n }\n }",
"variables": {
"input": {
"address": "0x037aa2a37b06699f9ea40c4830275620d367fefa",
"message": "I authorize CyberConnect from this device using signing key:....",
"signature": "....",
"network": "ETH"
}
}
}
那么到此,我们也基本上理解了如何去通过REST API去follow一个用户。
e.prototype.connect = function(e, t, n) {
var r, o, s, c;
return void 0 === t && (t = ""),
void 0 === n && (n = x.ConnectionType.FOLLOW),
i(this, void 0, void 0, (function() {
var i, u, f, d, l, h, b;
return a(this, (function(a) {
switch (a.label) {
case 0:
return a.trys.push([0, 8, , 9]),
i = this,
[4, this.getAddress()];
case 1:
return i.address = a.sent(),
[4, this.authWithSigningKey()];
case 2:
return a.sent(),
u = {
name: n.toLowerCase(),
from: this.address,
to: e,
namespace: this.namespace,
network: this.chain,
timestamp: Date.now(),
alias: t
},
[4, (0,
E.signWithSigningKey)(JSON.stringify(u), this.address)];
case 3:
return f = a.sent(),
[4, (0,
E.getPublicKey)(this.address)];
case 4:
return d = a.sent(),
l = {
fromAddr: this.address,
toAddr: e,
alias: t,
namespace: this.namespace,
signature: f,
signingKey: d,
operation: JSON.stringify(u),
network: this.chain,
type: n
},
[4, (0,
v.follow)(l, this.endpoint.cyberConnectApi)];
case 5:
return h = a.sent(),
"INVALID_SIGNATURE" !== (null === (r = null === h || void 0 === h ? void 0 : h.data) || void 0 === r ? void 0 : r.connect.result) ? [3, 7] : [4, (0,
E.clearSigningKey)()];
case 6:
throw a.sent(),
new y.ConnectError(y.ErrorCode.GraphqlError,null === (o = null === h || void 0 === h ? void 0 : h.data) || void 0 === o ? void 0 : o.connect.result);
case 7:
if ("SUCCESS" !== (null === (s = null === h || void 0 === h ? void 0 : h.data) || void 0 === s ? void 0 : s.connect.result))
throw new y.ConnectError(y.ErrorCode.GraphqlError,null === (c = null === h || void 0 === h ? void 0 : h.data) || void 0 === c ? void 0 : c.connect.result);
return [3, 9];
case 8:
throw b = a.sent(),
new y.ConnectError(y.ErrorCode.GraphqlError,b.message || b);
case 9:
return M.DFLAG && this.ceramicConnect(e, t),
[2]
}
}
))
}
))
}
e.prototype.connect = function(e, t, n) {
var r, o, s, c;
return void 0 === t && (t = ""),
void 0 === n && (n = x.ConnectionType.FOLLOW),
i(this, void 0, void 0, (function() {
var i, u, f, d, l, h, b;
return a(this, (function(a) {
switch (a.label) {
case 0:
return a.trys.push([0, 8, , 9]),
i = this,
[4, this.getAddress()];
case 1:
return i.address = a.sent(),
[4, this.authWithSigningKey()];
case 2:
return a.sent(),
u = {
name: n.toLowerCase(),
from: this.address,
to: e,
namespace: this.namespace,
network: this.chain,
timestamp: Date.now(),
alias: t
},
[4, (0,
E.signWithSigningKey)(JSON.stringify(u), this.address)];
case 3:
return f = a.sent(),
[4, (0,
E.getPublicKey)(this.address)];
case 4:
return d = a.sent(),
l = {
fromAddr: this.address,
toAddr: e,
alias: t,
namespace: this.namespace,
signature: f,
signingKey: d,
operation: JSON.stringify(u),
network: this.chain,
type: n
},
[4, (0,
v.follow)(l, this.endpoint.cyberConnectApi)];
case 5:
return h = a.sent(),
"INVALID_SIGNATURE" !== (null === (r = null === h || void 0 === h ? void 0 : h.data) || void 0 === r ? void 0 : r.connect.result) ? [3, 7] : [4, (0,
E.clearSigningKey)()];
case 6:
throw a.sent(),
new y.ConnectError(y.ErrorCode.GraphqlError,null === (o = null === h || void 0 === h ? void 0 : h.data) || void 0 === o ? void 0 : o.connect.result);
case 7:
if ("SUCCESS" !== (null === (s = null === h || void 0 === h ? void 0 : h.data) || void 0 === s ? void 0 : s.connect.result))
throw new y.ConnectError(y.ErrorCode.GraphqlError,null === (c = null === h || void 0 === h ? void 0 : h.data) || void 0 === c ? void 0 : c.connect.result);
return [3, 9];
case 8:
throw b = a.sent(),
new y.ConnectError(y.ErrorCode.GraphqlError,b.message || b);
case 9:
return M.DFLAG && this.ceramicConnect(e, t),
[2]
}
}
))
}
))
}
No activity yet