背景
星际文件系统 IPFS(InterPlanetary File System)是一个面向全球的、点对点的分布式文件系统,目标是为了补充(甚至是取代)目前统治互联网的超文本传输协议(HTTP),将所有具有相同文件系统的计算设备连接在一起。原理用基于内容的地址替代基于域名的地址,也就是用户寻找的不是某个地址而是储存在某个地方的内容,不需要验证发送者的身份,而只需要验证内容的哈希,通过这样可以让网页的速度更快、更安全、更健壮、更持久。
社交互联数据 Solid (Social Linked Data) 由万维网发明者 Tim Berners-Lee 发起,该项目旨在从根本上改变 Web 应用程序的中心化趋势, 它将真正地让数据所有权属于用户,并改善隐私问题。它是一组约定和工具,主要用于构建基于关联数据的分布式社交应用。
简单来说,IPFS 是一个任何人都可以访问的点对点存储平台(可以存储大量非结构化数据),Solid 是一个必须授权才可以使用的结构化数据计算和存储平台。
我们想要解决的问题是,如何私有化存储 IPFS 文件的哈希值。存储在 IPFS 上的文件哈希如果被泄漏,任何人都可以访问该文件,这是极不安全的,不是每个人都想把自己的文件上传到公有网络里。解决哈希值的泄漏有两种方案:
- 自建 IPFS 私有节点。该方案成本比较大,需要根据 IPFS 开放的协议重头来写;
- 自己写一套或使用成熟的互联网访问控制(WAC,Web Access Control)方案;
综合考虑成本、时间等因素,我们使用第二种方案。而第二种方案有非常多的实现,同时 Solid 是所有实现中最具开放性、代表性和权威性的。WAC 本身就是由 Tim Berners-Lee 在 2009 年提出的方案,如今用于 Solid 项目中是天作之合。
Solid 一个巨大的优势在于,它想将数据的所有权还归用户。如果想让用户愿意上传隐私数据到 IPFS 网络中,一个重要的因素在于如何保证用户上传的文件哈希不被其他人非法获取到,而 Solid 不仅可以安全的存储文件哈希值,还可以保证文件哈希值仅为用户所有。
于是我们写了个 solid-ipfs 框架用来解决这个问题。
解决方案
代码在 Github 上已开源:Eximua/solid-ipfs。
以下是以一个 WebId (用户在 Solid 网络中的唯一标识)为 https://alicea.solid.authing.... 的用户举例。
这是用户 Alicea 在 Solid 上的个人主页,其中 Profile 和 Public Folder 是可以公开被读取的数据(但是写入需要 Alicea 的权限确认),Inbox 为隐私数据,只有 Alicea 本人可以读取和写入。我们上传到 IPFS 网络中的私有文件哈希值将被存储到 Inbox 中。
简单来说的话,Profile、Public Folder 和 Inbox 可以理解为公有文件夹和私有文件夹。你所有的公有文件可以放到到公有文件夹里,私有的隐私数据可以放到私有文件夹内。
更简单来说,这就是 Solid Pod。
Solid 的数据存储使用 RDF,RDF 是用来描述网络资源的一个框架,他把所有资源以三元组的形式进行描述。比如(姚明,身高,226cm)定义了姚明的身高是 226 厘米。
示例中的 (alicea, type, Person) 则定义了 Alicea 的类型是人。同理,(alicea, hash, QmVCZeNR7eQNEu5Gekqqbnmk85v66cFHHjZZTGZxAqA2hD) 定义了 Alicea 的哈希值为 "QmVCZeNR7eQNEu5Gekqqbnmk85v66cFHHjZZTGZxAqA2hD"(该哈希来自于 IPFS 的某个文件)。
当然这种描述方式不是语义化的,仅供示例参考。
为了对这些 RDF 进行读写操作,RDF 官方封装了 rdflib.js ,使语义计算可以在 Web 上执行(也就是可以在浏览器里执行语义计算啦)。
我们最终语义化的私有存储样例如下:
可以看到,我们使用了 "ipfs/hash" 这个命名空间(可以理解成文件夹)来存储相应的 IPFS 文件哈希值,并且把每一个哈希值作为一个文件(哈希值.txt)存储到 Solid Pod 中。这样用户在使用 Solid 账号登录之后我们就可以读取用户的文件哈希值列表,然后从 IPFS 网络中拉取文件了。
具体的技术细节就不再细讲了,感兴趣的可以自行查看代码:Eximua/solid-ipfs。
使用 solid-ipfs
最后介绍一下 solid-ipfs 的使用方法。
solid-ipfs 其实不止可以写入私有数据,还可以写入公有数据。
安装
$ npm install solid-ipfs --save
使用
import SolidIPFS from 'solid-ipfs';const main = async () => {const solidIpfs = new SolidIPFS({url: 'YOUR_SOLID_URL', // e.g. https://alicea.solid.authing.cn/inbox/});const result = await solidIpfs.storeHash({hash: 'YOUR_IPFS_HASH',});console.log(result, result ? '保存成功' : '保存失败');
}main();
通过访问<YOURL_SOLID_URL>/ipfs/hash/
之后即可获得用户的 IPFS 哈希值列表
如果你还没有 Solid 账号,可以点击这里注册。
私有文件示例
- https://alicea.solid.authing....
import SolidIPFS from 'solid-ipfs';const main = async () => {const solidIpfs = new SolidIPFS({url: 'https://alicea.solid.authing.cn/inbox/', // inbox -> private});const result = await solidIpfs.storeHash({hash: 'YOUR_IPFS_HASH',});console.log(result, result ? '保存成功' : '保存失败');
}main();
公有文件示例
- https://alicea.solid.authing....
- https://alicea.solid.authing....
import SolidIPFS from 'solid-ipfs';const main = async () => {const solidIpfs = new SolidIPFS({url: 'https://alicea.solid.authing.cn/public/', // public -> public});const result = await solidIpfs.storeHash({hash: 'YOUR_IPFS_HASH',});console.log(result, result ? '保存成功' : '保存失败');
}main();
题外话,有的人可能对 RDF、语义计算这些概念不熟悉,这里再简单介绍下。
RDF 为什么叫资源描述框架,这个资源具体指代什么?
RDF 中的资源指代一切资源,它是一个通用的,可以定义一切的规范。比如:文件夹、文件、文件类型、代码、聊天内容、邮件等都属于资源,RDF 主要定义了这些不同类型资源的存储方式和数据规范。
我们为什么需要 RDF,它能解决什么问题?
RDF 看重语义化,可移植性和互操作性。语义化指你的数据存储规范必须是人类能理解的;可移植性代表当我想把我的数据从 A 平台移植到 B 平台时,不需要做任何的数据格式兼容;互操作性指我在 A 平台存储的数据在 B 平台上也可以进行读取和计算。
简单来说,就是所有的数据都共享同一套规范,减少为了兼容而产生的数据对齐时间,提升效率。RDF 是语义互联网(Web 3.0)的重要组成部分,它的愿景是全万维网的数据互通,变成一个大型计算平台,目前这个概念更有名的叫法为“知识图谱”。
Solid 资源列表:
- Solid 中文网
- Solid 中文社区
3. Solid Pod 中国节点
4. solid-ipfs