Created
April 19, 2022 02:14
-
-
Save ribsy/89066c6cfbd9c7a960494bf1195f412b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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