App icon indicating copy to clipboard operation
App copied to clipboard

[$250] Strip workspace name of html or handle validation php side reported by @kerupuksambel

Open kavimuru opened this issue 2 years ago • 29 comments

If you haven’t already, check out our contributing guidelines for onboarding and email [email protected] to request to join our Slack channel!


Action Performed:

  1. Open staging.new.expensify.com
  2. Create new workspace
  3. Change the name of the workspace with <b> </b> and save it

Expected Result:

Either the workspace name changed to after HTML-escaping (something like <b> </b> ), or returned error after the HTML tag got stripped and only the space remained

Actual Result:

The workspace name changed to no name

Workaround:

unknown

Platform:

Where is this issue occurring?

  • Web

Version Number: 1.2.21-4 Reproducible in staging?: y Reproducible in production?: y Email or phone of affected tester (no customers): Logs: https://stackoverflow.com/c/expensify/questions/4856 Notes/Photos/Videos:

https://user-images.githubusercontent.com/43996225/198730117-135e716c-ada7-4069-b153-df931cee5fc1.mp4

https://user-images.githubusercontent.com/43996225/198730150-69afdab6-b896-461c-945c-97c8914b4e39.mp4

Expensify/Expensify Issue URL: Issue reported by: @kerupuksambel Slack conversation: https://expensify.slack.com/archives/C01GTK53T8Q/p1666949886613589

View all open jobs on GitHub

kavimuru avatar Oct 28 '22 20:10 kavimuru

Triggered auto assignment to @NicMendonca (Bug), see https://stackoverflow.com/c/expensify/questions/14418 for more details.

melvin-bot[bot] avatar Oct 28 '22 20:10 melvin-bot[bot]

I am having trouble reproducing this. Asked in slack here.

NicMendonca avatar Oct 31 '22 18:10 NicMendonca

Okay, I got it. Am able to reproduce with using HTML spacing:

image

NicMendonca avatar Oct 31 '22 18:10 NicMendonca

Triggered auto assignment to @ctkochan22 (Engineering), see https://stackoverflow.com/c/expensify/questions/4319 for more details.

melvin-bot[bot] avatar Oct 31 '22 18:10 melvin-bot[bot]

Triggered auto assignment to @trjExpensify (External), see https://stackoverflow.com/c/expensify/questions/8582 for more details.

melvin-bot[bot] avatar Nov 04 '22 05:11 melvin-bot[bot]

Triggered auto assignment to Contributor-plus team member for initial proposal review - @rushatgabhane (External)

melvin-bot[bot] avatar Nov 04 '22 05:11 melvin-bot[bot]

Current assignee @ctkochan22 is eligible for the External assigner, not assigning anyone new.

melvin-bot[bot] avatar Nov 04 '22 05:11 melvin-bot[bot]

Looks related to https://github.com/Expensify/App/issues/12000

ctkochan22 avatar Nov 04 '22 05:11 ctkochan22

Got it, so does it need to be internal as per this comment? https://github.com/Expensify/App/issues/12000#issuecomment-1296576574

trjExpensify avatar Nov 04 '22 19:11 trjExpensify

@ctkochan22 bump on the above question?

trjExpensify avatar Nov 07 '22 20:11 trjExpensify

Proposal

