开放式社交媒体个人备忘

https://fediverse.party

个人站点

WordPress

使用人数足够多,两边的插件都有,”千客“就是基于这个方案做的。在Blog方面应该非常强,有技术支持的情况下可扩展性也会很高。

microblog.pub

https://docs.microblog.pub/

相比Mastodon或许更适合个站? 单用户 AcitivityPub和IndieWeb的双向支持

Dolphin

轻量级的,适合个人使用的。前端型技术栈 , 二次开发门槛相对来说是比较低吧

IndieWeb + Fediverse

很多都是 Ryan Barrett 的作品

能转换各种社交网络间的数据。举例:可以把IndieWeb站点上的数据发布到Mastodon上

Bridgy

https://brid.gy/

Granary

https://granary.io/

https://github.com/snarfed/granary

转换数据格式,让支持各种协议的平台成为数据源

以API形式提供的,公开数据作为管道通过这类服务也还是可以的。最好有其他备选项。

Webmention Demo

为本站加上Webmention支持,并尝试与其他自称支持webmention的服务交互。
通过订阅webmention.io提供的RSS源,也能足够及时地收到提示,各种信息汇集到一个视图下,注意力可聚焦。

Fediverse

发一个toot提及博文并发webmention,Blog上的脚本从中构造出用于交互的链接,包括操作栏和联邦宇宙入口。

比起把toot上下文集成进来作为评论区,目前还是更倾向把移步Fedivese讨论,因为可以让读者在自己的主场回复。

Comment

  • 尝试做一个评论插件,把页面的webmention加载出来。

参考时间线模板

1
2
3
4
5
6
7
8

<div class="timeline">
<article class="media">
<div class="media-content">

</div>
</article>
</div>

参考KAIX.IN的Webmention区实现,对Fediverse入口做了特殊处理,增加了Emoji来加强语义

尝试

Micro.blog

Micro.blogs声称会把对博文的回复作为Webmention来对待

Hosted blogs on Micro.blog can also receive Webmentions from other sites outside of Micro.blog. If the site URL has been verified in a Micro.blog user’s profile, Micro.blog can also match the incoming Webmention with a Micro.blog user and use their username. If not, Micro.blog will create a special “domain name” user for the incoming Webmention.

测试结果是站外的webmention能发送成功,返回202,但是无法在Micro.blog内看到来自这里的Webmention。
应该是接收了,但是不在Micro.blog体系内就难以用@xxx的形式展现出来,还是因为这个站的域名是二级域名,所以不被认可呢?
看来还是“自成一格”的

独立Blog

Re:Linked

能找到基于相同的理由在做相同的事的博客,还是很欣慰的。

  • 2021-02-02 在页面里没有找到webmention相关link,也许是出于某些考虑暂时撤下了?
  • 2021-02-03 在Fediverse里联系上,webmention成功!

KAIX.IN

从上文溯源就会找到这位的Blog。

真是一位了不起的咖啡师。


测试结果,返回201了,看来是发送成功了呢。

在对方页面上看到链接了,评论区实现方式好精巧,值得参考。

参考社区入口链接的处理方式,对关联到Mastodon的webmention做特殊处理吧。

Mastodon Integration

(RSS->Mastodon)->Webmention->Share

思路

为每一篇博文生成一个对应的Toot,并把Toot链接回链到博文上,形成双向链接,以Toot接入Fediverse;
前者有web规范,以前有linkback,pingback等,这里用Indiweb推荐的Webmention形式

步骤

  1. 用hexo生成atom.xml文件,即Blog文章的订阅源

  2. 用Huginn/IFTTT/自定义bot订阅1的RSS源,对每一条目调用Mastodon API, POST Statuses,content为我发布了博客文章: {title} {url}

  3. 取2的response body,解析为JSON对象,取其id,即为toot的id

  4. 调用telegraph API, source为3中返回的id拼装出的url https://{mastodonDomain}/interact/{statusId}?type=reply,target为RSS每个条目的url

    • telegraph会把这个消息发送给对应的webmention server
  5. 在Blog模板添加“分享”脚本,调用webmention API,获取页面收到的webmention

  6. 过滤5中获取的webmention,过滤出由自己mastodon实例发出的webmention(根据域名和作者)
    6-1. 取webmention的url,即第4步拼装出的url,把url设置到【回复】链接上;
    6-2. 把type=reply替换成type=reblog,把url设置到【转嘟】链接上
    6-3. 把type=reply替换成type=favourite,设置到【喜欢】链接上

