mirror of
https://github.com/DIYgod/RSSHub.git
synced 2025-12-03 10:38:03 +08:00
feat(config)!: unsafe domain toggle (#11588)
This commit is contained in:
@@ -564,7 +564,7 @@ It is also valid to contain route parameters, e.g. `/weibo/user/2612249974`.
|
||||
|
||||
::: tip Experimental features
|
||||
|
||||
Configs in this sections are in beta stage, and are turn off by default. Please read corresponded description and turn on if necessary.
|
||||
Configs in this sections are in beta stage, and **are turn off by default**. Please read corresponded description and turn on if necessary.
|
||||
|
||||
:::
|
||||
|
||||
@@ -572,6 +572,8 @@ Configs in this sections are in beta stage, and are turn off by default. Please
|
||||
|
||||
`FILTER_REGEX_ENGINE`: Define Regex engine used in [Parameters->filtering](/en/parameter.html#filtering). Valid value are `[re2, regexp]`. Default value is `re2`. We suggest public instance should leave this value to default, and this option right now is mainly for backward compatibility.
|
||||
|
||||
`ALLOW_USER_SUPPLY_UNSAFE_DOMAIN`: allow users to provide a domain as a parameter to routes that are not in their allow list, respectively. Public instances are suggested to leave this value default, as it may lead to [Server-Side Request Forgery (SSRF)](https://owasp.org/www-community/attacks/Server_Side_Request_Forgery)
|
||||
|
||||
### Other Application Configurations
|
||||
|
||||
`DISALLOW_ROBOT`: prevent indexing by search engine, default to enable, set false or 0 to disable
|
||||
|
||||
@@ -571,7 +571,7 @@ RSSHub 支持使用访问密钥 / 码,白名单和黑名单三种方式进行
|
||||
|
||||
::: tip 测试特性
|
||||
|
||||
这个板块控制的是一些新特性的选项,默认他们都是关闭的。如果有需要请阅读对应说明后按需开启
|
||||
这个板块控制的是一些新特性的选项,他们都是**默认关闭**的。如果有需要请阅读对应说明后按需开启
|
||||
|
||||
:::
|
||||
|
||||
@@ -579,6 +579,8 @@ RSSHub 支持使用访问密钥 / 码,白名单和黑名单三种方式进行
|
||||
|
||||
`FILTER_REGEX_ENGINE`: 控制 [通用参数 -> 内容过滤](/parameter.html#nei-rong-guo-lu) 使用的正则引擎。可选`[re2, regexp]`,默认`re2`。我们推荐公开实例不要调整这个选项,这个选项目前主要用于向后兼容。
|
||||
|
||||
`ALLOW_USER_SUPPLY_UNSAFE_DOMAIN`: 允许用户为路由提供域名作为参数。建议公共实例不要调整此选项,开启后可能会导致 [服务端请求伪造(SSRF)](https://owasp.org/www-community/attacks/Server_Side_Request_Forgery)
|
||||
|
||||
### 其他应用配置
|
||||
|
||||
`DISALLOW_ROBOT`: 阻止搜索引擎收录,默认开启,设置 false 或 0 关闭
|
||||
|
||||
@@ -97,6 +97,7 @@ const calculateValue = () => {
|
||||
feature: {
|
||||
allow_user_hotlink_template: envs.ALLOW_USER_HOTLINK_TEMPLATE === 'true',
|
||||
filter_regex_engine: envs.FILTER_REGEX_ENGINE || 're2',
|
||||
allow_user_supply_unsafe_domain: envs.ALLOW_USER_SUPPLY_UNSAFE_DOMAIN === 'true',
|
||||
},
|
||||
suffix: envs.SUFFIX,
|
||||
titleLengthLimit: parseInt(envs.TITLE_LENGTH_LIMIT) || 150,
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
const got = require('@/utils/got');
|
||||
const cheerio = require('cheerio');
|
||||
const { isValidHost } = require('@/utils/valid-host');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const lang = ctx.params.lang || 'en';
|
||||
const id = ctx.params.id || 'bandizip';
|
||||
if (!isValidHost(lang)) {
|
||||
throw Error('Invalid language code');
|
||||
}
|
||||
|
||||
const rootUrl = `https://${lang}.bandisoft.com`;
|
||||
const currentUrl = `${rootUrl}/${id}/history/`;
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
const cheerio = require('cheerio');
|
||||
const got = require('@/utils/got');
|
||||
const { isValidHost } = require('@/utils/valid-host');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
if (!isValidHost(ctx.params.column)) {
|
||||
throw Error('Invalid column');
|
||||
}
|
||||
|
||||
const url = `http://${ctx.params.column}.bio1000.com/${ctx.params.id}`;
|
||||
const res = await got.get(url);
|
||||
const $ = cheerio.load(res.data);
|
||||
|
||||
@@ -4,9 +4,13 @@ const md = require('markdown-it')({
|
||||
html: true,
|
||||
});
|
||||
const dayjs = require('dayjs');
|
||||
const { isValidHost } = require('@/utils/valid-host');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const type = ctx.params.type;
|
||||
if (!isValidHost(type)) {
|
||||
throw Error('Invalid type');
|
||||
}
|
||||
|
||||
const url = `https://${type}.hedwig.pub`;
|
||||
const res = await got({
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
const parser = require('@/utils/rss-parser');
|
||||
const config = require('@/config').value;
|
||||
const allowDomain = ['lawrence.code.blog'];
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
if (!config.feature.allow_user_supply_unsafe_domain && !allowDomain.includes(ctx.params.domain)) {
|
||||
ctx.throw(403, `This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
|
||||
}
|
||||
|
||||
const scheme = ctx.params.https || 'https';
|
||||
const cdn = config.wordpress.cdnUrl;
|
||||
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
const got = require('@/utils/got');
|
||||
const cheerio = require('cheerio');
|
||||
|
||||
const { isValidHost } = require('@/utils/valid-host');
|
||||
const maxPages = 5;
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const { subdomain } = ctx.params;
|
||||
if (!isValidHost(subdomain)) {
|
||||
throw Error('Invalid subdomain');
|
||||
}
|
||||
const shopUrl = `https://${subdomain}.booth.pm`;
|
||||
|
||||
let shopName;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const got = require('@/utils/got');
|
||||
const parser = require('@/utils/rss-parser');
|
||||
const cheerio = require('cheerio');
|
||||
const { isValidHost } = require('@/utils/valid-host');
|
||||
|
||||
async function load(link, need_feed_description) {
|
||||
const response = await got.get(link);
|
||||
@@ -29,6 +30,9 @@ async function load(link, need_feed_description) {
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const { column } = ctx.params;
|
||||
if (!isValidHost(column)) {
|
||||
throw Error('Invalid column');
|
||||
}
|
||||
const link = `http://${column}.blog.caixin.com`;
|
||||
const feed_url = `${link}/feed`;
|
||||
const feed = await parser.parseURL(feed_url);
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
const got = require('@/utils/got');
|
||||
const cheerio = require('cheerio');
|
||||
const { isValidHost } = require('@/utils/valid-host');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const category = ctx.params.category;
|
||||
const column = ctx.params.column;
|
||||
const url = `http://${column}.caixin.com/${category}`;
|
||||
if (!isValidHost(column)) {
|
||||
throw Error('Invalid column');
|
||||
}
|
||||
|
||||
const response = await got({
|
||||
method: 'get',
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
const got = require('@/utils/got');
|
||||
const cheerio = require('cheerio');
|
||||
const { isValidHost } = require('@/utils/valid-host');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
if (!isValidHost(ctx.params.location)) {
|
||||
throw Error('Invalid location');
|
||||
}
|
||||
|
||||
const queryParams = ctx.request.querystring;
|
||||
const queryUrl = `https://${ctx.params.location}.craigslist.org/search/${ctx.params.type}?${queryParams}`;
|
||||
const { data } = await got.get(queryUrl);
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
const got = require('@/utils/got');
|
||||
const cheerio = require('cheerio');
|
||||
const parser = require('@/utils/rss-parser');
|
||||
const allowLang = ['chinese', 'cn', 'us', 'japanese', 'www'];
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const lang = ctx.params.lang === 'us' ? 'www' : ctx.params.lang || 'cn';
|
||||
if (!allowLang.includes(lang)) {
|
||||
throw Error('Invalid lang');
|
||||
}
|
||||
const rssUrl = `https://${lang}.engadget.com/rss.xml`;
|
||||
const feed = await parser.parseURL(rssUrl);
|
||||
|
||||
|
||||
@@ -4,12 +4,15 @@
|
||||
// user?: fanbox domain name
|
||||
|
||||
const got = require('@/utils/got');
|
||||
|
||||
const { isValidHost } = require('@/utils/valid-host');
|
||||
const conv_item = require('./conv');
|
||||
const get_header = require('./header');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const user = ctx.params.user || 'official'; // if no user specified, just go to official page
|
||||
if (!isValidHost(user)) {
|
||||
throw Error('Invalid user');
|
||||
}
|
||||
const box_url = `https://${user}.fanbox.cc`;
|
||||
|
||||
// get user info
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
const got = require('@/utils/got');
|
||||
const cheerio = require('cheerio');
|
||||
const { isValidHost } = require('@/utils/valid-host');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const country = ctx.params.country || 'ww';
|
||||
if (!isValidHost(country)) {
|
||||
throw Error('Invalid country');
|
||||
}
|
||||
|
||||
const rootUrl = `https://${country}.fashionnetwork.com`;
|
||||
const response = await got({
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
const got = require('@/utils/got');
|
||||
const cheerio = require('cheerio');
|
||||
const { isValidHost } = require('@/utils/valid-host');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const country = ctx.params.country || 'ww';
|
||||
@@ -12,6 +13,10 @@ module.exports = async (ctx) => {
|
||||
const sectorsUrl = sectors ? 'sectors%5B%5D=' + sectors.split(',').join('§ors%5B%5D=') : '';
|
||||
const categoriesUrl = categories ? 'categs%5B%5D=' + categories.split(',').join('&categs%5B%5D=') : '';
|
||||
|
||||
if (!isValidHost(country)) {
|
||||
throw Error('Invalid country');
|
||||
}
|
||||
|
||||
const rootUrl = `https://${country}.fashionnetwork.com`;
|
||||
const currentUrl = `${rootUrl}/news/s.jsonp?${sectorsUrl}&${categoriesUrl}`;
|
||||
const response = await got({
|
||||
|
||||
5
lib/routes/gitlab/common.js
Normal file
5
lib/routes/gitlab/common.js
Normal file
@@ -0,0 +1,5 @@
|
||||
const allowHost = ['gitlab.com'];
|
||||
|
||||
module.exports = {
|
||||
allowHost,
|
||||
};
|
||||
@@ -1,5 +1,7 @@
|
||||
const got = require('@/utils/got');
|
||||
const cheerio = require('cheerio');
|
||||
const config = require('@/config').value;
|
||||
const { allowHost } = require('./common');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
let { type, host } = ctx.params;
|
||||
@@ -10,6 +12,9 @@ module.exports = async (ctx) => {
|
||||
starred: 'Most stars',
|
||||
all: 'All',
|
||||
};
|
||||
if (!config.feature.allow_user_supply_unsafe_domain && !allowHost.includes(new URL(host).hostname)) {
|
||||
ctx.throw(403, `This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
|
||||
}
|
||||
|
||||
const res = await got({
|
||||
method: 'get',
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
const got = require('@/utils/got');
|
||||
const { parseDate } = require('@/utils/parse-date');
|
||||
const config = require('@/config').value;
|
||||
const { allowHost } = require('./common');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const { namespace, project, host } = ctx.params;
|
||||
if (!config.feature.allow_user_supply_unsafe_domain && !allowHost.includes(host)) {
|
||||
ctx.throw(403, `This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
|
||||
}
|
||||
|
||||
const host_ = host ? host : 'gitlab.com';
|
||||
const namespace_ = encodeURIComponent(namespace);
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
const got = require('@/utils/got');
|
||||
const { parseDate } = require('@/utils/parse-date');
|
||||
const config = require('@/config').value;
|
||||
const { allowHost } = require('./common');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const { namespace, project, host } = ctx.params;
|
||||
if (!config.feature.allow_user_supply_unsafe_domain && !allowHost.includes(host)) {
|
||||
ctx.throw(403, `This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
|
||||
}
|
||||
|
||||
const host_ = host ? host : 'gitlab.com';
|
||||
const namespace_ = encodeURIComponent(namespace);
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
const cheerio = require('cheerio');
|
||||
const got = require('@/utils/got');
|
||||
const config = require('@/config').value;
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
if (!config.feature.allow_user_supply_unsafe_domain) {
|
||||
ctx.throw(403, `This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
|
||||
}
|
||||
const url = `http://${ctx.params.url}`;
|
||||
const res = await got.get(`${url}/archives/`);
|
||||
const $ = cheerio.load(res.data);
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
const cheerio = require('cheerio');
|
||||
const got = require('@/utils/got');
|
||||
const config = require('@/config').value;
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
if (!config.feature.allow_user_supply_unsafe_domain) {
|
||||
ctx.throw(403, `This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
|
||||
}
|
||||
const url = `http://${ctx.params.url}`;
|
||||
const res = await got.get(`${url}/archives/`);
|
||||
const $ = cheerio.load(res.data);
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
const cheerio = require('cheerio');
|
||||
const got = require('@/utils/got');
|
||||
const config = require('@/config').value;
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
if (!config.feature.allow_user_supply_unsafe_domain) {
|
||||
ctx.throw(403, `This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
|
||||
}
|
||||
const url = `http://${ctx.params.url}`;
|
||||
const res = await got.get(url);
|
||||
const $ = cheerio.load(res.data);
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
const utils = require('./utils');
|
||||
const config = require('@/config').value;
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const site = ctx.params.site;
|
||||
const account_id = ctx.params.account_id;
|
||||
const only_media = ctx.params.only_media ? 'true' : 'false';
|
||||
if (!config.feature.allow_user_supply_unsafe_domain && !utils.allowSiteList.includes(site)) {
|
||||
ctx.throw(403, `This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
|
||||
}
|
||||
|
||||
const { account_data, data } = await utils.getAccountStatuses(site, account_id, only_media);
|
||||
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
const got = require('@/utils/got');
|
||||
const utils = require('./utils');
|
||||
const config = require('@/config').value;
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const site = ctx.params.site;
|
||||
const only_media = ctx.params.only_media ? 'true' : 'false';
|
||||
if (!config.feature.allow_user_supply_unsafe_domain && !utils.allowSiteList.includes(site)) {
|
||||
ctx.throw(403, `This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
|
||||
}
|
||||
|
||||
const url = `http://${site}/api/v1/timelines/public?local=true&only_media=${only_media}`;
|
||||
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
const got = require('@/utils/got');
|
||||
const utils = require('./utils');
|
||||
const config = require('@/config').value;
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const site = ctx.params.site;
|
||||
const only_media = ctx.params.only_media ? 'true' : 'false';
|
||||
if (!config.feature.allow_user_supply_unsafe_domain && !utils.allowSiteList.includes(site)) {
|
||||
ctx.throw(403, `This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
|
||||
}
|
||||
|
||||
const url = `http://${site}/api/v1/timelines/public?remote=true&only_media=${only_media}`;
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
const got = require('@/utils/got');
|
||||
const { parseDate } = require('@/utils/parse-date');
|
||||
|
||||
const allowSiteList = ['mastodon.social', 'pawoo.net'];
|
||||
|
||||
const parseStatuses = (data) =>
|
||||
data.map((item) => {
|
||||
// docs on: https://docs.joinmastodon.org/entities/status/
|
||||
@@ -125,4 +127,5 @@ module.exports = {
|
||||
parseStatuses,
|
||||
getAccountStatuses,
|
||||
getAccountIdByAcct,
|
||||
allowSiteList,
|
||||
};
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
const got = require('@/utils/got');
|
||||
const cheerio = require('cheerio');
|
||||
const { isValidHost } = require('@/utils/valid-host');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const language = ctx.params.language || 'www';
|
||||
const url = ctx.params.url || 'video';
|
||||
const link = `https://${language}.pornhub.com/${url}`;
|
||||
if (!isValidHost(language)) {
|
||||
throw Error('Invalid language');
|
||||
}
|
||||
|
||||
const response = await got.get(link);
|
||||
const $ = cheerio.load(response.data);
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
const got = require('@/utils/got');
|
||||
const cheerio = require('cheerio');
|
||||
const { isValidHost } = require('@/utils/valid-host');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const language = ctx.params.language || 'www';
|
||||
const username = ctx.params.username;
|
||||
const sort = ctx.params.sort || 'mr';
|
||||
const link = `https://${language}.pornhub.com/model/${username}/videos?o=${sort}`;
|
||||
if (!isValidHost(language)) {
|
||||
throw Error('Invalid language');
|
||||
}
|
||||
|
||||
const response = await got.get(link);
|
||||
const $ = cheerio.load(response.data);
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
const got = require('@/utils/got');
|
||||
const cheerio = require('cheerio');
|
||||
const { isValidHost } = require('@/utils/valid-host');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const language = ctx.params.language || 'www';
|
||||
const username = ctx.params.username;
|
||||
const sort = ctx.params.sort || 'mr';
|
||||
const link = `https://${language}.pornhub.com/pornstar/${username}/videos?o=${sort}`;
|
||||
if (!isValidHost(language)) {
|
||||
throw Error('Invalid language');
|
||||
}
|
||||
|
||||
const response = await got.get(link);
|
||||
const $ = cheerio.load(response.data);
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
const got = require('@/utils/got');
|
||||
const cheerio = require('cheerio');
|
||||
const { isValidHost } = require('@/utils/valid-host');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const language = ctx.params.language || 'www';
|
||||
const username = ctx.params.username;
|
||||
const link = `https://${language}.pornhub.com/users/${username}/videos`;
|
||||
if (!isValidHost(language)) {
|
||||
throw Error('Invalid language');
|
||||
}
|
||||
|
||||
const response = await got.get(link);
|
||||
const $ = cheerio.load(response.data);
|
||||
|
||||
@@ -11,6 +11,9 @@ const getBaseUrl = (language) => (language === 'ja' ? 'https://touhougarakuta.co
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const { language, type } = ctx.params;
|
||||
if (!Object.keys(languageCodes).includes(language)) {
|
||||
throw Error('Invalid language');
|
||||
}
|
||||
|
||||
const baseUrl = getBaseUrl(language);
|
||||
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
const got = require('@/utils/got');
|
||||
const cheerio = require('cheerio');
|
||||
const { isValidHost } = require('@/utils/valid-host');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
ctx.params.lang = ctx.params.lang || 'www';
|
||||
ctx.params.platform = ctx.params.platform || '';
|
||||
ctx.params.year = ctx.params.year || '';
|
||||
const lang = ctx.params.lang || 'www';
|
||||
const platform = ctx.params.platform || '';
|
||||
const year = ctx.params.year || '';
|
||||
if (!isValidHost(lang)) {
|
||||
throw Error('Invalid lang');
|
||||
}
|
||||
|
||||
const rootUrl = `https://${ctx.params.lang === 'en' ? 'www' : ctx.params.lang}.weforum.org`;
|
||||
const currentUrl = `${rootUrl}/reports?platform=${ctx.params.platform}&year=${ctx.params.year}`;
|
||||
const rootUrl = `https://${lang === 'en' ? 'www' : lang}.weforum.org`;
|
||||
const currentUrl = `${rootUrl}/reports?platform=${platform}&year=${year}`;
|
||||
const response = await got({
|
||||
method: 'get',
|
||||
url: currentUrl,
|
||||
|
||||
4
lib/routes/yahoo-news/index.js
vendored
4
lib/routes/yahoo-news/index.js
vendored
@@ -1,9 +1,13 @@
|
||||
const got = require('@/utils/got');
|
||||
const parser = require('@/utils/rss-parser');
|
||||
const cheerio = require('cheerio');
|
||||
const { isValidHost } = require('@/utils/valid-host');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const region = ctx.params.region === 'en' ? '' : ctx.params.region.toLowerCase() + '.';
|
||||
if (!isValidHost(region)) {
|
||||
throw Error('Invalid region');
|
||||
}
|
||||
const category = ctx.params.category ? ctx.params.category.toLowerCase() : '';
|
||||
const rssUrl = `https://${region}news.yahoo.com/rss/${category}`;
|
||||
const feed = await parser.parseURL(rssUrl);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const got = require('@/utils/got');
|
||||
const { isValidHost } = require('@/utils/valid-host');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const city = ctx.params.city || 'sh';
|
||||
@@ -7,6 +8,10 @@ module.exports = async (ctx) => {
|
||||
const room = ctx.params.room || '1';
|
||||
const domain = `${city === 'bj' ? '' : city + '.'}m.ziroom.com`;
|
||||
|
||||
if (!isValidHost(city)) {
|
||||
throw Error('Invalid city');
|
||||
}
|
||||
|
||||
const response = await got({
|
||||
method: 'post',
|
||||
url: `http://${domain}/list/ajax-get-data`,
|
||||
|
||||
16
lib/utils/valid-host.js
Normal file
16
lib/utils/valid-host.js
Normal file
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Check if a sub-domain is valid
|
||||
* @param {String} hostname sub-domain
|
||||
* @returns {Boolean} true if valid
|
||||
*/
|
||||
const isValidHost = (hostname) => {
|
||||
if (typeof hostname !== 'string') {
|
||||
return false;
|
||||
}
|
||||
const regex = /^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$/;
|
||||
return regex.test(hostname);
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
isValidHost,
|
||||
};
|
||||
@@ -3,6 +3,7 @@ const cheerio = require('cheerio');
|
||||
const timezone = require('@/utils/timezone');
|
||||
const { parseDate } = require('@/utils/parse-date');
|
||||
const iconv = require('iconv-lite');
|
||||
const { isValidHost } = require('@/utils/valid-host');
|
||||
|
||||
const setCookie = function (cookieName, cookieValue, seconds, path, domain, secure) {
|
||||
let expires = null;
|
||||
@@ -15,6 +16,9 @@ const setCookie = function (cookieName, cookieValue, seconds, path, domain, secu
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const city = ctx.params.city ?? 'www';
|
||||
if (!isValidHost(city)) {
|
||||
throw Error('Invalid city');
|
||||
}
|
||||
|
||||
const rootUrl = `https://${city}.19lou.com`;
|
||||
|
||||
|
||||
@@ -3,11 +3,13 @@ const cheerio = require('cheerio');
|
||||
const { parseDate } = require('@/utils/parse-date');
|
||||
const { art } = require('@/utils/render');
|
||||
const path = require('path');
|
||||
const { domainValidation } = require('./utils');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const { domain = '91porn.com' } = ctx.query;
|
||||
const { uid, lang = 'en_US' } = ctx.params;
|
||||
const siteUrl = `https://${domain}/uvideos.php?UID=${uid}&type=public`;
|
||||
domainValidation(domain, ctx);
|
||||
|
||||
const response = await got.post(siteUrl, {
|
||||
form: {
|
||||
|
||||
@@ -3,11 +3,13 @@ const cheerio = require('cheerio');
|
||||
const { parseDate } = require('@/utils/parse-date');
|
||||
const { art } = require('@/utils/render');
|
||||
const path = require('path');
|
||||
const { domainValidation } = require('./utils');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const { domain = '91porn.com' } = ctx.query;
|
||||
const siteUrl = `https://${domain}/index.php`;
|
||||
const { lang = 'en_US' } = ctx.params;
|
||||
domainValidation(domain, ctx);
|
||||
|
||||
const response = await got.post(siteUrl, {
|
||||
form: {
|
||||
|
||||
12
lib/v2/91porn/utils.js
Normal file
12
lib/v2/91porn/utils.js
Normal file
@@ -0,0 +1,12 @@
|
||||
const config = require('@/config').value;
|
||||
const allowDomain = ['91porn.com', 'www.91porn.com', '0122.91p30.com', 'www.91zuixindizhi.com', 'w1218.91p46.com'];
|
||||
|
||||
const domainValidation = (domain, ctx) => {
|
||||
if (!config.feature.allow_user_supply_unsafe_domain && !allowDomain.includes(domain)) {
|
||||
ctx.throw(403, `This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
domainValidation,
|
||||
};
|
||||
@@ -2,9 +2,13 @@ const got = require('@/utils/got');
|
||||
const cheerio = require('cheerio');
|
||||
const timezone = require('@/utils/timezone');
|
||||
const { parseDate } = require('@/utils/parse-date');
|
||||
const { isValidHost } = require('@/utils/valid-host');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const city = ctx.params.city;
|
||||
if (!isValidHost(city)) {
|
||||
throw Error('Invalid city');
|
||||
}
|
||||
|
||||
const rootUrl = `http://${city}.bendibao.com`;
|
||||
|
||||
|
||||
@@ -3,10 +3,31 @@ const cheerio = require('cheerio');
|
||||
const iconv = require('iconv-lite');
|
||||
const timezone = require('@/utils/timezone');
|
||||
const { parseDate } = require('@/utils/parse-date');
|
||||
const config = require('@/config').value;
|
||||
const allowHost = [
|
||||
'www.xbiquwx.la',
|
||||
'www.biqu5200.net',
|
||||
'www.xbiquge.so',
|
||||
'www.biqugeu.net',
|
||||
'www.b520.cc',
|
||||
'www.ahfgb.com',
|
||||
'www.ibiquge.la',
|
||||
'www.biquge.tv',
|
||||
'www.bswtan.com',
|
||||
'www.biquge.co',
|
||||
'www.bqzhh.com',
|
||||
'www.biqugse.com',
|
||||
'www.ibiquge.info',
|
||||
'www.ishuquge.com',
|
||||
'www.mayiwxw.com',
|
||||
];
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const rootUrl = ctx.path.split('/').slice(1, 4).join('/');
|
||||
const currentUrl = ctx.path.slice(1);
|
||||
if (!config.feature.allow_user_supply_unsafe_domain && !allowHost.includes(new URL(rootUrl).hostname)) {
|
||||
ctx.throw(403, `This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
|
||||
}
|
||||
|
||||
const response = await got({
|
||||
method: 'get',
|
||||
|
||||
@@ -4,10 +4,15 @@ const timezone = require('@/utils/timezone');
|
||||
const { parseDate } = require('@/utils/parse-date');
|
||||
const { art } = require('@/utils/render');
|
||||
const path = require('path');
|
||||
const config = require('@/config').value;
|
||||
const allowDomain = ['btbtt15.com'];
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
let category = ctx.params.category ?? '';
|
||||
let domain = ctx.query.domain ?? 'btbtt20.com';
|
||||
let domain = ctx.query.domain ?? 'btbtt15.com';
|
||||
if (!config.feature.allow_user_supply_unsafe_domain && !allowDomain.includes(new URL(domain).hostname)) {
|
||||
ctx.throw(403, `This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
|
||||
}
|
||||
|
||||
if (category === 'base') {
|
||||
category = '';
|
||||
|
||||
@@ -12,6 +12,9 @@ const categories = {
|
||||
module.exports = async (ctx) => {
|
||||
const category = ctx.params.category ?? 'jxrb';
|
||||
const id = ctx.params.id;
|
||||
if (!Object.keys(categories).includes(category)) {
|
||||
throw Error('Invalid category');
|
||||
}
|
||||
|
||||
const rootUrl = `https://${category}.cnjxol.com`;
|
||||
const currentUrl = `${rootUrl}/${category}Paper/pc/layout`;
|
||||
|
||||
@@ -3,9 +3,13 @@ const cheerio = require('cheerio');
|
||||
const { parseDate } = require('@/utils/parse-date');
|
||||
const defaults = require('./defaults');
|
||||
const shortcuts = require('./shortcuts');
|
||||
const { isValidHost } = require('@/utils/valid-host');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const site = ctx.params[0] ?? 'news';
|
||||
if (!isValidHost(site)) {
|
||||
throw Error('Invalid site');
|
||||
}
|
||||
|
||||
let items;
|
||||
let category = ctx.params[1] ?? (defaults.hasOwnProperty(site) ? defaults[site] : '');
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
const got = require('@/utils/got');
|
||||
const cheerio = require('cheerio');
|
||||
const { parseDate } = require('@/utils/parse-date');
|
||||
|
||||
const { isValidHost } = require('@/utils/valid-host');
|
||||
const cateList = ['all', 'design-resources', 'learn-design', 'inside-eagle'];
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
let cate = ctx.params.cate ?? 'all';
|
||||
let language = ctx.params.language ?? 'cn';
|
||||
if (cateList.indexOf(cate) === -1) {
|
||||
if (!isValidHost(cate) || !isValidHost(language)) {
|
||||
throw Error('Invalid host');
|
||||
}
|
||||
if (!cateList.includes(cate)) {
|
||||
language = cate;
|
||||
cate = 'all';
|
||||
}
|
||||
|
||||
const host = `https://${language}.eagle.cool`;
|
||||
const url = `${host}/blog/${cate === 'all' ? '' : cate}`;
|
||||
|
||||
|
||||
@@ -4,9 +4,13 @@ const cheerio = require('cheerio');
|
||||
const { parseDate } = require('@/utils/parse-date');
|
||||
const { art } = require('@/utils/render');
|
||||
const path = require('path');
|
||||
const allowRegion = ['tw', 'hk'];
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const region = ctx.params.region ?? 'tw';
|
||||
if (!allowRegion.includes(region)) {
|
||||
throw Error('Invalid region');
|
||||
}
|
||||
|
||||
const feed = await parser.parseURL(`https://www.eprice.com.${region}/news/rss.xml`);
|
||||
|
||||
|
||||
@@ -2,11 +2,16 @@ const got = require('@/utils/got');
|
||||
const { parseDate } = require('@/utils/parse-date');
|
||||
const { art } = require('@/utils/render');
|
||||
const path = require('path');
|
||||
const { isValidHost } = require('@/utils/valid-host');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const lang = ctx.params.lang;
|
||||
const type = ctx.params.type ?? 'all';
|
||||
|
||||
if (!isValidHost(lang)) {
|
||||
throw Error('Invalid lang');
|
||||
}
|
||||
|
||||
const response = await got({
|
||||
method: 'get',
|
||||
url: `https://lodestonenews.com/news/${type}?locale=${lang}`,
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
const got = require('@/utils/got');
|
||||
const cheerio = require('cheerio');
|
||||
const parser = require('@/utils/rss-parser');
|
||||
const { isValidHost } = require('@/utils/valid-host');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const { domain = 'news', category } = ctx.params;
|
||||
if (!isValidHost(domain)) {
|
||||
throw Error('Invalid domain');
|
||||
}
|
||||
const baseUrl = `https://${domain}.gamme.com.tw`;
|
||||
const feed = await parser.parseURL(`${baseUrl + (category ? `/category/${category}` : '')}/feed`);
|
||||
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
const got = require('@/utils/got');
|
||||
const cheerio = require('cheerio');
|
||||
const { parseDate } = require('@/utils/parse-date');
|
||||
const { isValidHost } = require('@/utils/valid-host');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const { domain = 'news', tag } = ctx.params;
|
||||
if (!isValidHost(domain)) {
|
||||
throw Error('Invalid domain');
|
||||
}
|
||||
const baseUrl = `https://${domain}.gamme.com.tw`;
|
||||
const pageUrl = `${baseUrl}/tag/${tag}`;
|
||||
|
||||
|
||||
@@ -2,10 +2,14 @@ const got = require('@/utils/got');
|
||||
const cheerio = require('cheerio');
|
||||
const { art } = require('@/utils/render');
|
||||
const path = require('path');
|
||||
const { isValidHost } = require('@/utils/valid-host');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const username = ctx.params.username;
|
||||
const products = ctx.params.products;
|
||||
if (!isValidHost(username)) {
|
||||
throw Error('Invalid username');
|
||||
}
|
||||
const url = `https://${username}.gumroad.com/l/${products}`;
|
||||
|
||||
const response = await got(url);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const got = require('@/utils/got');
|
||||
const cheerio = require('cheerio');
|
||||
const { parseDate } = require('@/utils/parse-date');
|
||||
const { isValidHost } = require('@/utils/valid-host');
|
||||
|
||||
function getKeysRecursive(dic, key, attr, array) {
|
||||
Object.values(dic).forEach((v) => {
|
||||
@@ -15,6 +16,10 @@ function getKeysRecursive(dic, key, attr, array) {
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const category = ctx.params.category ?? 'china';
|
||||
if (!isValidHost(category)) {
|
||||
throw Error('Invalid category');
|
||||
}
|
||||
|
||||
const host = 'https://' + category + '.huanqiu.com';
|
||||
|
||||
const resp = await got({
|
||||
|
||||
@@ -4,10 +4,14 @@ const timezone = require('@/utils/timezone');
|
||||
const { parseDate } = require('@/utils/parse-date');
|
||||
const { art } = require('@/utils/render');
|
||||
const path = require('path');
|
||||
const { isValidHost } = require('@/utils/valid-host');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const user = ctx.params.user ?? '';
|
||||
const id = ctx.params.id ?? '';
|
||||
if (!isValidHost(user)) {
|
||||
throw Error('Invalid user');
|
||||
}
|
||||
|
||||
const rootUrl = `https://${user}.itch.io/${id}/devlog`;
|
||||
|
||||
|
||||
@@ -3,17 +3,27 @@ const cheerio = require('cheerio');
|
||||
const { parseDate } = require('@/utils/parse-date');
|
||||
const { art } = require('@/utils/render');
|
||||
const path = require('path');
|
||||
const config = require('@/config').value;
|
||||
|
||||
const toSize = (raw) => {
|
||||
const matches = raw.match(/(\d+(\.\d+)?)(\w+)/);
|
||||
return matches[3] === 'GB' ? matches[1] * 1024 : matches[1];
|
||||
};
|
||||
|
||||
const allowDomain = ['javbus.com', 'javbus.org', 'javsee.icu', 'javsee.one'];
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const isWestern = /^\/western/.test(ctx.path);
|
||||
const domain = ctx.query.domain ?? 'javbus.com';
|
||||
const westernDomain = ctx.query.western_domain ?? 'javbus.org';
|
||||
|
||||
const rootUrl = `https://www.${domain}`;
|
||||
const westernUrl = `https://www.${westernDomain}`;
|
||||
|
||||
if (!config.feature.allow_user_supply_unsafe_domain && (!allowDomain.includes(new URL(domain).hostname) || !allowDomain.includes(new URL(westernDomain).hostname))) {
|
||||
ctx.throw(403, `This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
|
||||
}
|
||||
|
||||
const rootUrl = `https://www.${ctx.query.domain ?? 'javbus.com'}`;
|
||||
const westernUrl = `https://www.${ctx.query.western_domain ?? 'javbus.org'}`;
|
||||
const currentUrl = `${isWestern ? westernUrl : rootUrl}${ctx.path.replace(/^\/western/, '').replace(/\/home/, '')}`;
|
||||
|
||||
const response = await got({
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
const got = require('@/utils/got');
|
||||
const cheerio = require('cheerio');
|
||||
const { parseDate } = require('@/utils/parse-date');
|
||||
const config = require('@/config').value;
|
||||
const allowDomain = ['javdb.com', 'javdb36.com', 'javdb007.com'];
|
||||
|
||||
module.exports = {
|
||||
ProcessItems: async (ctx, currentUrl, title) => {
|
||||
const domain = ctx.query.domain ?? 'javdb.com';
|
||||
if (!config.feature.allow_user_supply_unsafe_domain && !allowDomain.includes(new URL(domain).hostname)) {
|
||||
ctx.throw(403, `This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
|
||||
}
|
||||
|
||||
const rootUrl = `https://${domain}`;
|
||||
|
||||
const response = await got({
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
const got = require('@/utils/got');
|
||||
const { parseDate } = require('@/utils/parse-date');
|
||||
const { isValidHost } = require('@/utils/valid-host');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const name = ctx.params.name ?? 'i';
|
||||
const limit = ctx.query.limit ? parseInt(ctx.query.limit) : '50';
|
||||
if (!isValidHost(name)) {
|
||||
throw Error('Invalid name');
|
||||
}
|
||||
|
||||
const rootUrl = `${name}.lofter.com`;
|
||||
|
||||
|
||||
@@ -4,10 +4,13 @@ const md = require('markdown-it')({
|
||||
html: true,
|
||||
linkify: true,
|
||||
});
|
||||
const { isValidHost } = require('@/utils/valid-host');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const id = ctx.params.id;
|
||||
|
||||
if (!id.endsWith('.eth') && !isValidHost(id)) {
|
||||
throw Error('Invalid id');
|
||||
}
|
||||
const rootUrl = 'https://mirror.xyz';
|
||||
const currentUrl = id.endsWith('.eth') ? `${rootUrl}/${id}` : `https://${id}.mirror.xyz`;
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ const timezone = require('@/utils/timezone');
|
||||
const { parseDate } = require('@/utils/parse-date');
|
||||
const { art } = require('@/utils/render');
|
||||
const path = require('path');
|
||||
const { isValidHost } = require('@/utils/valid-host');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const category = ctx.params.category ?? '-1';
|
||||
@@ -13,6 +14,10 @@ module.exports = async (ctx) => {
|
||||
const latestAlerts = ctx.params.latestAlerts ?? '1';
|
||||
const latestPictures = ctx.params.latestPictures ?? '1';
|
||||
|
||||
if (language && !isValidHost(language)) {
|
||||
throw Error('Invalid language');
|
||||
}
|
||||
|
||||
const rootUrl = `https://${language === 'en' || language === '' ? '' : `${language}.`}myfigurecollection.net`;
|
||||
const currentUrl = `${rootUrl}/browse.v4.php?mode=activity&latestAdditions=${latestAdditions}&latestEdits=${latestEdits}&latestAlerts=${latestAlerts}&latestPictures=${latestPictures}&rootId=${category}`;
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ const got = require('@/utils/got');
|
||||
const cheerio = require('cheerio');
|
||||
const { art } = require('@/utils/render');
|
||||
const path = require('path');
|
||||
const { isValidHost } = require('@/utils/valid-host');
|
||||
|
||||
const shortcuts = {
|
||||
potd: 'picture/browse/potd/',
|
||||
@@ -12,6 +13,9 @@ const shortcuts = {
|
||||
module.exports = async (ctx) => {
|
||||
const language = ctx.params.language ?? '';
|
||||
const category = ctx.params.category ?? 'figure';
|
||||
if (language && !isValidHost(language)) {
|
||||
throw Error('Invalid language');
|
||||
}
|
||||
|
||||
const rootUrl = `https://${language === 'en' || language === '' ? '' : `${language}.`}myfigurecollection.net`;
|
||||
const currentUrl = `${rootUrl}/${shortcuts.hasOwnProperty(category) ? shortcuts[category] : category}`;
|
||||
|
||||
@@ -2,6 +2,7 @@ const got = require('@/utils/got');
|
||||
const cheerio = require('cheerio');
|
||||
const timezone = require('@/utils/timezone');
|
||||
const { parseDate } = require('@/utils/parse-date');
|
||||
const { isValidHost } = require('@/utils/valid-host');
|
||||
|
||||
const cleanContent = (language, content) => {
|
||||
switch (language) {
|
||||
@@ -23,6 +24,9 @@ module.exports = async (ctx) => {
|
||||
const language = ctx.params.language ?? 'cn';
|
||||
const category = ctx.params.category ?? '';
|
||||
const type = ctx.params.type ?? '';
|
||||
if (!isValidHost(language)) {
|
||||
throw Error('Invalid language');
|
||||
}
|
||||
|
||||
const rootUrl = `https://${language === 'zh' ? `zh.cn` : language}.nikkei.com`;
|
||||
const currentUrl = `${rootUrl}/${category ? (category === 'rss' ? 'rss.html' : `${category}${type ? `/${type}` : ''}.html`) : ''}`;
|
||||
|
||||
@@ -3,12 +3,16 @@ const cheerio = require('cheerio');
|
||||
const iconv = require('iconv-lite');
|
||||
const timezone = require('@/utils/timezone');
|
||||
const { parseDate } = require('@/utils/parse-date');
|
||||
const { isValidHost } = require('@/utils/valid-host');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const site = ctx.params[0] ?? 'www';
|
||||
let category = ctx.params[1] ?? (site === 'www' ? '59476' : '');
|
||||
category = site === 'cpc' && category === '24h' ? '87228' : category;
|
||||
|
||||
if (!isValidHost(site)) {
|
||||
throw Error('Invalid site');
|
||||
}
|
||||
const rootUrl = `http://${site}.people.com.cn`;
|
||||
const currentUrl = `${rootUrl}/GB/${category}/index.html`;
|
||||
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
const cheerio = require('cheerio');
|
||||
const { puppeteerGet, renderDesc } = require('./utils');
|
||||
const config = require('@/config').value;
|
||||
const { isValidHost } = require('@/utils/valid-host');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const pub = ctx.params.pub;
|
||||
const jrn = ctx.params.jrn;
|
||||
const host = `https://${pub}.scitation.org`;
|
||||
const jrnlUrl = `${host}/toc/${jrn}/current?size=all`;
|
||||
if (!isValidHost(pub)) {
|
||||
throw Error('Invalid pub');
|
||||
}
|
||||
|
||||
// use Puppeteer due to the obstacle by cloudflare challenge
|
||||
const browser = await require('@/utils/puppeteer')();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const cheerio = require('cheerio');
|
||||
const { puppeteerGet, renderDesc } = require('./utils');
|
||||
const config = require('@/config').value;
|
||||
const { isValidHost } = require('@/utils/valid-host');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const pub = ctx.params.pub;
|
||||
@@ -8,6 +9,9 @@ module.exports = async (ctx) => {
|
||||
const sec = ctx.params.sec.split('+').join(' ');
|
||||
const host = `https://${pub}.scitation.org`;
|
||||
const jrnlUrl = `${host}/toc/${jrn}/current?size=all`;
|
||||
if (!isValidHost(pub)) {
|
||||
throw Error('Invalid pub');
|
||||
}
|
||||
|
||||
// use Puppeteer due to the obstacle by cloudflare challenge
|
||||
const browser = await require('@/utils/puppeteer')();
|
||||
|
||||
@@ -6,9 +6,14 @@
|
||||
const got = require('@/utils/got'); // get web content
|
||||
const cheerio = require('cheerio'); // html parser
|
||||
const get_article = require('./_article');
|
||||
const { isValidHost } = require('@/utils/valid-host');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const type = ctx.params.type ?? 'www';
|
||||
if (!isValidHost(type)) {
|
||||
throw Error('Invalid type');
|
||||
}
|
||||
|
||||
const base_url = `https://${type}.solidot.org`;
|
||||
const response = await got({
|
||||
method: 'get',
|
||||
|
||||
@@ -2,11 +2,15 @@ const got = require('@/utils/got');
|
||||
const cheerio = require('cheerio');
|
||||
const { parseDate } = require('@/utils/parse-date');
|
||||
const { extractArticle, extractWork } = require('./utils');
|
||||
const { isValidHost } = require('@/utils/valid-host');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const { uid } = ctx.params;
|
||||
let pageUrl = `https://www.zcool.com.cn/u/${uid}`;
|
||||
if (isNaN(uid)) {
|
||||
if (!isValidHost(uid)) {
|
||||
throw Error('Invalid uid');
|
||||
}
|
||||
pageUrl = `https://${uid}.zcool.com.cn`;
|
||||
}
|
||||
const { data: response } = await got(pageUrl);
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
const got = require('@/utils/got');
|
||||
const { parseDate } = require('@/utils/parse-date');
|
||||
const { isValidHost } = require('@/utils/valid-host');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const { id } = ctx.params;
|
||||
const limit = ctx.query.limit ? parseInt(ctx.query.limit) : 20;
|
||||
if (!isValidHost(id)) {
|
||||
throw Error('Invalid id');
|
||||
}
|
||||
|
||||
const response = await got({
|
||||
method: 'get',
|
||||
|
||||
21
test/utils/valid-host.js
Normal file
21
test/utils/valid-host.js
Normal file
@@ -0,0 +1,21 @@
|
||||
const { isValidHost } = require('../../lib/utils/valid-host');
|
||||
|
||||
describe('valid-host', () => {
|
||||
it('validate hostname', () => {
|
||||
expect(isValidHost()).toBe(false);
|
||||
expect(isValidHost(123)).toBe(false);
|
||||
expect(isValidHost('')).toBe(false);
|
||||
expect(isValidHost('subd0main')).toBe(true);
|
||||
expect(isValidHost('-subd0main')).toBe(false);
|
||||
expect(isValidHost('sub-d0main')).toBe(true);
|
||||
expect(isValidHost('subd0main-')).toBe(false);
|
||||
expect(isValidHost('sub.d0main')).toBe(false);
|
||||
expect(isValidHost('sub-.d0main')).toBe(false);
|
||||
expect(isValidHost('s')).toBe(true);
|
||||
expect(isValidHost('-')).toBe(false);
|
||||
expect(isValidHost('0')).toBe(true);
|
||||
expect(isValidHost('s-')).toBe(false);
|
||||
expect(isValidHost('s-u')).toBe(true);
|
||||
expect(isValidHost('su')).toBe(true);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user