Skip to content

Instantly share code, notes, and snippets.

@ribsy
Created April 19, 2022 02:14
Show Gist options
  • Save ribsy/89066c6cfbd9c7a960494bf1195f412b to your computer and use it in GitHub Desktop.
Save ribsy/89066c6cfbd9c7a960494bf1195f412b to your computer and use it in GitHub Desktop.
source("helper_functions.R")
#30MB File Upload
options(shiny.maxRequestSize = 30*1024^2)
ui <- dashboardPage(
title="Vuln Burndown",
dashboardHeader(title = "Vulnerability Burndown"),
dashboardSidebar(
#useShinyalert(),
#CSS Settings For Scrolling and Button Colors
tags$head(tags$style(HTML('#search{background-color:black;color:white}'))),
tags$head(tags$style(HTML('#kpi_update{background-color:grey;color:white}'))),
#File Input
fileInput("file", "Upload Vuln CSV",accept = c(".csv")),
dateRangeInput("reportrange", "Report Range:"),
#Create Custom Buttons For Date Range
GetSearchButton(),
GetResetButton(),
selectInput("mode", "Analysis Mode:",c("Default Mode" = "rate", "KPI Mode" = "kpi", "Mixed Mode" = "mixed"), selected = "rate"),
sliderInput("crit_kpi", "Set Critical KPI Goal:",1,100,.95),
sliderInput("sev_kpi", "Set Severe KPI Goal:", 1, 100, .95),
sliderInput("mod_kpi", "Set Moderate KPI Goal:", 1, 100, .95)
),
dashboardBody(
fluidRow(
verbatimTextOutput("text"),
infoBoxOutput("criticalBurnBox"),
infoBoxOutput("severeBurnBox"),
infoBoxOutput("moderateBurnBox")
),
fluidRow(
infoBoxOutput("criticalCountBox"),
infoBoxOutput("severeCountBox"),
infoBoxOutput("moderateCountBox")
),
fluidRow(
infoBoxOutput("criticalTTLBox"),
infoBoxOutput("severeTTLBox"),
infoBoxOutput("moderateTTLBox")
),
fluidRow(
tabBox(
title = "Vulnerability Search And Forecasting", width = 12,
tabPanel("Survival Analysis", plotOutput("hazard_plot")),
tabPanel("Search Open Vulns", reactableOutput("open_vulns")),
tabPanel("Search Closed Vulns", reactableOutput("closed_vulns"))
)
)
)
)
server <- function(input, output, session) {
data_vals <- reactiveValues(data = NULL, vuln_data = NULL, count_data = NULL)
#If a data range is requested we need to update
observeEvent(
input$search, {
#Fetch Data from global data() based on date inputs
data_vals$vuln_data <- UpdateVulnData(data_vals$data, input$reportrange[1], input$reportrange[2])
data_vals$count_data = GetVulnVariables(data_vals$vuln_data)
crit_kpi <- reactive(GetBestKPI(data_vals$vuln_data, "Critical"))
sev_kpi <- reactive(GetBestKPI(data_vals$vuln_data, "Severe"))
mod_kpi <- reactive(GetBestKPI(data_vals$vuln_data, "Moderate"))
#Update Sliders
updateSliderInput(session, "crit_kpi", value = crit_kpi() * 100)
updateSliderInput(session, "sev_kpi", value = sev_kpi() * 100)
updateSliderInput(session, "mod_kpi", value = mod_kpi() * 100)
}, ignoreInit = TRUE
)
observeEvent(
input$reset, {
#Reset Data To Orginal And Make Vars To Pass To Sliders
data_vals$vuln_data <- GetUpdatedVulnData(data_vals$data)
data_vals$count_data = GetVulnVariables(data_vals$vuln_data)
crit_kpi <- reactive(GetBestKPI(data_vals$vuln_data, "Critical"))
sev_kpi <- reactive(GetBestKPI(data_vals$vuln_data, "Severe"))
mod_kpi <- reactive(GetBestKPI(data_vals$vuln_data, "Moderate"))
#Update KPI Sliders
updateSliderInput(session, "crit_kpi", value = crit_kpi() * 100)
updateSliderInput(session, "sev_kpi", value = sev_kpi() * 100)
updateSliderInput(session, "mod_kpi", value = mod_kpi() * 100)
#Get Orginal Date Range Update Calender
min_date <- min(mdy(data_vals$data$discovered_date))
max_date <- max(mdy(data_vals$data$last_scan_date))
updateDateRangeInput(session, "reportrange",start = min_date, end = max_date)
}, ignoreInit = TRUE
)
observeEvent(c(input$crit_kpi,input$mode),{
crit_kpi <- as.numeric(input$crit_kpi/100)
mode <- input$mode
output$criticalBurnBox <- renderInfoBox({ GetBurndownBox("Critical", isolate(data_vals$vuln_data), crit_kpi, mode)})
}, ignoreInit = TRUE)
observeEvent(c(input$sev_kpi,input$mode),{
sev_kpi <- as.numeric(input$sev_kpi/100)
mode <- input$mode
output$severeBurnBox <- renderInfoBox({ GetBurndownBox("Severe", isolate(data_vals$vuln_data), sev_kpi, mode) })
}, ignoreInit = TRUE)
observeEvent(c(input$mod_kpi, input$mode),{
mod_kpi <- as.numeric(input$mod_kpi/100)
mode <- input$mode
output$moderateBurnBox <- renderInfoBox({ GetBurndownBox("Moderate", isolate(data_vals$vuln_data), mod_kpi, mode) })
}, ignoreInit = TRUE)
observeEvent(input$file,{
#Set Reactive Values - See Top Of Server Function.
data_vals$data = GetFileData(input$file) # Cache for Reset
if( is.data.frame(data_vals$data) == FALSE ){
output$text <- renderText({data_vals$data})
return()
}
data_vals$vuln_data = data_vals$data
data_vals$count_data = GetVulnVariables(data_vals$vuln_data)
#Get Slider Data
crit_kpi_rate <- GetBestKPI(data_vals$vuln_data, "Critical") * 100
sev_kpi_rate <- GetBestKPI(data_vals$vuln_data, "Severe") * 100
mod_kpi_rate <- GetBestKPI(data_vals$vuln_data, "Moderate") * 100
#Update Sliders With Best KPI - These Fire Off And Create Burndown Boxes Above
updateSliderInput(session, "crit_kpi", value = crit_kpi_rate)
updateSliderInput(session, "sev_kpi", value = sev_kpi_rate)
updateSliderInput(session, "mod_kpi", value = mod_kpi_rate)
#Get Calendear Data and Update Cal
cal_start <- min(mdy(data_vals$vuln_data$discovered_date))
cal_end <- max(mdy(data_vals$vuln_data$last_scan_date))
updateDateRangeInput(session, "reportrange",start = cal_start, end = cal_end)
#Count Boxes
output$criticalCountBox <- renderInfoBox({ GetCountBox("Critical", data_vals$count_data$critical) })
output$severeCountBox <- renderInfoBox({ GetCountBox("Severe", data_vals$count_data$severe)})
output$moderateCountBox <- renderInfoBox({ GetCountBox("Moderate",data_vals$count_data$moderate) })
#TTL Boxes
output$criticalTTLBox <- renderInfoBox({ GetTTLBox("Critical", data_vals$vuln_data) })
output$severeTTLBox <- renderInfoBox({ GetTTLBox("Severe", data_vals$vuln_data) })
output$moderateTTLBox <- renderInfoBox({ GetTTLBox("Moderate", data_vals$vuln_data) })
#Survival Plot
output$hazard_plot <- renderPlot({GetSurvPlot(data_vals$vuln_data)})
#Not Remediated Search
output$open_vulns <- renderReactable({
reactable(GetVulnTable(data_vals$vuln_data,"NOT_REMEDIATED"),
groupBy = c("severity", "title"),
filterable = TRUE,
minRows = 10,
searchable = TRUE,
resizable = TRUE,
striped = TRUE,
highlight = TRUE)
})
#Remediated Search
output$closed_vulns <- renderReactable({
reactable(GetVulnTable(data_vals$vuln_data,"REMEDIATED"),
groupBy = c("severity", "title"),
filterable = TRUE,
minRows = 10,
searchable = TRUE,
resizable = TRUE,
striped = TRUE,
highlight = TRUE)
})
})# End observe event
}
shinyApp(ui, server)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment