From 3adfb6ac2d5bec812f695bd208ce1138626c8540 Mon Sep 17 00:00:00 2001 From: Vanessa Fotso Date: Mon, 19 Dec 2022 19:11:06 -0500 Subject: [PATCH] Enabled upload of zip archive of multiple SRG XML files Signed-off-by: Vanessa Fotso --- ...security_requirements_guides_controller.rb | 71 ++++++++++++++----- .../SecurityRequirementsGuidesUpload.vue | 6 +- app/models/security_requirements_guide.rb | 2 +- 3 files changed, 58 insertions(+), 21 deletions(-) diff --git a/app/controllers/security_requirements_guides_controller.rb b/app/controllers/security_requirements_guides_controller.rb index 56430a80..1404c287 100644 --- a/app/controllers/security_requirements_guides_controller.rb +++ b/app/controllers/security_requirements_guides_controller.rb @@ -4,6 +4,7 @@ class SecurityRequirementsGuidesController < ApplicationController before_action :authorize_admin, except: %i[index] before_action :security_requirements_guide, only: %i[destroy] + before_action :read_uploaded_file, only: %i[create] def index @srgs = SecurityRequirementsGuide.all.order(:srg_id, :version).select(:id, :srg_id, :title, :version, :release_date) @@ -14,24 +15,25 @@ def index end def create - file = params.require('file') - parsed_benchmark = Xccdf::Benchmark.parse(file.read) - srg = SecurityRequirementsGuide.from_mapping(parsed_benchmark) - file.tempfile.seek(0) - srg.parsed_benchmark = parsed_benchmark - srg.xml = file.read - if srg.save - render(json: { toast: 'Successfully created SRG.' }, status: :ok) - else - render(json: { - toast: { - title: 'Could not create SRG.', - message: srg.errors.full_messages, - variant: 'danger' - }, - status: :unprocessable_entity - }) + if @upload_errors.empty? + srg_models = build_srg_from_xml(@upload_contents) + failed_instances = SecurityRequirementsGuide.import(srg_models, all_or_none: true, + recursive: true).failed_instances + if failed_instances.blank? + render(json: { toast: "Successfully created #{srg_models.size} SRG." }, status: :ok) and return + end + + @upload_errors = failed_instances.map { |instance| instance.errors.full_messages }.flatten end + + render(json: { + toast: { + title: 'Could not create SRG.', + message: @upload_errors, + variant: 'danger' + }, + status: :unprocessable_entity + }) end def destroy @@ -48,4 +50,39 @@ def destroy def security_requirements_guide @srg = SecurityRequirementsGuide.find(params[:id]) end + + def read_uploaded_file + file = params.require('file') + file_name = file.original_filename + @upload_contents = [] + @upload_errors = [] + + if file_name.ends_with?('.xml') + @upload_contents << file.read + elsif file_name.ends_with?('.zip') + Zip::File.open_buffer(file.read) do |zf| + if zf.all? { |f| f.name.ends_with?('.xml') } + zf.each do |entry| + entry.get_input_stream { |io| @upload_contents << io.read } + end + else + @upload_errors << 'Error reading the submitted zip file. Ensure that all files in the zip are XML files.' + end + end + else + @upload_errors << 'Wrong file type submitted: accepted file type are XML or zip archive of XML files.' + end + end + + def build_srg_from_xml(xmls) + srgs = [] + xmls.each do |xml| + parsed_benchmark = Xccdf::Benchmark.parse(xml) + srg = SecurityRequirementsGuide.from_mapping(parsed_benchmark) + srg.parsed_benchmark = parsed_benchmark + srg.xml = xml + srgs << srg + end + srgs + end end diff --git a/app/javascript/components/security_requirements_guides/SecurityRequirementsGuidesUpload.vue b/app/javascript/components/security_requirements_guides/SecurityRequirementsGuidesUpload.vue index 6aab24c5..c87c5d7c 100644 --- a/app/javascript/components/security_requirements_guides/SecurityRequirementsGuidesUpload.vue +++ b/app/javascript/components/security_requirements_guides/SecurityRequirementsGuidesUpload.vue @@ -9,9 +9,9 @@ >