diff --git a/source/controlers/rss.ts b/source/controlers/rss.ts index 3dbed2aeaa9..3bafcbce9c4 100644 --- a/source/controlers/rss.ts +++ b/source/controlers/rss.ts @@ -4,6 +4,7 @@ import twoKeyReply from '../utils/two-key-reply'; import errors from '../utils/errors'; import { MContext, Next } from '../types/ctx'; import { isNone } from '../types/option'; +import { decodeUrl } from '../utils/decodeUrl'; export async function sub(ctx: MContext, next: Next): Promise { const { feedUrl, chat, lang } = ctx.state; @@ -84,7 +85,7 @@ export async function rss(ctx: MContext, next: Next): Promise { builder.push( `${feed.feed_title.trim()}: ${decodeURI(feed.url.trim())}` + )}">${decodeUrl(feed.url.trim())}` ); }); } else { @@ -154,7 +155,7 @@ export async function getUrlById(ctx: MContext, next: Next): Promise { const { text } = ctx.message; const feed_id = text.match(/^\[(\d+)] (.+)/)[1]; const feed = await RSS.getFeedById(parseInt(feed_id)); - ctx.state.feedUrl = decodeURI(feed.url); + ctx.state.feedUrl = decodeUrl(feed.url); await next(); } diff --git a/source/middlewares/get-url-by-title.ts b/source/middlewares/get-url-by-title.ts index 090ac0359d2..7e016bb586e 100644 --- a/source/middlewares/get-url-by-title.ts +++ b/source/middlewares/get-url-by-title.ts @@ -2,6 +2,7 @@ import { MContext, Next } from '../types/ctx'; import { getFeedsByTitle } from '../proxies/rss-feed'; import errors from '../utils/errors'; +import { decodeUrl } from '../utils/decodeUrl'; export default async (ctx: MContext, next: Next): Promise => { const me = await ctx.telegram.getMe(); const myId = me.id; @@ -14,6 +15,6 @@ export default async (ctx: MContext, next: Next): Promise => { if (feeds.length > 1) throw errors.newCtrlErr('SAME_NAME'); if (feeds.length === 0) throw errors.newCtrlErr('UNSUBTHIS_USAGE'); ctx.state.feed = feeds[0]; - ctx.state.feedUrl = decodeURI(feeds[0].url); + ctx.state.feedUrl = decodeUrl(feeds[0].url); await next(); }; diff --git a/source/middlewares/get-url.ts b/source/middlewares/get-url.ts index 1ee3adf9ee1..72ae4f1c833 100644 --- a/source/middlewares/get-url.ts +++ b/source/middlewares/get-url.ts @@ -2,6 +2,7 @@ import errors from '../utils/errors'; import { getSubscribedFeedsByUserId } from '../proxies/rss-feed'; import i18n from '../i18n'; import { MContext, Next } from '../types/ctx'; +import { decodeUrl } from '../utils/decodeUrl'; export default async (ctx: MContext, next: Next): Promise => { const { lang } = ctx.state; @@ -41,6 +42,6 @@ export default async (ctx: MContext, next: Next): Promise => { } else if (!url.startsWith('http') && !url.startsWith('https')) { throw errors.newCtrlErr('FEED_URL_NOT_PARSE'); } - ctx.state.feedUrl = decodeURI(url); + ctx.state.feedUrl = decodeUrl(url); await next(); }; diff --git a/source/middlewares/sub-multi-url.ts b/source/middlewares/sub-multi-url.ts index 589b80c4695..a3b9b03794f 100644 --- a/source/middlewares/sub-multi-url.ts +++ b/source/middlewares/sub-multi-url.ts @@ -6,6 +6,7 @@ import { MContext, Next } from '../types/ctx'; import { isSome } from '../types/option'; import { Feed } from '../types/feed'; import { parseString } from '../parser/parse'; +import { decodeUrl } from '../utils/decodeUrl'; export default async (ctx: MContext, next: Next): Promise => { const urls = ctx.message.text.match( @@ -15,7 +16,7 @@ export default async (ctx: MContext, next: Next): Promise => { const feedsReady = await Promise.all( urls.map( async (url): Promise> => { - url = decodeURI(url); // idempotent operation just do it first + url = decodeUrl(url); // decode first const feed = await getFeedByUrl(url); if (isSome(feed)) { return feed.value; diff --git a/source/middlewares/test-url.ts b/source/middlewares/test-url.ts index 26148448a04..9a08e3e356f 100644 --- a/source/middlewares/test-url.ts +++ b/source/middlewares/test-url.ts @@ -6,6 +6,7 @@ import { getFeedByUrl } from '../proxies/rss-feed'; import { MContext, Next } from '../types/ctx'; import { isNone, isSome } from '../types/option'; import { parseString } from '../parser/parse'; +import { decodeUrl } from '../utils/decodeUrl'; export default async (ctx: MContext, next: Next): Promise => { const url = encodeURI(ctx.state.feedUrl); @@ -17,12 +18,12 @@ export default async (ctx: MContext, next: Next): Promise => { } else { try { const res = await got(url); - ctx.state.feedUrl = decodeURI(res.url); // handle redirect + ctx.state.feedUrl = decodeUrl(res.url); // handle redirect const feedOption = await isFeedValid(res.body); if (isNone(feedOption)) { // feed is NOT valid, try to find feed by link tag with type contain rss/atom ctx.state.feedUrls = await findFeed(res.body, res.url); - ctx.state.feedUrls = ctx.state.feedUrls.map(decodeURI); + ctx.state.feedUrls = ctx.state.feedUrls.map(decodeUrl); /* eslint no-case-declarations: 0*/ switch (ctx.state.feedUrls.length) { case 0: diff --git a/source/proxies/rss-feed.ts b/source/proxies/rss-feed.ts index 78debacdaad..8c870b282e9 100644 --- a/source/proxies/rss-feed.ts +++ b/source/proxies/rss-feed.ts @@ -3,13 +3,14 @@ import errors from '../utils/errors'; import { Feed } from '../types/feed'; import { Subscribe } from '../types/subscribe'; import { isSome, Option, Optional, Some } from '../types/option'; +import { decodeUrl } from '../utils/decodeUrl'; export async function sub( userId: number, feedUrl: string, feedTitle: string ): Promise { - feedUrl = decodeURI(feedUrl); + feedUrl = decodeUrl(feedUrl); const feed = await db('rss_feed').where('url', feedUrl).first(); if (feed) { const res = await db('subscribes') @@ -211,6 +212,7 @@ export async function handleRedirect( realUrl: string ): Promise { try { + realUrl = decodeUrl(realUrl); const oldFeed: Option = Optional( await db('rss_feed').where('url', url).first() ); diff --git a/source/utils/decodeUrl.ts b/source/utils/decodeUrl.ts new file mode 100644 index 00000000000..7707d913099 --- /dev/null +++ b/source/utils/decodeUrl.ts @@ -0,0 +1,6 @@ +export function decodeUrl(url) { + while (url !== decodeURIComponent(url)) { + url = decodeURIComponent(url); + } + return url; +} diff --git a/source/utils/fetch.ts b/source/utils/fetch.ts index b482433ee25..929f4a1506b 100644 --- a/source/utils/fetch.ts +++ b/source/utils/fetch.ts @@ -60,7 +60,7 @@ async function fetch(feedModal: Feed): Promise> { logger.debug(`fetching ${feedUrl}`); const res = await got.get(encodeURI(feedUrl)); if (encodeURI(feedUrl) !== res.url && Object.is(res.statusCode, 301)) { - await handleRedirect(feedUrl, decodeURI(res.url)); + await handleRedirect(feedUrl, res.url); } const feed = await parseString(res.body);