-
Notifications
You must be signed in to change notification settings - Fork 51
pkp/pkp-lib#1660 Customizable Reviewer Recommendations #444
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
73e1b28
to
664f865
Compare
6ffce94
to
843402d
Compare
a6bffdd
to
eb21d67
Compare
6a02187
to
3a9b03d
Compare
3a9b03d
to
9a47b49
Compare
9a47b49
to
fe6774b
Compare
406d064
to
253ac65
Compare
70c9f3f
to
b8beae3
Compare
3fc09e1
to
a3dc39d
Compare
this.openDialog({ | ||
name: 'delete', | ||
title: this.deleteRecommendationLabel, | ||
message: this.replaceLocaleParams(this.confirmDeleteMessage, { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an XSS flaw -- any HTML entered in the recommendation.title
will be passed through to the browser. (Also the other keys that mix user-supplied data in here.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@asmecher good spot . I had this left out as v-strip-unsafe-html
was not yet available for main
as we introduced in 3.4.0
. But then forgot to update these as v-strip-unsafe-html
was added just about a week ago in main branch .
One question , rather than applying this for replaceLocaleParams
every time like
message: this.replaceLocaleParams(this.confirmDeleteMessage, {
title: sanitizeHtml(this.localize(recommendation.title)),
})
should we add this sanitizeHtml
into the implementation of replaceLocaleParams
so that we don't need to make sure to add this every time ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
XSS is by default prevented by vue.js, and in cases where we use (and sometime overuse) v-html, its now replaced with v-strip-unsafe-html. Therefore this will go through that. Every component is responsible to do the XSS protection.
Therefore Dialog handles that when rendering message.
<div v-strip-unsafe-html="message" />
No point to sanitize twice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jardakotesovec, I used a <i>
tag to confirm that entered HTML was passed through, and I didn't check whether more malicious tags were filtered -- so it's possible that <i>
gets through because it's "safe", but worse HTML would be filtered. However, it's still incorrectly escaping the content. The reviewer recommendation title is plaintext, not a rich text field, so any entered content should be fully escaped before getting glued into the locale string.
src/components/ListPanel/reviewerRecommendations/ReviewerRecommendationsListPanel.vue
Outdated
Show resolved
Hide resolved
src/components/ListPanel/reviewerRecommendations/ReviewerRecommendationsListPanel.vue
Outdated
Show resolved
Hide resolved
src/components/ListPanel/reviewerRecommendations/ReviewerRecommendationsListPanel.vue
Outdated
Show resolved
Hide resolved
src/components/ListPanel/reviewerRecommendations/ReviewerRecommendationsListPanel.vue
Outdated
Show resolved
Hide resolved
src/pages/dashboard/composables/useDashboardConfigReviewActivity.js
Outdated
Show resolved
Hide resolved
src/pages/dashboard/composables/useDashboardConfigReviewActivity.js
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @touhidurabir. This is very nicely integrated with new code base. I am not sure whether this is aimed for 3.5, so I would understand if some of the 'composition api' updates would be left out for timeline purposes.
But if you decide to do the upgrade and struggle with something feel free to message me directly on mattermost. I should be able to point you to some good example or something.
It's scheduled for 3.6, and I was considering pulling it forward to 3.5 -- but I'd rather spend a bit more time to get a clean implementation than rush it in. So let's leave it on the 3.6 milestone. |
d224862
to
61d5f40
Compare
ccf98ca
to
13594b6
Compare
src/managers/ReviewerRecommendationManager/ReviewerRecommendationManager.vue
Outdated
Show resolved
Hide resolved
src/managers/ReviewerRecommendationManager/ReviewerRecommendationManager.vue
Show resolved
Hide resolved
src/managers/ReviewerRecommendationManager/ReviewerRecommendationManager.vue
Outdated
Show resolved
Hide resolved
src/managers/ReviewerRecommendationManager/ReviewerRecommendationManager.vue
Outdated
Show resolved
Hide resolved
src/managers/ReviewerRecommendationManager/reviewerRecommendationManagerStore.js
Outdated
Show resolved
Hide resolved
src/managers/ReviewerRecommendationManager/reviewerRecommendationManagerStore.js
Outdated
Show resolved
Hide resolved
src/managers/ReviewerRecommendationManager/reviewerRecommendationManagerStore.js
Outdated
Show resolved
Hide resolved
src/managers/ReviewerRecommendationManager/reviewerRecommendationManagerStore.js
Outdated
Show resolved
Hide resolved
? props.confirmDeactivateMessage | ||
: props.confirmActivateMessage, | ||
{ | ||
title: escapeHtml(localize(item.title)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess that the reviewer recommendations are not supporting any html tags, right? So we basically just want to make sure that if it has any html tags it would not be interpreted?
We have couple places like tooltip or dialogs, where we introduced v-html because we had some message in translations which required that. To reduce attack surface area we introduced v-strip-unsafe-html, which at least ensures safe html.
I would like to improve the situation in 3.6 further.
I think for general components that because of some use case started offering v-html - we should have separate props for that. For Example having openDialog with options: message
and messageHtml
. So its decided when the dialog is created whether html is needed and whether its safe based on what I am passing there. For this improvement I will create separate ticket and introduce the html
variants when necessary.
But your use case is bit more nuanced, because you have translation Are you sure you want to deactivate the recommendation <b>{$title}</b>
. Therefore you want to render it as html, but escape the argument, which you are doing, but would be nice to also make the translation toolkit safe by default.
I will leave up to you whether you would add this improvement here, since you already touched on the escaping functions or whether you prefer me to add it in separate ticket, but I think having option in our t
function will be best..
By default t
should escape all the arguments being passed. But need to introduce option to allow html if needed.
So in your case it should look like (now putting aside that I will move the message to messageHtml in separate ticket):
message: item.status ? t('manager.reviewerRecommendations.confirmDeactivate', {title: localize(item.title)}) : ...
But there still would be option, to skip the escaping for specific fields:
t('manager.reviewerRecommendations.confirmDeactivate', {title: localize(item.title)}, {allowHtml: ['title']})
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will and want to work on this but I think it will be better to handle this as a separate issue . Reason is, this would be a global impact level change and a very important one . Better to keep track of this as it's own issue so that we can in future get clear idea what plan and strategy we adapted for this one and what was the implementation. This issue is already got bit too big so better to separate this implementation from this issue .
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree.. make sense to introduce these changes separately.
In that case I would suggest not to introduce the escapeHtml
at this point. Because that will be default behaviour for the message
of dialog. So if you remove it - it will be safe enough for now and after we work on the updates that I mentioned, it will also prevent sneaking in any html to affect rendering.
24e353d
to
003b6aa
Compare
src/managers/ReviewerRecommendationManager/reviewerRecommendationManagerStore.js
Outdated
Show resolved
Hide resolved
Hi @jardakotesovec can you please take another look . |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Regarding useForm, sorry I need to document this better. I did some testing and it seems to be working fine. Feel free to cherry-pick this commit - jardakotesovec@6e4ec1a
I also sneaked in spinner to the table to indicate when the data are being refetched for small connections.
So my suggestion would be to add this commit (seemed working fine from my testing, if you see issue ping me on mattermost).
Resolve other suggestions.
And ping me and I will do the last quick check.
Thank you!
src/managers/ReviewerRecommendationManager/reviewerRecommendationManagerStore.js
Outdated
Show resolved
Hide resolved
src/managers/ReviewerRecommendationManager/reviewerRecommendationManagerStore.js
Outdated
Show resolved
Hide resolved
src/managers/ReviewerRecommendationManager/reviewerRecommendationManagerStore.js
Outdated
Show resolved
Hide resolved
src/managers/ReviewerRecommendationManager/reviewerRecommendationManagerStore.js
Outdated
Show resolved
Hide resolved
81712d6
to
081001c
Compare
@jardakotesovec hopefully ready for the final look , please check . |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just couple small clean up items. Thanks!
src/managers/ReviewerRecommendationManager/ReviewerRecommendationManager.vue
Show resolved
Hide resolved
<SideModalLayoutBasic> | ||
<PkpForm | ||
ref="editRecommendation" | ||
class="recommendations__recommendationForm" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this class needed?
<template #default="{closeModal}"> | ||
<SideModalLayoutBasic> | ||
<PkpForm | ||
ref="editRecommendation" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No big deal, but I think you don't think you need this ref?
const {t, localize} = useLocalize(); | ||
|
||
const items = computed({ | ||
get: () => recommendations.value?.items || [], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So could this be just
computed(() => recommendations.value?.items || [])
}); | ||
|
||
await fetch(); | ||
return isSuccess.value; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor, but isSuccess is not really needed.
const newStatus = !item.status; | ||
|
||
openDialog({ | ||
name: 'edit', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor, name is not used anymore
: t('manager.reviewerRecommendations.deactivate.title'), | ||
message: t( | ||
item.status | ||
? 'manager.reviewerRecommendations.confirmDeactivate' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright.. :-).. this is tricky..
Automatic detection of the locale keys is happening in build time and therefore I have to rely on regex.
So it needs to find t('key') or tk('key') to pick it up.
With having condition like this inside, I don't think it would work.
} | ||
|
||
// Initial data fetch | ||
fetchRecommendations(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is very subjective suggestion about how to organise with composition API. Especially for more complex components trying to group things by feature. So since the beginning is focused on the fetching the recommendations I would do the initial trigger there.
const {
data: recommendations,
fetch: fetchRecommendations,
isLoading: isRecommendationsLoading,
} = useFetch(apiUrl);
// Initial data fetch
fetchRecommendations();
8781121
to
1f8f1ae
Compare
pkp/pkp-lib#1660 remove static recommendations and added dymanic recommendations pulling pkp/pkp-lib#1660 updated activate/deactivate process pkp/pkp-lib#1660 behaviour update of checkbox to activate/deactivate pkp/pkp-lib#1660 table view implementation pkp/pkp-lib#1660 set used recommendation uneditable pkp/pkp-lib#1660 updated dropdown action component pkp/pkp-lib#1660 removed unused imports pkp/pkp-lib#1660 make recommendations optional for reviewer manager component to support OMP/OPS pkp/pkp-lib#1660 added js side html sanitizer to handle XXS issue pkp/pkp-lib#1660 removed value attributes form recommendation
pkp/pkp-lib#1660 fixing storybook pkp/pkp-lib#1660 issue when recommendation not available pkp/pkp-lib#1660 tag remove for put text presentation pkp/pkp-lib#1660 Better escaping added
1f8f1ae
to
5a3e17f
Compare
for pkp/pkp-lib#1660