对Matataki架构的一些思考

安全

  1. https://github.com/Matataki-io/Matataki-FE/issues/997 的回应

accessToken 如果放在非HttpOnly的Cookie里,脚本注入成功的话基本=拿到Token的值了。
API Server 和 Matataki-FE 并不在同一个domain下,Matataki-FE需要通过Header传递accessToken。如果是Android或是iOS这样的应用,那么找个相对安全的地方放置Token还是相对容易的,但是浏览器端都不好办,有的单页应用是直接放在被闭包保护的state里的,浏览器重新加载页面的话就重新登入。而要在有页面切换的应用使用,解决方案基本只会是Cookie,换成LocalStorage之类的地方只会更不保险。

大部分只是在开发层面上前端后端分离的,最后部署的时候还是会放在一个域下,站点前端控制器和API前端控制器分开来管理,前者做CSRF Token配合HttpOnly Secure Cookie传递SESSIONID或者JWT,后者用OAuth2,也更倾向和有后端的应用对接(不泄露ClientSecret),走authorization-code模式,安全性相对更高。

现在Matataki主站使用的基本是把两者当作一体对待的一般login,不过API Server Domain不同导致CSRF Token+HttpOnly Secure Cookie模式没法使用了。

而Developer平台提供的对接形式应该算是implicit模式的变种,应该是考虑到对接的APP不少是无后端的。

一般的APP用短期的JWT放在可被读到的Cookie里也还好,理由也是攻击的时间窗口并没有那么长,影响多少可控,而当前API涉及范围还挺大的,除了平台文章相关功能还包括Fan票部分,这里关系到用户的核心资产,如果授权了Fan票操作权限看来没有额度授权之类的,非常敏感了。

目前想到的主要改造思路:

  1. 权限进一步细化,授予Fan票相关权限的时候加上额度限制,并控制JWT的有效时长
  2. 涉及到转账、支付相关的API需要二次认证,可以有小额免密类的提升体验

这两个不调整架构也能做,要注意的细节会比较多,有API列表的话应该是针对特定API加强认证

对Matataki主站的改造可以考虑在matataki.io域名上搭一层薄的API转发网关,主站走这个API,accessToken放在主站的HttpOnly Secure Cookie里,在网关转发的时候把Token放到Header里提交给API Server

Developer那边也建议支持authorization-code,让第三方服务的后端也能用上HttpOnly Secure Cookie,现在的API Server模式在Server to Server的交互中使用。
现在的模式在静态Blog这种无后端的场景还是很有用,不过一个不注意是真的有可能从脚本泄露的。


如果Login Success在API Server的Domain下写HttpOnly Secure Cookie,API的调用根据条件检查Cookie和Header会如何呢?
没有其他后端的纯Client App/DAPP也没必要取这个Cookie里的JWT传给其他服务端,不能用JS读出来不是问题,有必要和其他后端交互的应用可以改造成authorization-code模式,在使用上似乎有优势。
问题在于一次登入就能在多个使用API的Client App应该是通用,会造成CSRF。即使根据申请的App来维护Cross-Origin清单,恶意站点如果去事先申请App,恐怕是没有那个精力去一个个审查的。这类跨站授权本来也是靠用户自己判断Client App是否值得信任,毕竟用户自己点授权的么。但是用户信任A站点生成的Token如果能被拿到B去使用性质就不一样了

如果是靠API返回值记录一个accessToken(和现在一样),再额外加一个HttpOnly Secure Cookie呢?
即使accessToken通过脚本泄露了,没有Cookie请求也无法通过;
即使在网站A请求到了Cookie,用户被某种方式引导带着Cookie访问危险站点B,没有accessToken也不行;
这样攻击就要再网站A构造脚本注入,读到accessToken后引导到危险站点B,两个都全了。那么签发accessToken的时候限定使用域,在B用这个accessToken请求会发现这个accessToken只能在站点A使用,也能拦截下来;

直接在Cookie里带上授权域信息也行,如果用同一个KEY,体验上会变成在其中一个App登入,另一个会被下线,从安全来说倒也不是问题;
如果不同的clientId写进不同的KEY里,accessToken里带上clientId,根据不同的clientId去检查不同的Cookie,应该能做到并存

这种模式下,API Server检查accessToken的逻辑是这样的:

  1. 判断API Endpoint是否需要accessToken才能访问,如果是没带accessToken,accessToken签名无法验证,accessToken过期等,拒绝
  2. 判断这个请求是不是带的accessToken是不是签发给谁的
    2-A. 是签发给某个服务端(可以包括matataki.io)的,如果是泄露的也说明服务端没尽到保管好accessToken的责任;不过还是可以通过检查请求头,请求IP等形式做进一步的安全判断,比如明显是通过浏览器发起的请求可以直接拒绝掉,不符合预设的使用场景;如果没有其他问题就判定通过
    2-B. 不是,是签发给浏览器前端使用的,判断是否有带上HttpOnly Secure Cookie(可以根据clientId检查不同的Cookie),如果有而且有效(格式也是一种JWT,不过内容和accessToken不同),那么通过,如果没有,拒绝
    2-C. 是签发给某个Mobile App的,按最普通的accessToken处理就可以了

PKCE解决的应该是clientSecret暴露在外的问题,本来也是Mobile App没有合适的放clientSecret位置的解决方案

https://www.oauth.com/playground/authorization-code-with-pkce.html

对SPA来说每重开一次都重新登录一次也不算不可接受了,涉及到币的话说不定反而是安全的证明
如果要更长时间保持,还是需要参考上面那种带些定制的手段了

有一些参考文章,可能有帮助:

https://wso2.com/library/articles/a-primer-on-oauth-2-0-for-client-side-applications-part-3/

https://developer.okta.com/blog/2019/05/01/is-the-oauth-implicit-flow-dead

  1. MatatakiAuth的JWT验证问题

当前是直接取JWT的payload解析回json使用的,没有验证签名。
通过userId+eth address等可以构造出这样的报文,有可能伪造身份。邮箱或者钱包地址在文章列表的author里是明文
userId在首页的url里就可以确认。
应该用签发JWT的KEY验证签名,为了减少KEY的扩散可以是生成JWT签名部分用privateKey,各个APP用publicKey验签

Fediverse生态应用

Mastodon is an open source decentralized social network - by the people for the people. Join the federation and take back control of your social media!

Pixelfed is an activitypub based image sharing platform.

Funkwhale is a community-driven project that lets you listen and share music and audio within a decentralized, open network.

PeerTube developed by Framasoft, is the free and decentralized alternative to video platforms, providing you over 400,000 videos published by 60,000 users and viewed over 15 million times.

WriteFreely is free and open source software for easily publishing writing on the web. Use it to start a personal blog — or an entire community.


参考: 活用 Bulma 美化 Icarus 文章

Hexo整合Matataki用Fan票打赏Blog文章

Hexo整合Matataki用Fan票打赏Blog文章

修改记录

  • 2020-12-14 初稿
  • 2020-12-15 修改方案,支持在目录页打赏

概述

在文章之后留下打赏地址/链接/二维码已经是一种很主流的激励创作者的形式了,Matataki的主站也支持用Fan票进行打赏。那么在站外我们能否用上Fan票呢?答案是肯定的。

如果已经有MetaMask这样的钱包,可以使用Fan票折跃门,把托管在平台上的Fan票转到我们自己的钱包,这样Blog上只要留下钱包地址即可转账打赏。

使用钱包仍然有些门槛,本文介绍了一种方法,可以当作站外使用Fan票场景的简单补充。这篇文章的成果很大程度上是基于

的研究:

使用的样例工程也是上文中提到的https://github.com/nekomeowww/hexo-plugin-matataki-example
这个方法工作量不大,只要做脚本集成就可以了,相对地,对Matataki的主站有依赖。

步骤

  1. FanLocker一样,我们在_config.yml里做好配置:
1
2
matataki:
userId: 4382

一般情况下整个Blog的文章都是自己的,打赏对象都是同一个人,所以不需要每篇文章分开来配置。这个userId可以在Matataki的个人主页看到,比如 https://www.matataki.io/user/4382

  1. 新建文件themes/landscape/layout/matataki.ejs,为Blog目录和每篇文章增加脚本片段
1
2
3
4
5
6
7
8
9
10
11
12
13
<script>
var mttk = {
userId: '<%- config.matataki.userId %>',
open: function (href) {
window.open(href, 'hexo-mttk',
'width=445,height=700,resizable=no,menubar=no,status=no,scrollbars=yes');
},
openUserHome: function () {
let href = 'https://matataki.io/user/' + mttk.userId;
mttk.open(href);
}
};
</script>

然后在themes/landscape/layout/_partial/header.ejs里添加引用

1
2
3
4
<head>
<meta charset="utf-8">
<%- partial('matataki') %>

这样就在每个页面都声明了mttk对象

  1. 在博客的分享脚本里增加打开Matataki的链接。这个主题是在themes/landscape/source/js/script.js。找到Share部分,增加动态html脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Share
$('body').on('click', function(){
// ...

var html = [
'<div id="' + id + '" class="article-share-box">',
'<input class="article-share-input" value="' + url + '">',
'<div class="article-share-links">',
'<a href="https://twitter.com/intent/tweet?url=' + encodedUrl + '" class="article-share-twitter" target="_blank" title="Twitter"></a>',
'<a href="https://www.facebook.com/sharer.php?u=' + encodedUrl + '" class="article-share-facebook" target="_blank" title="Facebook"></a>',
'<a href="http://pinterest.com/pin/create/button/?url=' + encodedUrl + '" class="article-share-pinterest" target="_blank" title="Pinterest"></a>',
'<a href="javascript:mttk.openUserHome()" class="article-share-matataki" title="Matataki"></a>',
'</div>',
'</div>'
].join('');

//...
});

就是 '<a href="javascript:mttk.openUserHome()" class="article-share-matataki" title="Matataki"></a>',这句了。因为现在Matataki还不支持带入分享链接,先这样没有入参也是可以的

为了article-share-matataki这个样式,我们再调整一下css

  1. 打开themes/landscape/source/css/_partial/article.styl,增加如下样式:
1
2
3
4
5
6
7
.article-share-matataki
@extend $article-share-link
&:before
content: "\f087"
&:hover
background: color-google
text-shadow: 0 1px darken(color-google, 20%)

content这里是字体图标,可以去http://www.fontawesome.com.cn/faicons/找个自己喜欢的,比如:http://www.fontawesome.com.cn/icons/thumbs-o-up/,把里面的Unicode填到content:后就可以了,注意要加一个反斜杠 \

5.看看效果

image.png

image.png
这个点赞图标就是我们加上的打开Matataki页面的链接了。点击之后会弹出窗口,打开博主在Matataki的个人主页,也就是上面配置的userId

image.png

因为实际就是主站点,登录和转账的方式都是一样的

留言可以留博客链接

image.png

链接

体验地址

结语

这样一些希望能有完整的文章管理权而自建博客的用户也可以接入Fan票生态了。这种方案的中心化程度比较高,不过个人认为先小规模使用Fan票,熟悉之后再用【Fan票迁跃门】体验更进一步的去中心化也有其意义所在。

另一方面算是对Matataki和Fan票的关系的一种确认。这篇文章涉及到的应用场景和“在Matataki平台上写文章”没什么关系,只涉及到了Fan票相关的部分。也就是说这个基于Fan票打赏的博客也是Fan票宇宙的一部分,但和Matataki更像邻居(相当大程度是账号权限系统没分离,所以体感上都在Matataki的域名和页面的缘故)

理论上可以做到在web3层面开发直接对接Fan票的dAPP来为博客构建打赏方案,不过现在文档和工具都不完善,门槛还是过高了些,期待Matataki进一步发展后这方面能有所改善

