-
Notifications
You must be signed in to change notification settings - Fork 2.9k
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
[$500] Chat - Square bracket does not break the link #28608
Comments
Job added to Upwork: https://www.upwork.com/jobs/~018a9cfe2e1c136177 |
Triggered auto assignment to @isabelastisser ( |
Bug0 Triage Checklist (Main S/O)
|
Triggered auto assignment to Contributor-plus team member for initial proposal review - @aimane-chnaif ( |
ProposalPlease re-state the problem that we are trying to solve in this issue.Messages containing URLs with parameters that end in square brackets posted as comments do not have the brackets parsed out. When the message is sent, whomever clicks the link will be taken to a wrong address. What is the root cause of that problem?After digging around in the codebase, I found the problem lived in the expensify-common repo which is being used here. More precisely, in this regex that's used to parse and transform plain text messages to HTML, it's escaping square brackets (i.e. allowing them to be part of the query parameter), when they shouldn't be because What changes do you think we should make in order to solve the problem?Both What alternative solutions did you explore? (Optional)Reminder: Please use plain English, be brief and avoid jargon. Feel free to use images, charts or pseudo-code if necessary. Do not post large multi-line diffs or write walls of text. Do not create PRs unless you have been hired for this job. |
📣 @szilard-dobai! 📣
|
✅ Contributor details stored successfully. Thank you for contributing to Expensify! |
@Tony-MK |
ProposalPlease re-state the problem that we are trying to solve in this issue.App considers closing square bracket as part of link if link as parameter in it What is the root cause of that problem?Square bracket is considered to be possible param char of URL(in What changes do you think we should make in order to solve the problem?As we can check on report video, ending parenthesis is not accepted, but square bracket is. |
📣 @r3770! 📣
|
@isabelastisser, @aimane-chnaif Uh oh! This issue is overdue by 2 days. Don't forget to update your issues! |
📣 It's been a week! Do we have any satisfactory proposals yet? Do we need to adjust the bounty for this issue? 💸 |
@isabelastisser, @aimane-chnaif 6 days overdue. This is scarier than being forced to listen to Vogon poetry! |
reviewing today |
ProposalPlease re-state the problem that we are trying to solve in this issue.Chat - Square bracket does not break the link What is the root cause of that problem?We only have the logic to break links for one type of bracket i.e. //...
for (let i = 0; i < url.length; i++) {
if (url[i] === '(') {
unmatchedOpenParentheses++;
} else if (url[i] === ')') {
// ...
}
}
//... That being said, this bug also occurs when a link is wrapped in curly braces i.e. What changes do you think we should make in order to solve the problem?We'll first need to create an object to count how many unmatched opening brackets of each type there are at the beginning of the We won't need the // let unmatchedOpenParentheses = 0; <- no longer necessary
const unmatchedOpeningBracketCount = {
'(': 0,
'[': 0,
'{': 0
};
const openingBracketsPattern = /[([{]/;
const closingBracketsPattern = /[)\]}]/; We'll then add some logic to deal with the two remaining types of brackets - Instead of just checking for parentheses " This is what this section in the //...
const unmatchedOpeningBracketCount = {
'(': 0,
'[': 0,
'{': 0
};
const openingBracketsPattern = /[([{]/;
const closingBracketsPattern = /[)\]}]/;
let url = match[2];
for (let i = 0; i < url.length; i++) {
if (openingBracketsPattern.test(url[i])) {
// Only 1 match is found, so we use the first and only one i.e. the opening bracket
unmatchedOpeningBracketCount[url[i].match(openingBracketsPattern)[0]]++;
} else if (closingBracketsPattern.test(url[i])) {
// Only 1 match is found, so we use the first and only one i.e. the closing bracket
const closingBracket = url[i].match(closingBracketsPattern)[0];
const matchingOpeningBracket = closingBracket === ')'
? '('
: closingBracket === ']'
? '['
: '{';
// Unmatched closing bracket
if (unmatchedOpeningBracketCount[matchingOpeningBracket] <= 0) {
const numberOfCharsToRemove = url.length - i;
match[0] = match[0].substr(0, match[0].length - numberOfCharsToRemove);
url = url.substr(0, url.length - numberOfCharsToRemove);
break;
}
unmatchedOpeningBracketCount[matchingOpeningBracket]--;
}
}
//... Short demo after changesexpensify-link-in-brackets-solution-demo.movWhat alternative solutions did you explore? (Optional)I tried extracting the // An example method
checkBracketType(unmatchedOpeningBrackets, openingBracket, closingBracket, url, match, i) {
if (url[i] === openingBracket) {
unmatchedOpeningBrackets++;
} else if (url[i] === closingBracket) {
// Unmatched closing bracket
if (unmatchedOpeningBrackets <= 0) {
const numberOfCharsToRemove = url.length - i;
match[0] = match[0].substr(0, match[0].length - numberOfCharsToRemove);
url = url.substr(0, url.length - numberOfCharsToRemove);
break; // <- can't break outside of a loop
}
unmatchedOpeningBrackets--;
}
} The main reason for these issues is the That's how I arrived at my first solution that involved repeating the let unmatchedOpenParentheses = 0; // <- Initially made 3 of these - one for each bracket type
//...
if (url[i] === '(') { // <- Switched the bracket type to [ and { in other if statements
unmatchedOpenParentheses++;
} else if (url[i] === ')') { // <- Switched the bracket type to ] and } in other if statements
// Unmatched closing parenthesis
if (unmatchedOpenParentheses <= 0) {
const numberOfCharsToRemove = url.length - i;
match[0] = match[0].substr(0, match[0].length - numberOfCharsToRemove);
url = url.substr(0, url.length - numberOfCharsToRemove);
break;
} However, this approach looked a bit messy and wasn't as DRY as I wanted it to be, so I spent some time right after posting my initial proposal looking for ways to tighten things up a bit, and that's how I arrived at my current solution. |
Hi @Victor-Nyagudi, I think const openingSymbols = ['(', '{', '['];
const closingSymbols = [')', '}', ']'];
const unmatchedSymbols = {
'(': 0,
'{': 0,
'[': 0,
};
let url = match[2];
for (let i = 0; i < url.length; i++) {
const char = url[i];
if (openingSymbols.includes(char)) {
unmatchedSymbols[char]++;
} else if (closingSymbols.includes(char)) {
const correspondingOpeningSymbol = openingSymbols[closingSymbols.indexOf(char)];
if (unmatchedSymbols[correspondingOpeningSymbol] <= 0) {
const numberOfCharsToRemove = url.length - i;
match[0] = match[0].substr(
0,
match[0].length - numberOfCharsToRemove
);
url = url.substr(0, url.length - numberOfCharsToRemove);
break;
}
unmatchedSymbols[correspondingOpeningSymbol]--;
}
} It seems it is also possible to move the complete for loop inside a function: function processUnmatchedBrackets(match) {
const openingSymbols = ['(', '{', '['];
const closingSymbols = [')', '}', ']'];
const unmatchedSymbols = {
'(': 0,
'{': 0,
'[': 0
};
let url = match[2];
for (let i = 0; i < url.length; i++) {
const char = url[i];
if (openingSymbols.includes(char)) {
unmatchedSymbols[char]++;
} else if (closingSymbols.includes(char)) {
const correspondingOpeningSymbol = openingSymbols[closingSymbols.indexOf(char)];
if (unmatchedSymbols[correspondingOpeningSymbol] <= 0) {
const numberOfCharsToRemove = url.length - i;
match[0] = match[0].substr(0, match[0].length - numberOfCharsToRemove);
url = url.substr(0, url.length - numberOfCharsToRemove);
break;
}
unmatchedSymbols[correspondingOpeningSymbol]--;
}
}
return url;
} |
Friendly bump @aimane-chnaif to review our proposals. |
Thanks. I will provide feedback by Monday |
@situchan can you please provide an update? |
@situchan bump |
reviewing proposals |
Hey @situchan what do you think of the proposals? |
@situchan can you please provide an update? Thanks! |
updating today |
Bump @situchan |
@t109ct I think your alternative solution is similar to @Victor-Nyagudi's main solution |
Thanks for your patience. I am still testing various edge cases since this will easily cause regressions |
@situchan it's not similar. I think we should keep consistency with backend |
@t109ct did the automated tests pass after applying your |
@situchan After then, all passed |
@situchan @aimane-chnaif |
If backend escapes, then fine to escape in frontend. We had similar concern in the past regarding email and landed on matching frontend with backend even if backend logic is not perfect |
@situchan |
#28608 (comment) |
Triggered auto assignment to @mountiny, see https://stackoverflow.com/c/expensify/questions/7972 for more details. |
I am actually thinking if we need to fix this honestly, given the current focus on new releases and features coming to the app this seems like very minor issue the user has easy workaround for. Additionally we work on live markdown feature which would make this even easier to spot for the user I think we can close this bug @situchan @isabelastisser |
Sounds good. Closing! |
If you haven’t already, check out our contributing guidelines for onboarding and email contributors@expensify.com to request to join our Slack channel!
Action Performed:
Expected Result:
App should not consider brackets as part of link
Actual Result:
App considers closing square bracket as part of link if link as parameter in it
Workaround:
Unknown
Platforms:
Which of our officially supported platforms is this issue occurring on?
Version Number: v1.3.75-8
Reproducible in staging?: Y
Reproducible in production?: Y
If this was caught during regression testing, add the test name, ID and link from TestRail:
Email or phone of affected tester (no customers):
Logs: https://stackoverflow.com/c/expensify/questions/4856
Notes/Photos/Videos: Any additional supporting documentation
ios.safari.square.bracket.does.not.break.link.mov
mac.chrome.desktop.square.bracket.does.not.break.the.link.mov
android.chrome.square.bracket.does.not.break.link.mp4
android.native.square.bracket.does.not.break.link.mov
windows.chrome.square.bracket.does.not.break.link.mp4
ios.native.square.bracket.breaks.the.link.mov
2023-10-02.12.48.13.mov
Expensify/Expensify Issue URL:
Issue reported by: @dhanashree-sawant
Slack conversation: https://expensify.slack.com/archives/C049HHMV9SM/p1696182736476879
View all open jobs on GitHub
Upwork Automation - Do Not Edit
The text was updated successfully, but these errors were encountered: