From 82d5ac99df0d6b46b2130aea9b393525c6ec2815 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Fri, 13 Sep 2019 11:55:38 +0200 Subject: [PATCH 01/22] Make hashtag links URL safe --- backend/src/middleware/hashtags/extractHashtags.js | 2 +- backend/src/middleware/hashtags/extractHashtags.spec.js | 6 +++--- backend/src/middleware/hashtags/hashtagsMiddleware.spec.js | 4 ++-- webapp/components/Editor/nodes/Hashtag.js | 2 +- webapp/pages/admin/tags.vue | 2 +- webapp/pages/index.vue | 3 ++- webapp/pages/search/hashtag/_id.vue | 5 +++-- 7 files changed, 13 insertions(+), 11 deletions(-) diff --git a/backend/src/middleware/hashtags/extractHashtags.js b/backend/src/middleware/hashtags/extractHashtags.js index c7782e59d..13f29475e 100644 --- a/backend/src/middleware/hashtags/extractHashtags.js +++ b/backend/src/middleware/hashtags/extractHashtags.js @@ -20,7 +20,7 @@ export default function(content) { .get() const hashtags = [] urls.forEach(url => { - const match = exec(url, regX) + const match = exec(decodeURI(url), regX) if (match != null) { hashtags.push(match[1]) } diff --git a/backend/src/middleware/hashtags/extractHashtags.spec.js b/backend/src/middleware/hashtags/extractHashtags.spec.js index 2e1761718..0881e33a3 100644 --- a/backend/src/middleware/hashtags/extractHashtags.spec.js +++ b/backend/src/middleware/hashtags/extractHashtags.spec.js @@ -27,14 +27,14 @@ describe('extractHashtags', () => { expect(extractHashtags(content)).toEqual(['Democracy']) }) - it('ignores Hashtag links with not allowed character combinations', () => { + it('ignores Hashtag links with not allowed character combinations and handles `encodeURI` URLs', () => { // Allowed are all unicode letters '\pL' and all digits '0-9'. There haveto be at least one letter in it. const content = - '

Something inspirational about #AbcDefXyz0123456789!*(),2, #0123456789, #0123456789a, #AbcDefXyz0123456789, and #λαπ.

' + '

Something inspirational about #AbcDefXyz0123456789!*(),2, #0123456789, #0123456789a, #AbcDefXyz0123456789, and #ħπαλ.

' expect(extractHashtags(content).sort()).toEqual([ '0123456789a', 'AbcDefXyz0123456789', - 'λαπ', + 'ħπαλ', ]) }) }) diff --git a/backend/src/middleware/hashtags/hashtagsMiddleware.spec.js b/backend/src/middleware/hashtags/hashtagsMiddleware.spec.js index 3f101f778..16cd96eb7 100644 --- a/backend/src/middleware/hashtags/hashtagsMiddleware.spec.js +++ b/backend/src/middleware/hashtags/hashtagsMiddleware.spec.js @@ -129,8 +129,8 @@ describe('hashtags', () => { ) }) - describe('afterwards update the Post by removing a Hashtag, leaving a Hashtag and add a Hashtag', () => { - // The already existing Hashtag has no class at this point. + describe('afterwards update the Post by removing a hashtag, leaving a hashtag and add a hashtag', () => { + // The already existing hashtag has no class at this point. const postContent = '

Hey Dude, #Elections should work equal for everybody!? That seems to be the only way to have equal #Liberty for everyone.

' diff --git a/webapp/components/Editor/nodes/Hashtag.js b/webapp/components/Editor/nodes/Hashtag.js index 97220668f..bf1530ceb 100644 --- a/webapp/components/Editor/nodes/Hashtag.js +++ b/webapp/components/Editor/nodes/Hashtag.js @@ -25,7 +25,7 @@ export default class Hashtag extends TipTapMention { 'a', { class: this.options.mentionClass, - href: `/search/hashtag/${node.attrs.id}`, + href: `/search/hashtag/${encodeURI(node.attrs.id)}`, 'data-hashtag-id': node.attrs.id, target: '_blank', }, diff --git a/webapp/pages/admin/tags.vue b/webapp/pages/admin/tags.vue index 9ede1d502..e068d68fa 100644 --- a/webapp/pages/admin/tags.vue +++ b/webapp/pages/admin/tags.vue @@ -5,7 +5,7 @@ {{ scope.index + 1 }}. diff --git a/webapp/pages/index.vue b/webapp/pages/index.vue index 31e07f382..99668f67a 100644 --- a/webapp/pages/index.vue +++ b/webapp/pages/index.vue @@ -75,7 +75,8 @@ export default { MasonryGridItem, }, data() { - const { hashtag = null } = this.$route.query + let { hashtag = null } = this.$route.query + hashtag = decodeURI(hashtag) return { posts: [], hasMore: true, diff --git a/webapp/pages/search/hashtag/_id.vue b/webapp/pages/search/hashtag/_id.vue index d180b4e4f..f501b67bc 100644 --- a/webapp/pages/search/hashtag/_id.vue +++ b/webapp/pages/search/hashtag/_id.vue @@ -5,8 +5,9 @@ From ee8ce5a153a7aad290c30edb06e67766216620a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Fri, 13 Sep 2019 13:07:12 +0200 Subject: [PATCH 02/22] Comment clearification --- webapp/pages/search/hashtag/_id.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/pages/search/hashtag/_id.vue b/webapp/pages/search/hashtag/_id.vue index f501b67bc..38364d86f 100644 --- a/webapp/pages/search/hashtag/_id.vue +++ b/webapp/pages/search/hashtag/_id.vue @@ -6,7 +6,7 @@ export default { mounted() { let { id: hashtag } = this.$route.params - // 'hashtag' seems automatically 'decodeURI' on macOS Firefox. Don't know if this is always the case. + // 'hashtag' seems automatically to be 'decodeURI' (on macOS Firefox). Don't know if this is always the case. this.$router.push({ path: '/', query: { hashtag: encodeURI(hashtag) } }) }, } From 0157cc3700f42b8c2885502c5ea396f5b6256435 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Fri, 13 Sep 2019 13:58:59 +0200 Subject: [PATCH 03/22] Refactor routing of of hashtag links --- webapp/middleware/searchHashtag.js | 16 ++++++++++++++++ webapp/nuxt.config.js | 2 +- webapp/pages/search/hashtag/_id.vue | 13 ------------- 3 files changed, 17 insertions(+), 14 deletions(-) create mode 100644 webapp/middleware/searchHashtag.js delete mode 100644 webapp/pages/search/hashtag/_id.vue diff --git a/webapp/middleware/searchHashtag.js b/webapp/middleware/searchHashtag.js new file mode 100644 index 000000000..a1bdda7e9 --- /dev/null +++ b/webapp/middleware/searchHashtag.js @@ -0,0 +1,16 @@ +import { exec, build } from 'xregexp/xregexp-all.js' + +export default async ({ store, env, route, redirect }) => { + let publicPages = env.publicPages + // only affect non public pages + if (publicPages.indexOf(route.name) >= 0) { + return true + } + + const regX = build('^/search/hashtag/((\\pL+[\\pL0-9]*)|([0-9]+\\pL+[\\pL0-9]*))$') + const matchHashtag = exec(decodeURI(route.name), regX) + + if (!matchHashtag) return true + + return redirect(`/?hashtag=${encodeURI(matchHashtag[0])}`) +} diff --git a/webapp/nuxt.config.js b/webapp/nuxt.config.js index 858294f37..5942d34e0 100644 --- a/webapp/nuxt.config.js +++ b/webapp/nuxt.config.js @@ -123,7 +123,7 @@ export default { ], router: { - middleware: ['authenticated', 'termsAndConditions'], + middleware: ['authenticated', 'termsAndConditions', 'searchHashtag'], linkActiveClass: 'router-link-active', linkExactActiveClass: 'router-link-exact-active', scrollBehavior: (to, _from, savedPosition) => { diff --git a/webapp/pages/search/hashtag/_id.vue b/webapp/pages/search/hashtag/_id.vue deleted file mode 100644 index 38364d86f..000000000 --- a/webapp/pages/search/hashtag/_id.vue +++ /dev/null @@ -1,13 +0,0 @@ - - - From 92df820323453ad6885fc623f70fb76bd4bcd730 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Fri, 13 Sep 2019 15:09:33 +0200 Subject: [PATCH 04/22] Rename `/admin/tags.vue` to `/admin/hashtags.vue` --- webapp/locales/de.json | 2 +- webapp/locales/en.json | 2 +- webapp/pages/admin.vue | 4 ++-- webapp/pages/admin/{tags.vue => hashtags.vue} | 10 +++++----- 4 files changed, 9 insertions(+), 9 deletions(-) rename webapp/pages/admin/{tags.vue => hashtags.vue} (79%) diff --git a/webapp/locales/de.json b/webapp/locales/de.json index 381e493f8..567febbeb 100644 --- a/webapp/locales/de.json +++ b/webapp/locales/de.json @@ -269,7 +269,7 @@ "categoryName": "Name", "postCount": "Beiträge" }, - "tags": { + "hashtags": { "name": "Hashtags", "number": "Nr.", "nameOfHashtag": "Name", diff --git a/webapp/locales/en.json b/webapp/locales/en.json index 66ab4a47b..2cb22e690 100644 --- a/webapp/locales/en.json +++ b/webapp/locales/en.json @@ -270,7 +270,7 @@ "categoryName": "Name", "postCount": "Posts" }, - "tags": { + "hashtags": { "name": "Hashtags", "number": "No.", "nameOfHashtag": "Name", diff --git a/webapp/pages/admin.vue b/webapp/pages/admin.vue index 4d498dc9b..7852673b0 100644 --- a/webapp/pages/admin.vue +++ b/webapp/pages/admin.vue @@ -48,8 +48,8 @@ export default { path: `/admin/categories`, }, { - name: this.$t('admin.tags.name'), - path: `/admin/tags`, + name: this.$t('admin.hashtags.name'), + path: `/admin/hashtags`, }, { name: this.$t('admin.invites.name'), diff --git a/webapp/pages/admin/tags.vue b/webapp/pages/admin/hashtags.vue similarity index 79% rename from webapp/pages/admin/tags.vue rename to webapp/pages/admin/hashtags.vue index e068d68fa..76306873a 100644 --- a/webapp/pages/admin/tags.vue +++ b/webapp/pages/admin/hashtags.vue @@ -1,5 +1,5 @@