Alice in Wonderland

The rabbit-hole went straight on like a tunnel for some way, and then dipped suddenly down, so suddenly that Alice had not a moment to think about stopping herself before she found herself falling down a very deep well.

Either the well was very deep, or she fell very slowly, for she had plenty of time as she went down to look about her and to wonder what was going to happen next. First, she tried to look down and make out what she was coming to, but it was too dark to see anything; then she looked at the sides of the well, and noticed that they were filled with cupboards and book-shelves; here and there she saw maps and pictures hung upon pegs. She took down a jar from one of the shelves as she passed; it was labelled ‘ORANGE MARMALADE’, but to her great disappointment it was empty: she did not like to drop the jar for fear of killing somebody, so managed to put it into one of the cupboards as she fell past it.

‘Well!’ thought Alice to herself, ‘after such a fall as this, I shall think nothing of tumbling down stairs! How brave they’ll all think me at home! Why, I wouldn’t say anything about it, even if I fell off the top of the house!’ (Which was very likely true.)

Down, down, down. Would the fall NEVER come to an end! ‘I wonder how many miles I’ve fallen by this time?’ she said aloud. ‘I must be getting somewhere near the centre of the earth. Let me see: that would be four thousand miles down, I think—’ (for, you see, Alice had learnt several things of this sort in her lessons in the schoolroom, and though this was not a VERY good opportunity for showing off her knowledge, as there was no one to listen to her, still it was good practice to say it over) ‘—yes, that’s about the right distance—but then I wonder what Latitude or Longitude I’ve got to?’ (Alice had no idea what Latitude was, or Longitude either, but thought they were nice grand words to say.)

Presently she began again. ‘I wonder if I shall fall right THROUGH the earth! How funny it’ll seem to come out among the people that walk with their heads downward! The Antipathies, I think—’ (she was rather glad there WAS no one listening, this time, as it didn’t sound at all the right word) ‘—but I shall have to ask them what the name of the country is, you know. Please, Ma’am, is this New Zealand or Australia?’ (and she tried to curtsey as she spoke—fancy CURTSEYING as you’re falling through the air! Do you think you could manage it?) ‘And what an ignorant little girl she’ll think me for asking! No, it’ll never do to ask: perhaps I shall see it written up somewhere.’

Down, down, down. There was nothing else to do, so Alice soon began talking again. ‘Dinah’ll miss me very much to-night, I should think!’ (Dinah was the cat.) ‘I hope they’ll remember her saucer of milk at tea-time. Dinah my dear! I wish you were down here with me! There are no mice in the air, I’m afraid, but you might catch a bat, and that’s very like a mouse, you know. But do cats eat bats, I wonder?’ And here Alice began to get rather sleepy, and went on saying to herself, in a dreamy sort of way, ‘Do cats eat bats? Do cats eat bats?’ and sometimes, ‘Do bats eat cats?’ for, you see, as she couldn’t answer either question, it didn’t much matter which way she put it. She felt that she was dozing off, and had just begun to dream that she was walking hand in hand with Dinah, and saying to her very earnestly, ‘Now, Dinah, tell me the truth: did you ever eat a bat?’ when suddenly, thump! thump! down she came upon a heap of sticks and dry leaves, and the fall was over.

Alice was not a bit hurt, and she jumped up on to her feet in a moment: she looked up, but it was all dark overhead; before her was another long passage, and the White Rabbit was still in sight, hurrying down it. There was not a moment to be lost: away went Alice like the wind, and was just in time to hear it say, as it turned a corner, 'Oh my ears and whiskers, how late it's getting!' She was close behind it when she turned the corner, but the Rabbit was no longer to be seen: she found herself in a long, low hall, which was lit up by a row of lamps hanging from the roof.

There were doors all round the hall, but they were all locked; and when Alice had been all the way down one side and up the other, trying every door, she walked sadly down the middle, wondering how she was ever to get out again.

Source: https://www.cs.cmu.edu/~rgs/alice-I.html

Placeholder text by Fillerati. Photography by UNSPLASH.