diff --git a/src/pages/workspace/WorkspaceSettingsPage.js b/src/pages/workspace/WorkspaceSettingsPage.js
index e778ecf89..feefb74c7 100644
--- a/src/pages/workspace/WorkspaceSettingsPage.js
+++ b/src/pages/workspace/WorkspaceSettingsPage.js
@@ -56,7 +56,7 @@ class WorkspaceSettingsPage extends React.Component {
         if (this.props.policy.isPolicyUpdating) {
             return;
         }
-        const name = values.name.trim();
+        const name = values.name?.replace(/(<([^>]+)>)/ig, '').trim();
         const outputCurrency = values.currency;
         Policy.updateGeneralSettings(this.props.policy.id, name, outputCurrency);
         Keyboard.dismiss();
@@ -64,7 +64,8 @@ class WorkspaceSettingsPage extends React.Component {
 
     validate(values) {
         const errors = {};
-        if (!values.name || !values.name.trim().length) {
+        const name = values.name?.replace(/(<([^>]+)>)/ig, '').trim();
+        if (!name || !name.length) {
             errors.name = this.props.translate('workspace.editor.nameIsRequiredError');
         }
         return errors;

https://user-images.githubusercontent.com/16493223/200658772-e73798d4-fca0-4843-9ae9-3c46fb5073c5.mp4

s77rt avatar Nov 08 '22 19:11 s77rt

Got it, so does it need to be internal as per this comment? https://github.com/Expensify/App/issues/12000#issuecomment-1296576574

I think i'm wrong about that. They seem like separate issues.

ctkochan22 avatar Nov 09 '22 05:11 ctkochan22

@s77rt can you please explain the proposal and why it'd fix the issue?

rushatgabhane avatar Nov 09 '22 06:11 rushatgabhane

@rushatgabhane

  1. Strip any html tags (using regex (<([^>]+)>)/ig
  2. Trim the output
  3. Check if the name is defined and has a length (>0)

s77rt avatar Nov 09 '22 06:11 s77rt

Another Proposal (idea)

Instead of stripping the tags, we can encode them, so the user would have the ability to name the workspace something like <test> WokrspaceA. However the tags gets stripped in the API. As long as the API strips the tags (and not escape them) the first proposal is the best fit here.

s77rt avatar Nov 09 '22 06:11 s77rt

Seems like https://stackoverflow.com/questions/31515999/how-to-remove-all-html-tags-from-a-string has a better regex option. Strangely we don't do this anywhere else either.

I think we should also validate the end result on the PHP side, and have a properly caught error.

ctkochan22 avatar Nov 09 '22 06:11 ctkochan22

@s77rt thanks for your proposal. Let me try doing a PHP side error handler first and see how that goes

ctkochan22 avatar Nov 09 '22 06:11 ctkochan22

Updated Proposal

diff --git a/src/pages/workspace/WorkspaceSettingsPage.js b/src/pages/workspace/WorkspaceSettingsPage.js
index e778ecf89..a20413c68 100644
--- a/src/pages/workspace/WorkspaceSettingsPage.js
+++ b/src/pages/workspace/WorkspaceSettingsPage.js
@@ -56,7 +56,7 @@ class WorkspaceSettingsPage extends React.Component {
         if (this.props.policy.isPolicyUpdating) {
             return;
         }
-        const name = values.name.trim();
+        const name = values.name.replace(/<(.|\n)*?>/g, '').trim();
         const outputCurrency = values.currency;
         Policy.updateGeneralSettings(this.props.policy.id, name, outputCurrency);
         Keyboard.dismiss();
@@ -64,7 +64,7 @@ class WorkspaceSettingsPage extends React.Component {
 
     validate(values) {
         const errors = {};
-        if (!values.name || !values.name.trim().length) {
+        if (!values.name || !values.name.replace(/<(.|\n)*?>/g, '').trim().length) {
             errors.name = this.props.translate('workspace.editor.nameIsRequiredError');
         }
         return errors;
  • The change is clearer this way
  • The first proposal will return a literal "undefined" in case the name was undefined (due to using .replace with an undefined)
  • Uses the suggested regex

https://user-images.githubusercontent.com/16493223/200758101-0d5e4597-ac18-4983-96fe-618250f657cf.mp4

s77rt avatar Nov 09 '22 06:11 s77rt

@ctkochan22 does this need the Internal label? Also, it's a Bug in the App repo, so we should keep this on Daily as we look to achieve BugZero for WAQ.

Can we confirm what the expected result is here and update the OP. Is this is?

  • If the workspace name includes HTML tags with no value between them (i.e <b> <b>, treat this as "blank" and show the error message that a workspace name is required.
  • If the workspace name includes HTML tags with a value between them (i.e <b> My workspace <b>), display My workspace as the workspace name. ✅ - this is working as expected

FWIW, I thought I'd test this out on Profile > FirstName/LastName fields to compare the behaviour and how we handle it, but we have a fall back on the primaryLogin when a name isn't set:

<b> value <b> ✅ (same scenario for the workspace name)

image

<b> <b> blank (thus reverting to the primaryLogin, which is okay in this use-case because a name is optional). image

Thanks!

trjExpensify avatar Nov 09 '22 11:11 trjExpensify

Sorry @trjExpensify going to go back on what I said, and bring this back internal.

My reasoning is as a rule of thumb, we always should have error catches as far server-side as possible and in each layer. Auth is ideal. Then PHP. Then client-side.

I'm going to add a catch PHP side, and we'll return an error.

@trjExpensify How do you think we should handle this error? Do you happen to know what our convention is with errors we don't explicitly need users to "clear"

ctkochan22 avatar Nov 10 '22 00:11 ctkochan22

A Contributor Manager will be assigned to issue payment via Upwork if we deploy an associated Pull Request to production. Per Contributing.md.

melvin-bot[bot] avatar Nov 10 '22 01:11 melvin-bot[bot]

Cool, switched the label.

@trjExpensify How do you think we should handle this error? Do you happen to know what our convention is with errors we don't explicitly need users to "clear"

Yep, let's follow the guidelines for form alerts: https://github.com/Expensify/App/blob/main/contributingGuides/FORMS.md#form-alerts

We largely have what we need here:

image

trjExpensify avatar Nov 10 '22 01:11 trjExpensify

The error will look a little different because its an error being returned form the php side.

image

Following how the code in the Form works at the moment.

ctkochan22 avatar Nov 11 '22 00:11 ctkochan22

Got it. It would be better if that was in-line to the field in error really.

trjExpensify avatar Nov 11 '22 00:11 trjExpensify

Yeah, I'm trying to see if I can make that happen. Currently I only know how to do that as a pending error, meaning the user would have to click an "x" to get rid of it. Which I don't like.

There must be a way

ctkochan22 avatar Nov 11 '22 00:11 ctkochan22

When there's a will, there's a way. 😉

trjExpensify avatar Nov 11 '22 00:11 trjExpensify

So we are discussing how to do inline here: https://expensify.slack.com/archives/C03TQ48KC/p1668128270722689

  • Seems like a new PR could allow us to add inline errors - https://github.com/Expensify/App/pull/11465

In the meantime, this is the Web PR to get it fixed: https://github.com/Expensify/Web-Expensify/pull/35548

ctkochan22 avatar Nov 11 '22 18:11 ctkochan22

unassigning since internal

rushatgabhane avatar Nov 13 '22 09:11 rushatgabhane

@rushatgabhane may be external as well (client side validation)

s77rt avatar Nov 13 '22 09:11 s77rt

Okay awesome, so @ctkochan22 are we holding that PR on @youssef-lr's here?

trjExpensify avatar Nov 14 '22 13:11 trjExpensify