fix(route/weibo/*): sinaimg anti-hotlinking (#11320)

* fix(route/weibo/*): sinaimg anti-hotlinking

Signed-off-by: Rongrong <i@rong.moe>

* refactor: migrate to v2

* Fix CodeQL warning

Signed-off-by: Rongrong <i@rong.moe>

* Fix CodeQL warning again

Signed-off-by: Rongrong <i@rong.moe>

* Narrow sinaimg URL regex

Signed-off-by: Rongrong <i@rong.moe>

* Fix CodeQL warning again and again

Signed-off-by: Rongrong <i@rong.moe>

* Fix CodeQL warning again, again and again

Signed-off-by: Rongrong <i@rong.moe>

* More accurate regex, dismiss CodeQL plz

Signed-off-by: Rongrong <i@rong.moe>

Signed-off-by: Rongrong <i@rong.moe>
This commit is contained in:
Rongrong
2022-11-28 03:37:43 +08:00
committed by GitHub
parent cf9c7baf6e
commit c3e78ee7df
14 changed files with 143 additions and 113 deletions
-21
View File
@@ -13,27 +13,6 @@
},
'https://www.icac.org.hk': { _name: '廉政公署', '.': [{ title: '新闻公布', docs: 'https://docs.rsshub.app/government.html#xiang-gang-lian-zheng-gong-shu', source: ['/:lang/press/index.html'], target: '/icac/news/:lang' }] },
'trow.cc': { _name: 'The Ring of Wonder', '.': [{ title: '首页更新', docs: 'https://docs.rsshub.app/bbs.html#the-ring-of-wonder', source: ['/'], target: '/portal' }] },
'weibo.com': {
_name: '微博',
'.': [
{
title: '博主',
docs: 'https://docs.rsshub.app/social-media.html#wei-bo',
source: ['/u/:id', '/:id'],
target: (params, url, document) => {
let uid = document?.documentElement.innerHTML.match(/\$CONFIG\['oid']='(\d+)'/)?.[1];
if (!uid && !isNaN(params.id)) {
uid = params.id;
}
return uid ? `/weibo/user/${uid}` : '';
},
},
{ title: '关键词', docs: 'https://docs.rsshub.app/social-media.html#wei-bo' },
{ title: '超话', docs: 'https://docs.rsshub.app/social-media.html#wei-bo', source: '/p/:id/super_index', target: '/weibo/super_index/:id' },
],
s: [{ title: '热搜榜', docs: 'https://docs.rsshub.app/social-media.html#wei-bo', source: '/top/summary', target: '/weibo/search/hot' }],
},
'weibo.cn': { _name: '微博', m: [{ title: '博主', docs: 'https://docs.rsshub.app/social-media.html#wei-bo', source: ['/u/:uid', '/profile/:uid'], target: '/weibo/user/:uid' }] },
'github.com': {
_name: 'GitHub',
'.': [
-46
View File
@@ -1,50 +1,4 @@
module.exports = {
'weibo.com': {
_name: '微博',
'.': [
{
title: '博主',
docs: 'https://docs.rsshub.app/social-media.html#wei-bo',
source: ['/u/:id', '/:id'],
target: (params, url, document) => {
let uid = document?.documentElement.innerHTML.match(/\$CONFIG\['oid']='(\d+)'/)?.[1];
if (!uid && !isNaN(params.id)) {
uid = params.id;
}
return uid ? `/weibo/user/${uid}` : '';
},
},
{
title: '关键词',
docs: 'https://docs.rsshub.app/social-media.html#wei-bo',
},
{
title: '超话',
docs: 'https://docs.rsshub.app/social-media.html#wei-bo',
source: '/p/:id/super_index',
target: '/weibo/super_index/:id',
},
],
s: [
{
title: '热搜榜',
docs: 'https://docs.rsshub.app/social-media.html#wei-bo',
source: '/top/summary',
target: '/weibo/search/hot',
},
],
},
'weibo.cn': {
_name: '微博',
m: [
{
title: '博主',
docs: 'https://docs.rsshub.app/social-media.html#wei-bo',
source: ['/u/:uid', '/profile/:uid'],
target: '/weibo/user/:uid',
},
],
},
'ximalaya.com': {
_name: '喜马拉雅',
'.': [
+7 -7
View File
@@ -47,12 +47,12 @@ router.get('/benedictevans', lazyloadRouteHandler('./routes/benedictevans/recent
// router.get('/twreporter/photography', lazyloadRouteHandler('./routes/twreporter/photography'));
// router.get('/twreporter/category/:cid', lazyloadRouteHandler('./routes/twreporter/category'));
// 微博
router.get('/weibo/user/:uid/:routeParams?', lazyloadRouteHandler('./routes/weibo/user'));
router.get('/weibo/keyword/:keyword/:routeParams?', lazyloadRouteHandler('./routes/weibo/keyword'));
router.get('/weibo/search/hot', lazyloadRouteHandler('./routes/weibo/search/hot'));
router.get('/weibo/super_index/:id/:type?/:routeParams?', lazyloadRouteHandler('./routes/weibo/super_index'));
router.get('/weibo/oasis/user/:userid', lazyloadRouteHandler('./routes/weibo/oasis/user'));
// 微博 migrated to v2
// router.get('/weibo/user/:uid/:routeParams?', lazyloadRouteHandler('./routes/weibo/user'));
// router.get('/weibo/keyword/:keyword/:routeParams?', lazyloadRouteHandler('./routes/weibo/keyword'));
// router.get('/weibo/search/hot', lazyloadRouteHandler('./routes/weibo/search/hot'));
// router.get('/weibo/super_index/:id/:type?/:routeParams?', lazyloadRouteHandler('./routes/weibo/super_index'));
// router.get('/weibo/oasis/user/:userid', lazyloadRouteHandler('./routes/weibo/oasis/user'));
// 贴吧 migrated to v2
// router.get('/tieba/forum/:kw', lazyloadRouteHandler('./routes/tieba/forum'));
@@ -2086,7 +2086,7 @@ router.get('/haimaoba/:id?', lazyloadRouteHandler('./routes/haimaoba/comics'));
router.get('/pgyer/:app?', lazyloadRouteHandler('./routes/pgyer/app'));
// 微博个人时间线
router.get('/weibo/timeline/:uid/:feature?/:routeParams?', lazyloadRouteHandler('./routes/weibo/timeline'));
// router.get('/weibo/timeline/:uid/:feature?/:routeParams?', lazyloadRouteHandler('./routes/weibo/timeline'));
// TAPTAP migrated to v2
// router.get('/taptap/topic/:id/:label?', lazyloadRouteHandler('./routes/taptap/topic'));
-17
View File
@@ -1,17 +0,0 @@
const buildData = require('@/utils/common-config');
module.exports = async (ctx) => {
const userid = ctx.params.userid;
const link = `https://oasis.weibo.cn/v1/h5/share?uid=${userid}`;
ctx.state.data = await buildData({
link,
url: link,
title: `$('.name-main').text().trim() + ' - 用户 - 绿洲'`,
description: `$('.desc').text().trim()`,
item: {
item: '.container .item',
title: `$('.status-desc').text()`,
description: `$('.status-desc').text() + '<br>' + $('.media-wrapper').html()`,
},
});
};
@@ -28,7 +28,7 @@ module.exports = async (ctx) => {
);
const routeParams = querystring.parse(ctx.params.routeParams);
ctx.state.data = {
ctx.state.data = weiboUtils.sinaimgTvax({
title: `又有人在微博提到${keyword}了`,
link: `http://s.weibo.com/weibo/${encodeURIComponent(keyword)}&b=1&nodup=1`,
description: `又有人在微博提到${keyword}了`,
@@ -51,5 +51,5 @@ module.exports = async (ctx) => {
link: `https://weibo.com/${item.mblog.user.id}/${item.mblog.bid}`,
};
}),
};
});
};
+8
View File
@@ -0,0 +1,8 @@
module.exports = {
'/keyword/:keyword/:routeParams?': ['DIYgod'],
'/oasis/user/:userid': ['kt286'],
'/search/hot': ['xyqfer'],
'/super_index/:id/:type?/:routeParams?': ['zengxs'],
'/timeline/:uid/:feature?/:routeParams?': ['zytomorrow', 'DIYgod ', 'Rongronggg9'],
'/user/:uid/:routeParams?': ['DIYgod', 'iplusx', 'Rongronggg9'],
};
+20
View File
@@ -0,0 +1,20 @@
const buildData = require('@/utils/common-config');
const weiboUtils = require('../utils');
module.exports = async (ctx) => {
const userid = ctx.params.userid;
const link = `https://oasis.weibo.cn/v1/h5/share?uid=${userid}`;
ctx.state.data = weiboUtils.sinaimgTvax(
await buildData({
link,
url: link,
title: `$('.name-main').text().trim() + ' - 用户 - 绿洲'`,
description: `$('.desc').text().trim()`,
item: {
item: '.container .item',
title: `$('.status-desc').text()`,
description: `$('.status-desc').text() + '<br>' + $('.media-wrapper').html()`,
},
})
);
};
+48
View File
@@ -0,0 +1,48 @@
module.exports = {
'weibo.com': {
_name: '微博',
'.': [
{
title: '博主',
docs: 'https://docs.rsshub.app/social-media.html#wei-bo',
source: ['/u/:id', '/:id'],
target: (params, url, document) => {
let uid = document?.documentElement.innerHTML.match(/\$CONFIG\['oid']='(\d+)'/)?.[1];
if (!uid && !isNaN(params.id)) {
uid = params.id;
}
return uid ? `/weibo/user/${uid}` : '';
},
},
{
title: '关键词',
docs: 'https://docs.rsshub.app/social-media.html#wei-bo',
},
{
title: '超话',
docs: 'https://docs.rsshub.app/social-media.html#wei-bo',
source: '/p/:id/super_index',
target: '/weibo/super_index/:id',
},
],
s: [
{
title: '热搜榜',
docs: 'https://docs.rsshub.app/social-media.html#wei-bo',
source: '/top/summary',
target: '/weibo/search/hot',
},
],
},
'weibo.cn': {
_name: '微博',
m: [
{
title: '博主',
docs: 'https://docs.rsshub.app/social-media.html#wei-bo',
source: ['/u/:uid', '/profile/:uid'],
target: '/weibo/user/:uid',
},
],
},
};
+8
View File
@@ -0,0 +1,8 @@
module.exports = (router) => {
router.get('/keyword/:keyword/:routeParams?', require('./keyword'));
router.get('/oasis/user/:userid', require('./oasis/user'));
router.get('/search/hot', require('./search/hot'));
router.get('/super_index/:id/:type?/:routeParams?', require('./super_index'));
router.get('/timeline/:uid/:feature?/:routeParams?', require('./timeline'));
router.get('/user/:uid/:routeParams?', require('./user'));
};
@@ -1,4 +1,5 @@
const got = require('@/utils/got');
// const weiboUtils = require('../utils');
module.exports = async (ctx) => {
const {
@@ -30,4 +31,5 @@ module.exports = async (ctx) => {
};
}),
};
// ctx.state.data = weiboUtils.sinaimgTvax(ctx.state.data); // no image in the route
};
@@ -53,10 +53,10 @@ module.exports = async (ctx) => {
}
}
ctx.state.data = {
ctx.state.data = weiboUtils.sinaimgTvax({
title: `微博超话 - ${containerData.pageInfo.page_title}`,
link: `https://weibo.com/p/${id}/super_index`,
description: `#${containerData.pageInfo.page_title}# 的超话`,
item: resultItems,
};
});
};
@@ -125,13 +125,13 @@ module.exports = async (ctx) => {
})
);
ctx.state.data = {
ctx.state.data = weiboUtils.sinaimgTvax({
title: `个人微博时间线--${name}`,
link: `http://weibo.com/${uid}/`,
description,
image: profileImageUrl,
item: resultItem,
};
});
} else if (uid === '0' || ctx.querystring) {
const { app_key = '', redirect_url = ctx.request.origin + '/weibo/timeline/0', app_secret = '' } = config.weibo;
@@ -145,11 +145,11 @@ module.exports = async (ctx) => {
resultItems = ordinaryItems;
}
ctx.state.data = {
ctx.state.data = weiboUtils.sinaimgTvax({
title: `${name}的微博`,
link: `https://weibo.com/${uid}/`,
description,
image: profileImageUrl,
item: resultItems,
};
});
};
@@ -4,6 +4,16 @@ const cheerio = require('cheerio');
const { fallback, queryToBoolean, queryToInteger } = require('@/utils/readable-social');
const weiboUtils = {
formatTitle: (html) =>
html
.replace(/<span class=["']url-icon["']><img\s[^>]*?alt=["']?([^>]+?)["']?\s[^>]*?\/?><\/span>/g, '$1') // 表情转换
.replace(/<span class=["']url-icon["']>(<img\s[^>]*>)<\/span>/g, '') // 去掉所有图标
.replace(/<img\s[^<]*>/g, '[图片]')
// impossible to have inline script in weibo posts, but CodeQL complains about it
// Dismiss it through the UI: https://github.com/github/codeql/issues/11427
.replace(/<[^<]*>/g, '')
.replace(/\n/g, ' ')
.trim(),
formatExtended: (ctx, status, params = {}, picsPrefixes = []) => {
// undefined and strings like "1" is also safely parsed, so no if branch is needed
const routeParams = querystring.parse(ctx.params.routeParams);
@@ -200,23 +210,11 @@ const weiboUtils = {
title += status.user.screen_name + ': ';
}
if (!status.retweeted_status || showRetweetTextInTitle) {
title += htmlNewLineUnreplaced
.replace(/<span class=["']url-icon["']><img\s[^>]*?alt=["']?([^>]+?)["']?\s[^>]*?\/><\/span>/g, '$1') // 表情转换
.replace(/<span class=["']url-icon["']>(<img\s[^>]*?>)<\/span>/g, '') // 去掉所有图标
.replace(/<img[\s\S]*?>/g, '[图片]')
.replace(/<.*?>/g, '')
.replace('\n', '')
.trim();
title += weiboUtils.formatTitle(htmlNewLineUnreplaced);
}
if (status.retweeted_status) {
title += showEmojiForRetweet ? '🔁 ' : ' - 转发 ';
title += retweeted
.replace(/<span class=["']url-icon["']><img\s[^>]*?alt=["']?([^>]+?)["']?\s[^>]*?\/><\/span>/g, '$1') // 表情转换
.replace(/<span class=["']url-icon["']>(<img\s[^>]*?>)<\/span>/g, '') // 去掉所有图标
.replace(/<img[\s\S]*?>/g, '[图片]')
.replace(/<.*?>/g, '')
.replace('\n', '')
.trim();
title += weiboUtils.formatTitle(retweeted);
}
if (livePhotoCount > 0) {
title += ' ';
@@ -417,6 +415,36 @@ const weiboUtils = {
}
return itemDesc;
},
sinaimgTvax: (() => {
// https://datatracker.ietf.org/doc/html/rfc1808#section-2.4.3
const regex = /(?<=\/\/)wx(?=[1-4]\.sinaimg\.cn\/)/gi;
const prefixes = ['tva', 'tvax'];
let cnt = 0;
const replace = (html) => {
cnt = (cnt + 1) % 2;
return html.replace(regex, prefixes[cnt]);
};
const replaceKV = (obj, keys) => {
keys.forEach((key) => {
if (obj[key]) {
obj[key] = replace(obj[key]);
}
});
};
const dataKeys = ['description', 'image'];
const itemKeys = ['description'];
return (data) => {
if (data) {
replaceKV(data, dataKeys);
if (data.item) {
data.item.forEach((item) => {
replaceKV(item, itemKeys);
});
}
}
return data;
};
})(),
};
module.exports = weiboUtils;