diff options
| author | Johann150 <johann.galle@protonmail.com> | 2022-02-10 11:47:46 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-02-10 19:47:46 +0900 |
| commit | afb63049798dd0277cd9045eb00a16ab1228376b (patch) | |
| tree | c3a00837a7fc7e626f5632902cf894db326c7828 /packages/client/src | |
| parent | Node v16.13.2 (#8281) (diff) | |
| download | sharkey-afb63049798dd0277cd9045eb00a16ab1228376b.tar.gz sharkey-afb63049798dd0277cd9045eb00a16ab1228376b.tar.bz2 sharkey-afb63049798dd0277cd9045eb00a16ab1228376b.zip | |
fix: regular expressions in word mutes (#8254)
* fix: handle regex exceptions for word mutes
* add i18n strings
Co-authored-by: rinsuki <428rinsuki+git@gmail.com>
* stricter input validation in backend
* add migration for hard mutes
* fix
* use correct regex library in migration
* use query builder to avoid SQL injection
Co-authored-by: Robin B <robflop98@outlook.com>
Co-authored-by: rinsuki <428rinsuki+git@gmail.com>
Diffstat (limited to 'packages/client/src')
| -rw-r--r-- | packages/client/src/pages/settings/word-mute.vue | 55 | ||||
| -rw-r--r-- | packages/client/src/scripts/check-word-mute.ts | 31 |
2 files changed, 69 insertions, 17 deletions
diff --git a/packages/client/src/pages/settings/word-mute.vue b/packages/client/src/pages/settings/word-mute.vue index 19980dea14..bdccd7f1ee 100644 --- a/packages/client/src/pages/settings/word-mute.vue +++ b/packages/client/src/pages/settings/word-mute.vue @@ -81,18 +81,65 @@ export default defineComponent({ }, async created() { - this.softMutedWords = this.$store.state.mutedWords.map(x => x.join(' ')).join('\n'); - this.hardMutedWords = this.$i.mutedWords.map(x => x.join(' ')).join('\n'); + const render = (mutedWords) => mutedWords.map(x => { + if (Array.isArray(x)) { + return x.join(' '); + } else { + return x; + } + }).join('\n'); + + this.softMutedWords = render(this.$store.state.mutedWords); + this.hardMutedWords = render(this.$i.mutedWords); this.hardWordMutedNotesCount = (await os.api('i/get-word-muted-notes-count', {})).count; }, methods: { async save() { - this.$store.set('mutedWords', this.softMutedWords.trim().split('\n').map(x => x.trim().split(' '))); + const parseMutes = (mutes, tab) => { + // split into lines, remove empty lines and unnecessary whitespace + let lines = mutes.trim().split('\n').map(line => line.trim()).filter(line => line != ''); + + // check each line if it is a RegExp or not + for(let i = 0; i < lines.length; i++) { + const line = lines[i] + const regexp = line.match(/^\/(.+)\/(.*)$/); + if (regexp) { + // check that the RegExp is valid + try { + new RegExp(regexp[1], regexp[2]); + // note that regex lines will not be split by spaces! + } catch (err) { + // invalid syntax: do not save, do not reset changed flag + os.alert({ + type: 'error', + title: this.$ts.regexpError, + text: this.$t('regexpErrorDescription', { tab, line: i + 1 }) + "\n" + err.toString() + }); + // re-throw error so these invalid settings are not saved + throw err; + } + } else { + lines[i] = line.split(' '); + } + } + }; + + let softMutes, hardMutes; + try { + softMutes = parseMutes(this.softMutedWords, this.$ts._wordMute.soft); + hardMutes = parseMutes(this.hardMutedWords, this.$ts._wordMute.hard); + } catch (err) { + // already displayed error message in parseMutes + return; + } + + this.$store.set('mutedWords', softMutes); await os.api('i/update', { - mutedWords: this.hardMutedWords.trim().split('\n').map(x => x.trim().split(' ')), + mutedWords: hardMutes, }); + this.changed = false; }, diff --git a/packages/client/src/scripts/check-word-mute.ts b/packages/client/src/scripts/check-word-mute.ts index 55637bb3b3..74e2581863 100644 --- a/packages/client/src/scripts/check-word-mute.ts +++ b/packages/client/src/scripts/check-word-mute.ts @@ -1,23 +1,28 @@ -export function checkWordMute(note: Record<string, any>, me: Record<string, any> | null | undefined, mutedWords: string[][]): boolean { +export function checkWordMute(note: Record<string, any>, me: Record<string, any> | null | undefined, mutedWords: Array<string | string[]>): boolean { // 自分自身 if (me && (note.userId === me.id)) return false; - const words = mutedWords - // Clean up - .map(xs => xs.filter(x => x !== '')) - .filter(xs => xs.length > 0); - - if (words.length > 0) { + if (mutedWords.length > 0) { if (note.text == null) return false; - const matched = words.some(and => - and.every(keyword => { - const regexp = keyword.match(/^\/(.+)\/(.*)$/); - if (regexp) { + const matched = mutedWords.some(filter => { + if (Array.isArray(filter)) { + return filter.every(keyword => note.text!.includes(keyword)); + } else { + // represents RegExp + const regexp = filter.match(/^\/(.+)\/(.*)$/); + + // This should never happen due to input sanitisation. + if (!regexp) return false; + + try { return new RegExp(regexp[1], regexp[2]).test(note.text!); + } catch (err) { + // This should never happen due to input sanitisation. + return false; } - return note.text!.includes(keyword); - })); + } + }); if (matched) return true; } |