Skip to content

Htmlwidget#36

Open
gvegayon wants to merge 8 commits intomasterfrom
htmlwidget
Open

Htmlwidget#36
gvegayon wants to merge 8 commits intomasterfrom
htmlwidget

Conversation

@gvegayon
Copy link
Copy Markdown
Owner

@gvegayon gvegayon commented Jan 31, 2020

This pull request introduces a new HTML widget integration for interactive GEXF graph visualization using gexfjs, and adds supporting infrastructure to the package for both R and Shiny usage. The main changes include new functions for widget creation and rendering, registration of these functions for export, and addition of all necessary JavaScript, CSS, and configuration files for the widget.

New HTML widget and Shiny integration:

  • Added new R functions gexfjs, gexfjsOutput, and renderGexfjs to create and render an interactive GEXF graph widget, including Shiny support. Also added analogous test widget functions (test1, test1Output, renderTest1). (R/plot.R, R/plot.RR226-R301)
  • Registered the new widget functions for export in the package namespace. (NAMESPACE, NAMESPACER17-R30)
  • Added htmlwidgets as an imported package in DESCRIPTION. (DESCRIPTION, DESCRIPTIONL24-R25)

Widget implementation and dependencies:

  • Added the widget implementation JavaScript file (inst/htmlwidgets/gexfjs.js), widget configuration YAML (inst/htmlwidgets/gexfjs.yaml), and supporting setup, config, and style files. (inst/htmlwidgets/gexfjs.js, [1]; inst/htmlwidgets/gexfjs.yaml, [2]; inst/htmlwidgets/lib/gexfjs/setup.js, [3]; inst/htmlwidgets/lib/gexfjs/config.js, [4]; inst/htmlwidgets/lib/gexfjs/styles/gexfjs.css, [5]

Supporting project metadata:

@gvegayon
Copy link
Copy Markdown
Owner Author

OK, @copilot, I need you to ensure this branch is up to date with master. While you are at it, give it a pass to assess whether things are working as expected.

Copy link
Copy Markdown

Copilot AI commented Nov 24, 2025

@gvegayon I've opened a new pull request, #47, to work on those changes. Once the pull request is ready, I'll request review from you.

* Fixing bugs

* Working on release version

* Forgot to add the website

* Preparing for CRAN re-release

* Porting C functions to R

* Fixing bug on processing visual attributes and start working on issue #35

* Preparing CRAN release

* Last details before resubmitting to CRAN

* Version submitted on Feb 12, 2020

* Updating URLs

* Read GEXF file without node labels.

* Starting up paper

* Preparing to submit paper (and bumping version)

* Fixing the title

* Creating Logo

* Adjusting logo [skip ci]

* Adding statement of need and fixing DOI openjournals/joss-reviews#3369

* Update paper.md

* Adding CODE_OF_CONDUCT.md (#43)

* Working on examples and credit (#43)

* Moving files around

* Adding more examples, a head method

* Improving documentation + more examples (#43)

* Updating news

* Finalizing first review at JOSS

* Forgot to add readme figure

* Checking actions for website

* Update website.yml

* Preparing GH Actions

* Rename ci.tmp to ci.yml

* Updating vignette

* Updating README (forgot to add code of conduct properly)

* Adding website and CI badges

* Finalizing spell example

* JOSS Accepted (close #43)

* Preparing release with citation included

* Fixing links

* Adding an example with lesmiserables

* Forgot to add index

* Forcing copy

* Adding figure with gexf-js

* Finalizing CRAN release

* Adding parameters for rel scale

* Create FUNDING.yml

* Update README.md

* Update README.Rmd

* Preparing for CRAN patch

* Fixing

* Updating version number

* Adding markdown file

* Addressing CRAN comments

* Updating badges

* Removing trailing png from badges

* Initial plan

* Fix htmlwidgets dependency and namespace issues

Co-authored-by: gvegayon <893619+gvegayon@users.noreply.github.com>

---------

Co-authored-by: George G. Vega Yon <g.vegayon@gmail.com>
Co-authored-by: SamGG <samuel.granjeaud@inserm.fr>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: gvegayon <893619+gvegayon@users.noreply.github.com>
Copy link
Copy Markdown
Owner Author

@gvegayon gvegayon left a comment

Choose a reason for hiding this comment

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

@copilot, this PR has too many changes. The idea of the PR was to add the functionality to call plot() within rmarkdown, quarto, or shiny. Let's see what things that are fundamental for that funciontality can be preserved and discard the other changes.

Comment thread R/.Rhistory Outdated
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

This file needs to be removed. Also, we need to ensure this file is not added to git again

Comment thread R/plot.R
#' @details
#' Currently, the only languages supported are:
#' \Sexpr{paste(names(rgexf:::gexf_js_languages), " (", rgexf:::gexf_js_languages, ")", sep="", collapse=", ")}.
#' German (de), English (en), French (fr), Spanish (es), Italian (it),
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

What we were doing before seem smarter, why change it?

Copy link
Copy Markdown

Copilot AI commented Nov 25, 2025

@gvegayon I've opened a new pull request, #50, to work on those changes. Once the pull request is ready, I'll request review from you.

Copilot AI and others added 4 commits December 1, 2025 13:46
* Initial plan

* Fix .gitignore patterns and restore dynamic \Sexpr{} in plot.R docs

Co-authored-by: gvegayon <893619+gvegayon@users.noreply.github.com>

* Remove duplicate .Rproj.user entry from .gitignore

Co-authored-by: gvegayon <893619+gvegayon@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: gvegayon <893619+gvegayon@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown

github-actions bot commented Dec 1, 2025

Thank you for your contribution @gvegayon 🚀! The pkgdown site preview is ready for review 👉 Download here 👈!
(The artifact expires on 2026-03-01T20:51:53Z. You can re-generate it by re-running the workflow here.)

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This pull request adds HTMLwidget support to the rgexf package, enabling interactive visualization of GEXF graph files in R using the gexf-js JavaScript library. The implementation allows users to embed graph visualizations in R Markdown documents, Shiny applications, and HTML outputs.

  • Adds gexfjs() function for creating htmlwidget-based graph visualizations
  • Includes helper functions for Shiny integration (gexfjsOutput(), renderGexfjs())
  • Adds extensive gexf-js JavaScript library files and dependencies
  • Includes test/example implementations (test1() function and playground files)

Reviewed changes

Copilot reviewed 18 out of 53 changed files in this pull request and generated 13 comments.

Show a summary per file
File Description
R/plot.R Adds new htmlwidget functions: gexfjs(), test1() and their Shiny wrappers
DESCRIPTION Adds htmlwidgets package dependency
NAMESPACE Exports new htmlwidget-related functions
.gitignore Updates ignore patterns with proper wildcard syntax
inst/htmlwidgets/gexfjs.js Main JavaScript widget binding for gexf-js
inst/htmlwidgets/gexfjs.yaml Dependency configuration for the htmlwidget
inst/htmlwidgets/test1.js Test widget implementation
inst/htmlwidgets/lib/gexfjs/* Complete gexf-js library files (JS, CSS, images)
playground/*.html, *.rmd, *.cpp Example/test files for development

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

last: "Vega Yon"
};

// Looping and contatenating objects
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

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

Typo in comment: "contatenating" should be "concatenating".

Copilot uses AI. Check for mistakes.
function fillValue(id, a, b) {
var txt = document.getElementById(id).innerHTML;

var x = txt.indexOf(a)
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

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

Missing semicolon after variable declaration. While JavaScript allows this, adding it ensures consistency with the coding style used elsewhere in the file (e.g., line 11).

Copilot uses AI. Check for mistakes.
Comment thread R/plot.R
#' @import htmlwidgets
#' @export
gexfjs <- function(
gexf = "lib/gexf-1/lesmiserables.gexf" , # This is the onlyone that is working... for now
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

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

Typo in comment: "onlyone" should be "only one" (two words).

Suggested change
gexf = "lib/gexf-1/lesmiserables.gexf" , # This is the onlyone that is working... for now
gexf = "lib/gexf-1/lesmiserables.gexf" , # This is the only one that is working... for now

Copilot uses AI. Check for mistakes.
<html>
<head>
<script>
// A simple3 function to get an element ID
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

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

Typo in comment: "simple3" should be "simple".

Copilot uses AI. Check for mistakes.
Hello
</p>
<p id="id2">
Yuo
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

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

Typo in text content: "Yuo" should be "You".

Copilot uses AI. Check for mistakes.

// parse gexf data
var parser = new DOMParser();
var data = parser.parseFromString(x.data, "application/xml");
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

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

Unused variable data.

Suggested change
var data = parser.parseFromString(x.data, "application/xml");

Copilot uses AI. Check for mistakes.
Comment thread inst/htmlwidgets/test1.js

// parse gexf data
var parser = new DOMParser();
var data = parser.parseFromString(x.data, "application/xml");
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

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

Unused variable data.

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,161 @@
if (typeof jQuery == 'undefined') {
document.write(unescape("%3Cscript type='text/javascript' src='js/jquery-2.0.2.min.js'%3E%3C/script%3E"));
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

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

Avoid using functions that evaluate strings as code.

Suggested change
document.write(unescape("%3Cscript type='text/javascript' src='js/jquery-2.0.2.min.js'%3E%3C/script%3E"));
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'js/jquery-2.0.2.min.js';
document.head.appendChild(script);

Copilot uses AI. Check for mistakes.
Comment thread R/plot.R
Comment on lines +235 to +247
# read the gexf file
data <- paste(tryCatch(readLines(gexf), error = function(e) "e"), collapse="\n")

# # create a list that contains the settings
# settings <- list(
# drawEdges = drawEdges,
# drawNodes = drawNodes
# )

# pass the data and settings using 'x'
x <- list(
path = gexf,
data = data#,
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

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

readLines(gexf) will read whatever path/URL is provided and the result is placed into x$data, which is then sent to the browser via the htmlwidget. In a Shiny context, if an attacker can control gexf, they can cause the server to read arbitrary local files (e.g., /etc/passwd) and exfiltrate the contents to the client. Restrict gexf to a known safe directory (use normalizePath and a base-dir check), reject absolute/parent (..) paths, and avoid echoing raw file contents back to the client (drop x$data or send only parsed/sanitized fields). For example:

base <- system.file("gexf-graphs", package = "rgexf")
path <- normalizePath(gexf, winslash = "/", mustWork = TRUE)
stopifnot(startsWith(path, normalizePath(base, winslash = "/")))
# Prefer not to include raw file content in x$data
x <- list(path = path)
Suggested change
# read the gexf file
data <- paste(tryCatch(readLines(gexf), error = function(e) "e"), collapse="\n")
# # create a list that contains the settings
# settings <- list(
# drawEdges = drawEdges,
# drawNodes = drawNodes
# )
# pass the data and settings using 'x'
x <- list(
path = gexf,
data = data#,
# Restrict gexf to a known safe directory
base <- system.file("lib/gexf-1", package = "rgexf")
path <- normalizePath(gexf, winslash = "/", mustWork = TRUE)
if (!startsWith(path, normalizePath(base, winslash = "/"))) {
stop("gexf file must be within the package's lib/gexf-1 directory.")
}
# pass only the safe path using 'x'
x <- list(
path = path

Copilot uses AI. Check for mistakes.
Comment thread R/plot.R
width = NULL,
height = NULL
) {

Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

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

Using readLines(gexf) without validating the scheme allows remote URLs (e.g., http:// or https://) to be fetched by the server, enabling SSRF. An attacker controlling gexf in a Shiny app could force requests to internal services (e.g., http://169.254.169.254/ or http://localhost:...) and the response would be embedded in the widget. Disallow URL schemes entirely or enforce a strict allowlist (and block loopback/link-local ranges), e.g.:

if (grepl("^[a-zA-Z]+://", gexf)) stop("URLs are not allowed")
# or allowlist only file paths under a safe base dir as shown above
Suggested change
# Disallow URL schemes to prevent SSRF
if (grepl("^[a-zA-Z]+://", gexf)) stop("URLs are not allowed for 'gexf' argument")

Copilot uses AI. Check for mistakes.
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