HOMEBLOGABOUT

如何实现基于 Activitypub 协议服务器

在本系列文章中将介绍如何实现基于 Activitypub 协议的服务器

首先,您需要了解什么是 Activitypub ,在本系列文章中,并不会过多的介绍协议的基础知识,但是内容中会提供关于协议细节的链接。

它是一套 w3c 推出的开放式分散式社交网络协议标准,你可以通过这套协议来实现自己的服务器。

请查阅 ActivityPub (w3.org) 来了解详情。


本文首选的编程语言为 Golang , 所以首先需要准备的是 Golang 开发环境。

我们还需要准备一个测试用的本地 https 服务器,你可以使用 ngrok 服务来搭建一个。

actor

actor 是一个公开访问的 JSON-LD 文档,它提供公开使用者的个人信息的数据,供其它的服务器查询,下面是该文档的样式

{
  "@context": ["https://www.w3.org/ns/activitystreams",
               {"@language": "ja"}],
  "type": "Person",
  "id": "https://kenzoishii.example.com/",
  "following": "https://kenzoishii.example.com/following.json",
  "followers": "https://kenzoishii.example.com/followers.json",
  "liked": "https://kenzoishii.example.com/liked.json",
  "inbox": "https://kenzoishii.example.com/inbox.json",
  "outbox": "https://kenzoishii.example.com/feed.json",
  "preferredUsername": "kenzoishii",
  "name": "石井健蔵",
  "summary": "この方はただの例です",
  "icon": [
    "https://kenzoishii.example.com/image/165987aklre4"
  ]
}

下面,我们将使用 Golang 的 gin 框架来制作一个 demo

r := gin.Default()
r.GET("/actor", GetActorHandler)

这个函数是 Activitypub 协议的 Actor 的 JSON-LD 标准数据返回

我们需要生成一个公钥和私钥,请生成公钥和私钥。

func GetActorHandler(c *gin.Context) {

    address := "https://2222d352b2aa.ngrok.io"
    actor := fmt.Sprintf("https://%s/actor/hvturingga", address)
    inbox := fmt.Sprintf("https://%s/actor/hvturingga/inbox", address)
    
    con := []string{"https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1"}
    
    publicKey := map[string]string{
        "id": 1,
        "owner": actor,
        "publicKeyPem": PublicKey, // 在这里放上刚才生成的公钥
    }

    c.JSON(200, gin.H{
        "@context":          con,
        "type":              "Person",
        "id":                actor,
        "preferredUsername": "hvturingga",
        "name":              "hvturingga",
        "inbox":             inbox,
        "outbox":            inbox,
        "publicKey":         publicKey,
    })
}

现在我们就生成了一个名为 hvturingga 的用户

Webfinger

我们还需要一个 Webfinger 的 http 路由,它作为查询该服务器是否存在这个用户名的功能

r.GET("/.well-known/webfinger", GetWebFingerHandler)
// WebFinger 和 WebFingerLinks 组成标准 Activitypub 的 JSON-LD 协议
type WebFinger struct {
    Subject string `json:"subject"`
    Links   []WebFingerLinks `json:"links"`
}

// WebFingerLinks 供 WebFinger 使用
type WebFingerLinks struct {
    Rel  string `json:"rel"`
    Type string `json:"type"`
    Href string `json:"href"`
}

func GetWebFingerHandler(c *gin.Context) {
    address := "https://2222d352b2aa.ngrok.io"
    
    links := []models.WebFingerLinks{
        {
            Rel: "self",
            Type: "application/activity+json",
            Href: fmt.Sprintf("https://%s/actor", address),
        },
    }
    finger := &models.WebFinger{
        Subject: fmt.Sprintf("acct:[email protected]%s", address),
        Links: links,
    }
}

现在,我们可以测试是否可以找到你刚刚创建的用户,使用 mastodon 的一个实例来测试是否可以找到

输入 [email protected] , 你将看到如下界面。

屏幕截图 2021-02-13 192235.png


在本文中,大致介绍了 actor 和 Webfinger 的实现过程。

仅仅是提供了一个实现过程,具体的代码实现和相关知识需要自行搜索和实现

参考链接:

Activitypub 协议的文档· ActivityPub (w3.org)

用 nodejs 实现的教程 · Decentralizing Social Interactions with ActivityPub - Mozilla Hacks - the Web developer blog

mastodon 作者的教程 · How to implement a basic ActivityPub server - Official Mastodon Blog (joinmastodon.org)

openssl 官方网站了解如何生成密钥 · /index.html (openssl.org)

用于本地测试的 https 服务器 · ngrok - secure introspectable tunnels to localhost

© 2021 disism.com All Rights Reserved. Built with Gatsby