Skip to content
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

Add copy-to-clipboard fallback if navigator.clipboard is not available #1336

Conversation

lacksfish
Copy link
Contributor

@lacksfish lacksfish commented Dec 6, 2023

Refactored the onClick event for the Copy To Clipboard buttons. A fallback mechanism has been introduced using the deprecated document.execCommand('copy') method to address browsers that lack support for the new navigator.clipboard API (e.g., IE and Firefox Android).

Alternatively, if the decision is not to include this fallback mechanism, it's recommended not to display the "Copy To Clipboard" buttons at all. This avoids potential issues, such as providing a non-functioning button that could unintentionally retain previously copied addresses. Note that opting for this approach would involve more extensive code changes across multiple files.

Summary by CodeRabbit

  • Bug Fixes
    • Improved clipboard operations with better error handling and fallback methods.

@saubyk
Copy link
Collaborator

saubyk commented Dec 7, 2023

Hi @lacksfish thanks for submitting these prs. We'll be reviewing it shortly.

@lacksfish
Copy link
Contributor Author

You're welcome, I'm happy to help :) Looking forward to the reviews!

@saubyk
Copy link
Collaborator

saubyk commented Jan 18, 2024

@coderabbitai review

Copy link

coderabbitai bot commented Jan 18, 2024

Walkthrough

The update refactors the clipboard interaction in the directive by removing the conditional check for the navigator.clipboard API and instead directly returning if there is no payload. The clipboard writing process is now split into two methods: one that uses the Clipboard API and another as a fallback. Error handling is streamlined to emit errors as JSON strings.

Changes

File Change Summary
.../clipboard.directive.ts Removed check for navigator.clipboard, added early return if no payload, refactored clipboard writing into two separate methods, and improved error handling.

🐇✂️📋
"In the code, we hop and snip,
A directive's change, a clever flip.
Now with a clip, and a copy so slick,
Bugs in the burrow, we fix them quick!" 🎉🐰

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share

Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit-tests for this file.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit tests for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository from git and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit tests.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger a review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • The JSON schema for the configuration file is available here.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/coderabbit-overrides.v2.json

CodeRabbit Discord Community

Join our Discord Community to get help, request features, and share feedback.

@saubyk
Copy link
Collaborator

saubyk commented Jan 18, 2024

@coderabbitai review

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Status

Actionable comments generated: 2

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between ea7f300 and c6f477e.
Files selected for processing (1)
  • src/app/shared/directive/clipboard.directive.ts (1 hunks)
Additional comments: 2
src/app/shared/directive/clipboard.directive.ts (2)
  • 17-17: The early return pattern is correctly used to avoid unnecessary nesting.
  • 19-22: The conditional check for navigator.clipboard is now correctly separated into two distinct method calls, improving readability and maintainability.

Comment on lines 26 to 42
private copyUsingFallbackMethod(): void {
const input = document.createElement('textarea');
input.innerHTML = this.payload;
document.body.appendChild(input);
input.select();

try {
const result = document.execCommand('copy');
if (result) {
this.copied.emit(this.payload.toString());
} else {
this.copied.emit('Error could not copy text.');
}
} finally {
document.body.removeChild(input);
}
}
Copy link

@coderabbitai coderabbitai bot Jan 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The copyUsingFallbackMethod method correctly implements the fallback mechanism using document.execCommand('copy'). However, the payload is set using innerHTML, which can be a security risk if the payload is not sanitized, as it may lead to XSS attacks.

- input.innerHTML = this.payload;
+ input.value = this.payload;

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
private copyUsingFallbackMethod(): void {
const input = document.createElement('textarea');
input.innerHTML = this.payload;
document.body.appendChild(input);
input.select();
try {
const result = document.execCommand('copy');
if (result) {
this.copied.emit(this.payload.toString());
} else {
this.copied.emit('Error could not copy text.');
}
} finally {
document.body.removeChild(input);
}
}
private copyUsingFallbackMethod(): void {
const input = document.createElement('textarea');
input.value = this.payload;
document.body.appendChild(input);
input.select();
try {
const result = document.execCommand('copy');
if (result) {
this.copied.emit(this.payload.toString());
} else {
this.copied.emit('Error could not copy text.');
}
} finally {
document.body.removeChild(input);
}
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, should use input.innerText or input.value

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lacksfish You're correct that using input.value is the preferred approach for setting the text content of a textarea element, as it ensures the text is treated as raw text rather than HTML, which can prevent XSS vulnerabilities. The input.innerText could be used, but input.value is more conventional and semantically correct for form inputs. Here's the updated code:

private copyUsingFallbackMethod(): void {
  const input = document.createElement('textarea');
  input.value = this.payload;
  document.body.appendChild(input);
  input.select();

  try {
    const result = document.execCommand('copy');
    if (result) {
      this.copied.emit(this.payload.toString());
    } else {
      this.copied.emit('Error could not copy text.');
    }
  } finally {
    document.body.removeChild(input);
  }
}

This change should address the security concern while maintaining the functionality of your clipboard directive.

Comment on lines +44 to +47
private copyUsingClipboardAPI(): void {
navigator.clipboard.writeText(this.payload.toString())
.then(() => this.copied.emit(this.payload.toString()))
.catch((error) => this.copied.emit('Error could not copy text: ' + JSON.stringify(error)));
Copy link

@coderabbitai coderabbitai bot Jan 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tip

Codebase Verification

The context provided around the assignment input.innerHTML = this.payload; does not include any code that indicates sanitization of the payload. The payload is directly assigned to the innerHTML of a newly created textarea element, which is then used for the fallback copy method. This could potentially introduce security risks if the payload contains untrusted user input that is not properly sanitized.

Based on the information gathered, there is no evidence in the provided context to suggest that the payload is sanitized before being used in the copyUsingClipboardAPI method or in the fallback method.

Therefore, the review comment regarding the need to ensure that the payload is sanitized before being copied to the clipboard is valid and should be addressed to prevent potential security issues.

Analysis chain

The copyUsingClipboardAPI method is well-implemented with proper promise handling for success and error cases. Ensure that the payload is sanitized before being copied to the clipboard to prevent potential security issues.

Scripts Executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Verify that the payload is sanitized before being passed to this method.
ast-grep --lang typescript --pattern $'this.copyUsingClipboardAPI($_)'

Length of output: 71



Script:

#!/bin/bash
# Search for the invocation of 'copyUsingClipboardAPI' method and check for payload sanitization
rg "this.copyUsingClipboardAPI\(" --type ts

Length of output: 129



Script:

#!/bin/bash
# Search for assignments or modifications to 'this.payload' to check for sanitization before it's used in 'copyUsingClipboardAPI'
rg "this.payload" --type ts

Length of output: 505



Script:

#!/bin/bash
# Examine the context around the assignment to 'input.innerHTML' to check for payload sanitization
rg -C 5 "input.innerHTML = this.payload" --type ts

Length of output: 845

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm open to suggestions for sanitization. I haven't looked at all places in the menus where copy is being used, for me the issue scope was not having copied invoices I created.

In the fallback, since there's gonna be a temp textarea element's content in the DOM it's important (as suggested above) to use input.innerText or input.value. I've opted for innerText and pushed the 1-line change.

Again, maybe a more simple alternative would be to not display the "copy" button when navigator.clipboard is not available.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lacksfish, using input.innerText instead of input.innerHTML is a good move to mitigate the risk of script injection, as it treats the content as text rather than HTML. Regarding the alternative to hide the "Copy" button when navigator.clipboard is not available, it could simplify the implementation and reduce the need for a fallback, but it would also remove functionality for users on older browsers. It's a trade-off between functionality and maintainability that should be carefully considered based on your user base and their needs.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Status

Actionable comments generated: 0

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between c6f477e and d9f9431.
Files selected for processing (1)
  • src/app/shared/directive/clipboard.directive.ts (1 hunks)
Additional comments: 3
src/app/shared/directive/clipboard.directive.ts (3)
  • 17-22: The refactoring of the onClick event handler correctly separates the concerns of checking for the payload and determining which clipboard method to use. However, ensure that the copyUsingFallbackMethod is only called when navigator.clipboard is not available.
  • 26-41: The copyUsingFallbackMethod uses innerText instead of innerHTML, which is a safer choice to prevent XSS attacks. However, ensure that the payload is sanitized before being set to prevent any potential security risks.
  • 44-47: The copyUsingClipboardAPI method is implemented with proper promise handling for success and error cases. Ensure that the payload is sanitized before being copied to the clipboard to prevent potential security issues.

@ShahanaFarooqui ShahanaFarooqui added this to the Release 0.15.1-beta milestone Jan 22, 2024
@ShahanaFarooqui ShahanaFarooqui changed the base branch from master to Release-0.15.1 January 22, 2024 21:26
@ShahanaFarooqui ShahanaFarooqui force-pushed the Release-0.15.1 branch 3 times, most recently from 8f8178a to c2c9e74 Compare January 22, 2024 21:32
Copy link
Collaborator

@ShahanaFarooqui ShahanaFarooqui left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes look good but need some lint fixes. Also need to push compiled code.

I do not have write access to the fork, so I will do that in the next commit.

@lacksfish Thank you for the PR.

@ShahanaFarooqui ShahanaFarooqui merged commit 1fcb5bb into Ride-The-Lightning:Release-0.15.1 Jan 22, 2024
ShahanaFarooqui pushed a commit that referenced this pull request Jan 22, 2024
#1336)

* add copy-to-clipboard fallback if navigator.clipboard is not available

* amend copy fallback
ShahanaFarooqui added a commit that referenced this pull request Jun 10, 2024
* rm .DS_Store

* Add watchfrontenddev command for npm

* Fix toggle issues in sidenav (pinning and on page refresh)

* Add copy-to-clipboard fallback if navigator.clipboard is not available (#1336)

* add copy-to-clipboard fallback if navigator.clipboard is not available

* amend copy fallback

* clipboard copy lint fixes and frontend build

* fix: add missing boltz state `transaction.lockupFailed` (#1349)

* fix: boltzd docs link (#1354)

* exit gracefully (#1356)

* allow for eclair updated relayed audit format (#1363)

* feat: add boltz service to cln (#1352)

* lint fix

* Request Params Cleanup

* cln: Boltz auto-send (#1366)

* Bug-fix (CLN Boltz): Hide claim tx id and routing fee for non-zero conf reverse swap

* cln: Boltz auto-send

- Added auto send option for Swap In
- Checking compatiblity with v2.0.0 and above

* Test import fixes

* Update help.component.ts (#1379)

Fixed broken link under "Help" -> "Node Settings"

* Backend config fix (#1382)

* Updating Common Application Configuration

* Fixed get RTL Conf

* Update Application Settings

* application and settings case change

* Unified config models

* Default node update

* 2FA and Password reset

* Final application settings update

* Config Settings and Authentication case fixed

* Node Setting Fix

* Fiat currency Symbol fix

* CLN: Fiat symbol fix

* All: Fiat symbol fix

* Update node settings

* Services UI fix

* CLN: Removed child node settings

* All: Removed child node settings

* Test fixes

* mempool links for onchain information (#1383)

* Tests fix

Tests fix

* UI for Block Explorer Configuration (#1385)

* Bump fee with mempool information (#1386)

* Mempool openchannel minfee (#1388)

Open channel model block if min fee is higher

* Show error on login screen if rune is incorrect and getinfo throws error (#1391)

* cln: Removed channel lookup call for update policy (#1392)

* ECL: On-chain Transactions, Invoice and Payments pagination (#1393)

Done most of the UI changes to accommodate pagination on transactions, payments and invoices tables but true pagination cannot be implemented till total number of records are missing from the API response.

Once the issue ACINQ/eclair#2855 is fixed, I will uncomment pagination changes in the frontend.

* lnd: Onchain CPFP (#1394)

- UTXO label bug fix
- Warning on utxo label for "sweep" in text.

* Bug fixes after testing

* Testing bug fixes (#1401)

* Bug fix 2: lnd: Link channel point to explorer and show fee on close channel too

* lnd: explorer link on pending channels

* Node lookup link on view channel peer pubkey

* Testing bug fixes (#1402)

* Bug fix 2: lnd: Link channel point to explorer and show fee on close channel too

* lnd: explorer link on pending channels

* Node lookup link on view channel peer pubkey

* test fixes

* ng update to v18.0.x

* Updating install with  --legacy-peer-deps

---------

Co-authored-by: Grzegorz Kućmierz <[email protected]>
Co-authored-by: lacksfish <[email protected]>
Co-authored-by: jackstar12 <[email protected]>
Co-authored-by: Kilian <[email protected]>
Co-authored-by: Taylor King <[email protected]>
Co-authored-by: Fishcake <[email protected]>
Co-authored-by: Ant <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants