Skip to content

fix: Convert AI pdf into bytes and send the data url to Webview#956

Open
kaaviya98 wants to merge 2 commits intomasterfrom
bytes
Open

fix: Convert AI pdf into bytes and send the data url to Webview#956
kaaviya98 wants to merge 2 commits intomasterfrom
bytes

Conversation

@kaaviya98
Copy link
Contributor

Changes done

Reason for the changes

Fixes # .

@gemini-code-assist
Copy link

Summary of Changes

Hello @kaaviya98, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enhances the AI chat functionality by enabling the secure loading of locally cached PDF files into a WebView. It achieves this by converting the PDF content into a Base64 data URL, which is then exposed to the WebView via a JavaScript interface. This approach ensures that PDF content is loaded directly from memory, improving security and compatibility within the WebView environment for AI-driven interactions.

Highlights

  • PDF to Base64 Conversion: Introduced a new utility class, CachedPdfPathProvider, to convert locally cached PDF files into Base64 encoded strings and provide them as data URLs.
  • WebView Integration: Modified AIChatPdfFragment to inject CachedPdfPathProvider as a JavaScript interface into the WebView, allowing the WebView to access the Base64 PDF data directly.
  • PDF Path Provisioning: Updated DocumentViewerFragment to pass the cached PDF file path to AIChatPdfFragment's arguments, ensuring the correct PDF is processed.
  • Cached PDF Path Retrieval: Added a getCachedPdfPath() method to PDFDownloadManager to easily retrieve the absolute path of a downloaded PDF.
  • Sample Environment Update: Changed the default InstituteSettings base URL in TestpressCoreSampleActivity.java from sandbox.testpress.in to staging.testpress.in.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist
Copy link

Summary of Changes

Hello @kaaviya98, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enhances the application's ability to display locally cached PDF documents within a WebView. It achieves this by converting the PDF into a Base64 data URL, which can then be directly rendered by the WebView. The changes involve creating a dedicated utility for PDF data handling, integrating this utility with the AI chat PDF display fragment, and ensuring the necessary PDF file path is correctly propagated through the application's fragments.

Highlights

  • PDF to Base64 Conversion: Introduced a new utility class, CachedPdfPathProvider, to convert locally cached PDF files into Base64 encoded strings and generate data URLs for WebView consumption.
  • WebView Integration: The AIChatPdfFragment now initializes a JavaScript interface with the CachedPdfPathProvider to expose PDF data to the WebView, enabling the WebView to load the PDF directly from a data URL.
  • Fragment Communication: The DocumentViewerFragment has been updated to pass the path of the cached PDF to the AIChatPdfFragment via arguments, ensuring the correct PDF is loaded.
  • PDF Path Retrieval: A new method getCachedPdfPath() was added to PDFDownloadManager to easily retrieve the absolute path of a downloaded and decrypted PDF.
  • Sample Configuration Update: The sample application's InstituteSettings URLs were updated from sandbox.testpress.in to staging.testpress.in.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a feature to send a cached PDF to a WebView for an AI chat interface. The changes involve creating a Javascript interface to provide the PDF data as a Base64-encoded data URL. My review focuses on improving security, performance, and resource management. I've identified a potential resource leak, unnecessary and insecure WebView settings, and an inefficient decryption process. Please see the detailed comments for suggestions.

Comment on lines +73 to +76
webViewFragment.webView.settings.apply {
allowFileAccessFromFileURLs = true
allowUniversalAccessFromFileURLs = true
}

Choose a reason for hiding this comment

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

high

These WebView settings (allowFileAccessFromFileURLs and allowUniversalAccessFromFileURLs) pose a security risk and appear to be unnecessary for the current implementation. Since you are passing the PDF content as a Base64-encoded data URL, the WebView doesn't need to access the file system directly. Enabling these settings could expose the app to security vulnerabilities if the WebView were to load any untrusted content. It's recommended to remove these lines.

Comment on lines +22 to +34
return if (isPDFCached()) {
try {
val file = File(pdfPath)
val inputStream = FileInputStream(file)
val bytes = inputStream.readBytes()
inputStream.close()
Base64.encodeToString(bytes, Base64.DEFAULT)
} catch (e: Exception) {
""
}
} else {
""
}

Choose a reason for hiding this comment

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

high

There's a potential resource leak here. The FileInputStream is not guaranteed to be closed if an exception occurs while reading the bytes. It's better to use the use extension function, which automatically closes the stream. Also, catching a generic Exception is too broad and can hide other issues; it's better to catch specific exceptions like IOException. You can also make the code more concise by using the readBytes() extension function directly on the File object.

        return if (isPDFCached()) {
            try {
                val bytes = File(pdfPath).readBytes()
                Base64.encodeToString(bytes, Base64.DEFAULT)
            } catch (e: java.io.IOException) {
                e.printStackTrace() // Consider using a proper logger for debugging.
                ""
            }
        } else {
            ""
        }

Comment on lines +77 to +79
fun getCachedPdfPath(): String {
return if (isDownloaded()) get().absolutePath else ""
}

Choose a reason for hiding this comment

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

medium

The getCachedPdfPath function calls get(), which in turn calls fileEncryptAndDecryptUtil.decrypt(). This decryption process seems to be executed every time getCachedPdfPath is called, which can be inefficient, especially for large PDF files. This could lead to a noticeable delay when the user tries to access the AI chat feature. Consider caching the decrypted file or its path within PDFDownloadManager to avoid re-decrypting the file on every access. The cached value can be cleared in the cleanup() method.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a mechanism to send a cached PDF file to a WebView as a data URL. The implementation involves creating a new CachedPdfPathProvider class with a JavaScript interface to read the PDF file, encode it to Base64, and construct a data URL. My review focuses on improving security and resource management. I've pointed out unnecessary and insecure WebView settings that should be removed. Additionally, I've suggested a fix for a potential resource leak in the file reading logic and recommended better error handling.

Comment on lines +73 to +76
webViewFragment.webView.settings.apply {
allowFileAccessFromFileURLs = true
allowUniversalAccessFromFileURLs = true
}

Choose a reason for hiding this comment

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

high

These WebView settings (allowFileAccessFromFileURLs and allowUniversalAccessFromFileURLs) are deprecated and introduce a significant security risk. They allow JavaScript running in a file scheme URL to access content from any origin. Since the PDF data is being provided through a JavaScript interface which handles file access natively, these broad permissions for the WebView are not necessary and should be removed to avoid potential security vulnerabilities.

Comment on lines +23 to +31
try {
val file = File(pdfPath)
val inputStream = FileInputStream(file)
val bytes = inputStream.readBytes()
inputStream.close()
Base64.encodeToString(bytes, Base64.DEFAULT)
} catch (e: Exception) {
""
}

Choose a reason for hiding this comment

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

high

The FileInputStream is not guaranteed to be closed if an exception occurs during readBytes(), which can lead to a resource leak. It's safer to use a use block, which ensures the stream is closed automatically. Additionally, catching a generic Exception and returning an empty string without logging makes debugging difficult. It's better to catch a more specific exception and log the error.

Suggested change
try {
val file = File(pdfPath)
val inputStream = FileInputStream(file)
val bytes = inputStream.readBytes()
inputStream.close()
Base64.encodeToString(bytes, Base64.DEFAULT)
} catch (e: Exception) {
""
}
try {
File(pdfPath).inputStream().use { inputStream ->
val bytes = inputStream.readBytes()
Base64.encodeToString(bytes, Base64.DEFAULT)
}
} catch (e: java.io.IOException) {
// Consider logging the exception for debugging purposes.
""
}

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.

1 participant