dradis-calculator_cvss 4.18.0 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7f3df047ece82b92b97617deb1a9e964d2968c742a0c5c96f89da90c742ebfe6
4
- data.tar.gz: 77bcc61aab486daf2b7e784118428e49f53bec3c1c6d6a19d8a71776369c36c3
3
+ metadata.gz: 70e64e6d704b5d5cffd1e63cb0373fd3cffd936f181eaface3e1da7e9a67a2ff
4
+ data.tar.gz: 5bc99e966b19ccab4b3ef3496d622ea132c0b76c7b8c2eff745e080022fdedeb
5
5
  SHA512:
6
- metadata.gz: 450a7eea6d35c0f14f8f2b90ddb773c43717e68824563403a8b6225f6756f7ff5946d4b9a5db2f548a951da9a3fef6c450a4c9ed9b3fe97d5c067498c782eb06
7
- data.tar.gz: 5eb16eddaabc3998fa1bb7656a67e2d70ef3263b2d26d6c1a4f987e3a52477d914ff439afff19fa59d61556618b81c73e8b6699ba16109a7668fbed4d359d9c5
6
+ metadata.gz: 4aef8c58cba2f89a7f8398832a70aa78acfc4ebe51513ca5482d02dd9f5c198f0baa4b00b9bb935e421ff5c364e13ed13e139a46e8dc4a5890de0a6241ad2747
7
+ data.tar.gz: c330e37b118d78c141e0daeb340783cd2bc180520562f7ac88e6d766cc1c82d39cfcffe39c143aa42e438c1e390490a1e0acd4ebb07079c8ef13e117d9350565
data/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ v5.0.0 (March 2026)
2
+ - No changes
3
+
4
+ v4.20.0 (Month 2026)
5
+ - Calculator: Remove extra click to access the calculator
6
+ - CVSSv4: configure fields you care about
7
+
8
+ v4.19.0 (November 2025)
9
+ - No changes
10
+
1
11
  v4.18.0 (September 2025)
2
12
  - No changes
3
13
 
@@ -31,26 +31,54 @@ class CVSS4Calculator {
31
31
 
32
32
  class CVSS40Calculator extends CVSS4Calculator {
33
33
  constructor() {
34
- super()
34
+ super();
35
35
 
36
36
  this.app = cvss_v4_app();
37
+ this.updateFieldList();
38
+ this.bindFieldSwitches();
37
39
  this.calculate();
38
40
  }
39
41
 
42
+ updateFieldList() {
43
+ const switches = $('[data-behavior=cvss4-field-switch]');
44
+ if (switches.length) {
45
+ this.fieldList = [];
46
+ switches.filter(':checked').each((_, el) => {
47
+ this.fieldList.push($(el).data('field-name'));
48
+ });
49
+ } else {
50
+ this.fieldList = Object.keys(this.fieldMap());
51
+ }
52
+ }
53
+
54
+ bindFieldSwitches() {
55
+ $('[data-behavior=cvss4-field-switch]').on('change', () => {
56
+ this.updateFieldList();
57
+ this.setResult();
58
+ });
59
+
60
+ $('[data-behavior=form-select-all], [data-behavior=form-select-none]').on('click', () => {
61
+ this.updateFieldList();
62
+ this.setResult();
63
+ });
64
+ }
65
+
40
66
  calculate() {
41
67
  const regex = / \(.+?\)/i;
42
68
 
43
69
  $('input[type=submit]').attr('disabled', null);
44
70
 
45
71
  const that = this;
46
- $('[data-cvss-metrics] .btn-group').each(function(){
72
+ $('[data-cvss-metrics] .btn-group').each(function () {
47
73
  const selected = $(this).find('[data-cvss-option].active');
48
74
 
49
75
  if (selected.length == 1) {
50
- that.app.cvssSelected[selected.attr('name').toUpperCase()] = selected.attr('value');
76
+ that.app.cvssSelected[selected.attr('name').toUpperCase()] =
77
+ selected.attr('value');
51
78
 
52
79
  const label = selected.data('cvss-option');
53
- that.app.cvssSelectedValue[selected.attr('name').toUpperCase()] = label.replace(regex, '');
80
+ that.app.cvssSelectedValue[selected.attr('name').toUpperCase()] =
81
+ label.replace(regex, '');
54
82
  }
55
83
  });
56
84
 
@@ -63,106 +91,126 @@ class CVSS40Calculator extends CVSS4Calculator {
63
91
  let baseVector = 'CVSS:4.0';
64
92
  const that = this;
65
93
 
66
- Object.keys(expectedMetricOrder).forEach(function(metric) {
67
- if (that.app.cvssSelected[metric] && that.app.cvssSelected[metric] != 'X') {
68
- baseVector += `/${metric}:${that.app.cvssSelected[metric]}`
94
+ Object.keys(expectedMetricOrder).forEach(function (metric) {
95
+ if (
96
+ that.app.cvssSelected[metric] &&
97
+ that.app.cvssSelected[metric] != 'X'
98
+ ) {
99
+ baseVector += `/${metric}:${that.app.cvssSelected[metric]}`;
69
100
  }
70
- })
101
+ });
71
102
 
72
103
  return baseVector;
73
104
  }
74
105
 
106
+ fieldMap() {
107
+ return {
108
+ 'CVSSv4.BaseVector': () => this.baseVector(),
109
+ 'CVSSv4.BaseScore': () => this.app.score(),
110
+ 'CVSSv4.BaseSeverity': () => this.app.qualScore(),
111
+
112
+ 'CVSSv4.MacroVector': () => this.app.macroVector(),
113
+ 'CVSSv4.Exploitability': () =>
114
+ cvssMacroVectorValues[
115
+ this.app.macroVector()[cvssMacroVectorDetails['Exploitability']]
116
+ ],
117
+ 'CVSSv4.Complexity': () =>
118
+ cvssMacroVectorValues[
119
+ this.app.macroVector()[cvssMacroVectorDetails['Complexity']]
120
+ ],
121
+ 'CVSSv4.VulnerableSystem': () =>
122
+ cvssMacroVectorValues[
123
+ this.app.macroVector()[cvssMacroVectorDetails['VulnerableSystem']]
124
+ ],
125
+ 'CVSSv4.SubsequentSystem': () =>
126
+ cvssMacroVectorValues[
127
+ this.app.macroVector()[cvssMacroVectorDetails['SubsequentSystem']]
128
+ ],
129
+ 'CVSSv4.Exploitation': () =>
130
+ cvssMacroVectorValues[
131
+ this.app.macroVector()[cvssMacroVectorDetails['Exploitation']]
132
+ ],
133
+ 'CVSSv4.SecurityRequirements': () =>
134
+ cvssMacroVectorValues[
135
+ this.app.macroVector()[cvssMacroVectorDetails['SecurityRequirements']]
136
+ ],
137
+
138
+ 'CVSSv4.BaseExploitableAttackVector': () =>
139
+ this.app.cvssSelectedValue['AV'],
140
+ 'CVSSv4.BaseExploitableAttackComplexity': () =>
141
+ this.app.cvssSelectedValue['AC'],
142
+ 'CVSSv4.BaseExploitableAttackRequirements': () =>
143
+ this.app.cvssSelectedValue['AT'],
144
+ 'CVSSv4.BaseExploitablePrivilegesRequired': () =>
145
+ this.app.cvssSelectedValue['PR'],
146
+ 'CVSSv4.BaseExploitableUserInteraction': () =>
147
+ this.app.cvssSelectedValue['UI'],
148
+ 'CVSSv4.BaseVulnerableConfidentiality': () =>
149
+ this.app.cvssSelectedValue['VC'],
150
+ 'CVSSv4.BaseVulnerableIntegrity': () => this.app.cvssSelectedValue['VI'],
151
+ 'CVSSv4.BaseVulnerableAvailability': () =>
152
+ this.app.cvssSelectedValue['VA'],
153
+ 'CVSSv4.BaseSubsequentConfidentiality': () =>
154
+ this.app.cvssSelectedValue['SC'],
155
+ 'CVSSv4.BaseSubsequentIntegrity': () => this.app.cvssSelectedValue['SI'],
156
+ 'CVSSv4.BaseSubsequentAvailability': () =>
157
+ this.app.cvssSelectedValue['SA'],
158
+
159
+ 'CVSSv4.SupplementalSafety': () => this.app.cvssSelectedValue['S'],
160
+ 'CVSSv4.SupplementalAutomatable': () => this.app.cvssSelectedValue['AU'],
161
+ 'CVSSv4.SupplementalRecovery': () => this.app.cvssSelectedValue['R'],
162
+ 'CVSSv4.SupplementalValueDensity': () => this.app.cvssSelectedValue['V'],
163
+ 'CVSSv4.SupplementalVulnerabilityResponseEffort': () =>
164
+ this.app.cvssSelectedValue['RE'],
165
+ 'CVSSv4.SupplementalProviderUrgency': () =>
166
+ this.app.cvssSelectedValue['U'],
167
+ 'CVSSv4.EnvironmentalExploitabilityAttackVector': () =>
168
+ this.app.cvssSelectedValue['MAV'],
169
+ 'CVSSv4.EnvironmentalExploitabilityAttackComplexity': () =>
170
+ this.app.cvssSelectedValue['MAC'],
171
+ 'CVSSv4.EnvironmentalExploitabilityAttackRequirements': () =>
172
+ this.app.cvssSelectedValue['MAT'],
173
+ 'CVSSv4.EnvironmentalExploitabilityPrivilegesRequired': () =>
174
+ this.app.cvssSelectedValue['MPR'],
175
+ 'CVSSv4.EnvironmentalExploitabilityUserInteraction': () =>
176
+ this.app.cvssSelectedValue['MUI'],
177
+ 'CVSSv4.EnvironmentalVulnerableConfidentiality': () =>
178
+ this.app.cvssSelectedValue['MVC'],
179
+ 'CVSSv4.EnvironmentalVulnerableIntegrity': () =>
180
+ this.app.cvssSelectedValue['MVI'],
181
+ 'CVSSv4.EnvironmentalVulnerableAvailability': () =>
182
+ this.app.cvssSelectedValue['MVA'],
183
+ 'CVSSv4.EnvironmentalSubsequentConfidentiality': () =>
184
+ this.app.cvssSelectedValue['MSC'],
185
+ 'CVSSv4.EnvironmentalSubsequentIntegrity': () =>
186
+ this.app.cvssSelectedValue['MSI'],
187
+ 'CVSSv4.EnvironmentalSubsequentAvailability': () =>
188
+ this.app.cvssSelectedValue['MSA'],
189
+ 'CVSSv4.EnvironmentalConfidentialityRequirements': () =>
190
+ this.app.cvssSelectedValue['CR'],
191
+ 'CVSSv4.EnvironmentalIntegrityRequirements': () =>
192
+ this.app.cvssSelectedValue['IR'],
193
+ 'CVSSv4.EnvironmentalAvailabilityRequirements': () =>
194
+ this.app.cvssSelectedValue['AR'],
195
+ 'CVSSv4.ThreatExploitMaturity': () => this.app.cvssSelectedValue['E'],
196
+ };
197
+ }
75
198
  setResult() {
76
- let issue_cvss = ''
199
+ let issue_cvss = '';
77
200
 
78
- issue_cvss += "#[CVSSv4.BaseVector]#\n"
79
- issue_cvss += `${this.baseVector()}\n\n`
80
- issue_cvss += "#[CVSSv4.BaseScore]#\n"
81
- issue_cvss += `${this.app.score()}\n\n`
82
- issue_cvss += "#[CVSSv4.BaseSeverity]#\n"
83
- issue_cvss += `${this.app.qualScore()}\n\n`
201
+ for (const [name, getValue] of Object.entries(this.fieldMap())) {
202
+ const value = getValue();
84
203
 
85
- issue_cvss += "#[CVSSv4.MacroVector]#\n";
86
- issue_cvss += `${this.app.macroVector()}\n\n`
204
+ $(`[data-behavior=cvss4-field-value][data-field-name="${name}"]`).text(value);
87
205
 
88
- const that = this;
89
- [
90
- 'Exploitability', 'Complexity', 'VulnerableSystem', 'SubsequentSystem',
91
- 'Exploitation', 'SecurityRequirements'
92
- ].forEach(function(macroMetric) {
93
- issue_cvss += "#[CVSSv4." + macroMetric + "]#\n"
94
- issue_cvss += cvssMacroVectorValues[that.app.macroVector()[cvssMacroVectorDetails[macroMetric]]] + "\n\n"
95
- });
206
+ if (this.fieldList.includes(name)) {
207
+ issue_cvss += `#[${name}]#\n${value}\n\n`;
208
+ }
209
+ }
96
210
 
97
- issue_cvss += "#[CVSSv4.BaseExploitableAttackVector]#\n"
98
- issue_cvss += `${this.app.cvssSelectedValue['AV']}\n\n`
99
- issue_cvss += "#[CVSSv4.BaseExploitableAttackComplexity]#\n"
100
- issue_cvss += `${this.app.cvssSelectedValue['AC']}\n\n`
101
- issue_cvss += "#[CVSSv4.BaseExploitableAttackRequirements]#\n"
102
- issue_cvss += `${this.app.cvssSelectedValue['AT']}\n\n`
103
- issue_cvss += "#[CVSSv4.BaseExploitablePrivilegesRequired]#\n"
104
- issue_cvss += `${this.app.cvssSelectedValue['PR']}\n\n`
105
- issue_cvss += "#[CVSSv4.BaseExploitableUserInteraction]#\n"
106
- issue_cvss += `${this.app.cvssSelectedValue['UI']}\n\n`
107
- issue_cvss += "#[CVSSv4.BaseVulnerableConfidentiality]#\n"
108
- issue_cvss += `${this.app.cvssSelectedValue['VC']}\n\n`
109
- issue_cvss += "#[CVSSv4.BaseVulnerableIntegrity]#\n"
110
- issue_cvss += `${this.app.cvssSelectedValue['VI']}\n\n`
111
- issue_cvss += "#[CVSSv4.BaseVulnerableAvailability]#\n"
112
- issue_cvss += `${this.app.cvssSelectedValue['VA']}\n\n`
113
- issue_cvss += "#[CVSSv4.BaseSubsequentConfidentiality]#\n"
114
- issue_cvss += `${this.app.cvssSelectedValue['SC']}\n\n`
115
- issue_cvss += "#[CVSSv4.BaseSubsequentIntegrity]#\n"
116
- issue_cvss += `${this.app.cvssSelectedValue['SI']}\n\n`
117
- issue_cvss += "#[CVSSv4.BaseSubsequentAvailability]#\n"
118
- issue_cvss += `${this.app.cvssSelectedValue['SA']}\n\n`
119
-
120
- issue_cvss += "#[CVSSv4.SupplementalSafety]#\n"
121
- issue_cvss += `${this.app.cvssSelectedValue['S']}\n\n`
122
- issue_cvss += "#[CVSSv4.SupplementalAutomatable]#\n"
123
- issue_cvss += `${this.app.cvssSelectedValue['AU']}\n\n`
124
- issue_cvss += "#[CVSSv4.SupplementalRecovery]#\n"
125
- issue_cvss += `${this.app.cvssSelectedValue['R']}\n\n`
126
- issue_cvss += "#[CVSSv4.SupplementalValueDensity]#\n"
127
- issue_cvss += `${this.app.cvssSelectedValue['V']}\n\n`
128
- issue_cvss += "#[CVSSv4.SupplementalVulnerabilityResponseEffort]#\n"
129
- issue_cvss += `${this.app.cvssSelectedValue['RE']}\n\n`
130
- issue_cvss += "#[CVSSv4.SupplementalProviderUrgency]#\n"
131
- issue_cvss += `${this.app.cvssSelectedValue['U']}\n\n`
132
-
133
- issue_cvss += "#[CVSSv4.EnvironmentalExploitabilityAttackVector]#\n"
134
- issue_cvss += `${this.app.cvssSelectedValue['MAV']}\n\n`
135
- issue_cvss += "#[CVSSv4.EnvironmentalExploitabilityAttackComplexity]#\n"
136
- issue_cvss += `${this.app.cvssSelectedValue['MAC']}\n\n`
137
- issue_cvss += "#[CVSSv4.EnvironmentalExploitabilityAttackRequirements]#\n"
138
- issue_cvss += `${this.app.cvssSelectedValue['MAT']}\n\n`
139
- issue_cvss += "#[CVSSv4.EnvironmentalExploitabilityPrivilegesRequired]#\n"
140
- issue_cvss += `${this.app.cvssSelectedValue['MPR']}\n\n`
141
- issue_cvss += "#[CVSSv4.EnvironmentalExploitabilityUserInteraction]#\n"
142
- issue_cvss += `${this.app.cvssSelectedValue['MUI']}\n\n`
143
- issue_cvss += "#[CVSSv4.EnvironmentalVulnerableConfidentiality]#\n"
144
- issue_cvss += `${this.app.cvssSelectedValue['MVC']}\n\n`
145
- issue_cvss += "#[CVSSv4.EnvironmentalVulnerableIntegrity]#\n"
146
- issue_cvss += `${this.app.cvssSelectedValue['MVI']}\n\n`
147
- issue_cvss += "#[CVSSv4.EnvironmentalVulnerableAvailability]#\n"
148
- issue_cvss += `${this.app.cvssSelectedValue['MVA']}\n\n`
149
- issue_cvss += "#[CVSSv4.EnvironmentalSubsequentConfidentiality]#\n"
150
- issue_cvss += `${this.app.cvssSelectedValue['MSC']}\n\n`
151
- issue_cvss += "#[CVSSv4.EnvironmentalSubsequentIntegrity]#\n"
152
- issue_cvss += `${this.app.cvssSelectedValue['MSI']}\n\n`
153
- issue_cvss += "#[CVSSv4.EnvironmentalSubsequentAvailability]#\n"
154
- issue_cvss += `${this.app.cvssSelectedValue['MSA']}\n\n`
155
- issue_cvss += "#[CVSSv4.EnvironmentalConfidentialityRequirements]#\n"
156
- issue_cvss += `${this.app.cvssSelectedValue['CR']}\n\n`
157
- issue_cvss += "#[CVSSv4.EnvironmentalIntegrityRequirements]#\n"
158
- issue_cvss += `${this.app.cvssSelectedValue['IR']}\n\n`
159
- issue_cvss += "#[CVSSv4.EnvironmentalAvailabilityRequirements]#\n"
160
- issue_cvss += `${this.app.cvssSelectedValue['AR']}\n\n`
161
-
162
- issue_cvss += "#[CVSSv4.ThreatExploitMaturity]#\n"
163
- issue_cvss += `${this.app.cvssSelectedValue['E']}\n\n`
164
-
165
- $('[data-behavior=cvss4-result-text] textarea').val(issue_cvss)
166
- $('[data-behavior=cvss4-result]').html(this.app.score() + ' (' + this.app.qualScore() + ')')
211
+ $('[data-behavior=cvss4-result-text] textarea').val(issue_cvss);
212
+ $('[data-behavior=cvss4-result]').html(
213
+ this.app.score() + ' (' + this.app.qualScore() + ')',
214
+ );
167
215
  }
168
216
  }
@@ -3,17 +3,23 @@ module Dradis::Plugins::Calculators::CVSS
3
3
  class IssuesController < ::IssuesController
4
4
  before_action :set_cvss_version, only: :edit
5
5
  before_action :set_cvss_vector, only: :edit
6
+ before_action :set_v4_field_groups, only: :edit
6
7
 
7
8
  skip_before_action :remove_unused_state_param
8
9
 
9
10
  def edit; end
10
11
 
11
12
  def update
12
- cvss_fields = Hash[ *params[:cvss_fields].scan(FieldParser::FIELDS_REGEX).flatten.map(&:strip) ]
13
+ cvss_fields = Hash[*params[:cvss_fields].scan(FieldParser::FIELDS_REGEX).flatten.map(&:strip)]
13
14
  cvss_fields.each do |name, value|
14
15
  @issue.set_field(name, value)
15
16
  end
16
17
 
18
+ existing_v4_fields = @issue.fields.keys & V4::FIELDS
19
+ (existing_v4_fields - cvss_fields.keys).each do |name|
20
+ @issue.delete_field(name)
21
+ end
22
+
17
23
  if @issue.save
18
24
  redirect_to main_app.project_issue_path(current_project, @issue), notice: 'CVSS fields updated.'
19
25
  else
@@ -28,34 +34,53 @@ module Dradis::Plugins::Calculators::CVSS
28
34
  @cvss3_vector = Hash.new { |h, k| h[k] = 'X' }
29
35
  @cvss4_vector = Dradis::Plugins::Calculators::CVSS::V4::DEFAULT_CVSS_V4.clone
30
36
  field_value_v3 = @issue.fields['CVSSv3.Vector'] || @issue.fields['CVSSv3Vector']
31
- field_value_v4 = @issue.fields['CVSSv4.BaseVector']
37
+ field_value_v4 = @issue.fields['CVSSv4.BaseVector']
32
38
 
33
39
  # If no vector is set yet, that's OK
34
40
  return if field_value_v3.blank? && field_value_v4.blank?
35
41
 
36
42
  if field_value_v3
37
43
  if field_value_v3 =~ V3::VECTOR_REGEXP
38
- field_value_v3.split('/').each { |pair| @cvss3_vector.store *pair.split(':') }
44
+ field_value_v3.split('/').each { |pair| @cvss3_vector.store(*pair.split(':')) }
39
45
  else
40
- redirect_to main_app.project_issue_path(current_project, @issue), alert: 'The format of the CVSSv3 Vector field is invalid.'
46
+ redirect_to main_app.project_issue_path(current_project, @issue),
47
+ alert: 'The format of the CVSSv3 Vector field is invalid.'
41
48
  end
42
49
  end
43
50
 
44
- if field_value_v4
45
- if field_value_v4.starts_with?('CVSS:4.0')
46
- field_value_v4.split('/').each { |pair| @cvss4_vector.store *pair.split(':') }
47
- else
48
- redirect_to main_app.project_issue_path(current_project, @issue), alert: 'The format of the CVSSv4 Vector field is invalid.'
51
+ return unless field_value_v4
52
+
53
+ if field_value_v4.starts_with?('CVSS:4.0')
54
+ field_value_v4.split('/').each { |pair| @cvss4_vector.store(*pair.split(':')) }
55
+ else
56
+ redirect_to main_app.project_issue_path(current_project, @issue),
57
+ alert: 'The format of the CVSSv4 Vector field is invalid.'
58
+ end
59
+ end
60
+
61
+ def set_v4_field_groups
62
+ default_fields = Engine.settings.v4_fields.split(',')
63
+ existing_fields = @issue.fields.keys.select { |k| k.start_with?('CVSSv4.') }
64
+ @enabled_fields = existing_fields.any? ? existing_fields : default_fields
65
+
66
+ @v4_field_groups = V4::FIELDS.group_by do |field|
67
+ name = field.sub('CVSSv4.', '')
68
+ case name
69
+ when 'BaseVector', 'BaseScore', 'BaseSeverity' then 'Score'
70
+ when /^Base/ then 'Base Metrics'
71
+ when /^Supplemental/ then 'Supplemental'
72
+ when /^Environmental/ then 'Environmental'
73
+ when /^Threat/ then 'Threat'
74
+ else 'Macro Vector'
49
75
  end
50
76
  end
51
77
  end
52
78
 
53
79
  def set_cvss_version
54
80
  @cvss_version =
55
- case
56
- when @issue.fields['CVSSv3.Vector']&.include?('CVSS:3.1')
81
+ if @issue.fields['CVSSv3.Vector']&.include?('CVSS:3.1')
57
82
  '3.1'
58
- when @issue.fields['CVSSv3.Vector']&.include?('CVSS:3.0')
83
+ elsif @issue.fields['CVSSv3.Vector']&.include?('CVSS:3.0')
59
84
  '3.0'
60
85
  else
61
86
  '4.0'
@@ -1,5 +1,3 @@
1
- <% if defined?(Dradis::Pro) && !current_user.role?(:contributor) %>
2
- <li>
3
- <%= link_to 'Risk Calculators - CVSS', cvss_calculator.calculators_cvss_path, class: 'dropdown-item', data: { turbolinks: false } %>
4
- </li>
5
- <% end %>
1
+ <li>
2
+ <%= link_to 'Risk Calculators - CVSS', cvss_calculator.calculators_cvss_path, class: 'dropdown-item', data: { turbolinks: false } %>
3
+ </li>
@@ -1,3 +1,5 @@
1
1
  <li class="nav-item">
2
- <a href="#cvss-tab" data-bs-toggle="tab" class="nav-link"><i class="fa-solid fa-calculator"></i> CVSS</a>
2
+ <%= link_to cvss_calculator.cvss_project_issue_path(current_project, @issue), class: 'nav-link' do %>
3
+ <i class="fa-solid fa-calculator"></i> CVSS
4
+ <% end %>
3
5
  </li>
@@ -83,7 +83,7 @@ N/A
83
83
  </div>
84
84
  </div>
85
85
 
86
- <div class="form-actions">
86
+ <div class="form-actions sticky">
87
87
  <%= f.button :submit, nil, class: 'btn btn-primary' %> or
88
88
  <%= link_to 'Cancel', main_app.project_issue_path(current_project, @issue), class: 'cancel-link' %>
89
89
  </div>
@@ -1,4 +1,8 @@
1
- <div class="inner note-text-inner d-none" data-cvss-version="4">
1
+ <div
2
+ class="inner note-text-inner d-none"
3
+ data-behavior="cvss-v4-calculator"
4
+ data-cvss-version="4"
5
+ >
2
6
 
3
7
  <%= simple_form_for [:cvss, current_project, @issue] do |f| %>
4
8
 
@@ -39,63 +43,36 @@
39
43
  </div>
40
44
 
41
45
  <div class="tab-pane" id="cvss4-edit-result" data-behavior="cvss4-result-text">
42
- <textarea class="form-control" name="cvss_fields" rows="10" style="width:95%">#[CVSSv4.Vector]#
43
- N/A
46
+ <p>Toggle the fields you'd like to include in the issue content. Defaults can be set in the <%= link_to 'Configuration Manager', main_app.project_configurations_path %>.</p>
47
+ <div class="mb-2">
48
+ <a href="javascript:void(0)" data-behavior="form-select-all">Select all</a>
49
+ - <a href="javascript:void(0)" data-behavior="form-select-none">Deselect all</a>
50
+ </div>
51
+ <% @v4_field_groups.each do |group_name, fields| %>
52
+ <div class="mb-3">
53
+ <h6 class="mb-2"><%= group_name %></h6>
54
+ <% fields.each do |field| %>
55
+ <div class="form-check form-switch mb-2">
56
+ <input class="form-check-input"
57
+ type="checkbox"
58
+ role="switch"
59
+ id="cvss4-field-<%= field.parameterize %>"
60
+ data-behavior="cvss4-field-switch"
61
+ data-field-name="<%= field %>"
62
+ <%= 'checked' if @enabled_fields.include?(field) || field == 'CVSSv4.BaseVector' %>
63
+ <%= 'disabled' if field == 'CVSSv4.BaseVector' %>>
64
+ <label class="form-check-label<%= ' opacity-100' if field == 'CVSSv4.BaseVector' %>" for="cvss4-field-<%= field.parameterize %>"><%= field %></label>
65
+ <p class="small mb-0" data-behavior="cvss4-field-value" data-field-name="<%= field %>"></p>
66
+ </div>
67
+ <% end %>
68
+ </div>
69
+ <% end %>
44
70
 
45
- #[CVSSv4.BaseScore]#
46
- N/A
47
-
48
- #[CVSSv4.BaseSeverity]#
49
- N/A
50
-
51
- #[CVSSv4.MacroVector]#
52
- #[CVSSv4.Expoitability]#
53
- #[CVSSv4.Complexity]#
54
- #[CVSSv4.VulnerableSystem]#
55
- #[CVSSv4.SubsequentSystem]#
56
- #[CVSSv4.Exploitation]#
57
- #[CVSSv4.SecurityRequirements]#
58
-
59
- #[CVSSv4.BaseExploitableAttackVector]#
60
- #[CVSSv4.BaseExploitableAttackComplexity]#
61
- #[CVSSv4.BaseExploitableAttackRequirements]#
62
- #[CVSSv4.BaseExploitablePrivilegesRequired]#
63
- #[CVSSv4.BaseExploitableUserInteraction]#
64
- #[CVSSv4.BaseVulnerableConfidentiality]#
65
- #[CVSSv4.BaseVulnerableIntegrity]#
66
- #[CVSSv4.BaseVulnerableAvailability]#
67
- #[CVSSv4.BaseSubsequentConfidentiality]#
68
- #[CVSSv4.BaseSubsequentIntegrity]#
69
- #[CVSSv4.BaseSubsequentAvailability]#
70
-
71
- #[CVSSv4.SupplementalSafety]#
72
- #[CVSSv4.SupplementalAutomatable]#
73
- #[CVSSv4.SupplementalRecovery]#
74
- #[CVSSv4.SupplementalValueDensity]#
75
- #[CVSSv4.SupplementalVulnerabilityResponseEffort]#
76
- #[CVSSv4.SupplementalProviderUrgency]#
77
-
78
- #[CVSSv4.EnvironmentalExploitabilityAttackVector]#
79
- #[CVSSv4.EnvironmentalExploitabilityAttackComplexity]#
80
- #[CVSSv4.EnvironmentalExploitabilityAttackRequirements]#
81
- #[CVSSv4.EnvironmentalExploitabilityPrivilegesRequired]#
82
- #[CVSSv4.EnvironmentalExploitabilityUserInteraction]#
83
- #[CVSSv4.EnvironmentalVulnerableConfidentiality]#
84
- #[CVSSv4.EnvironmentalVulnerableIntegrity]#
85
- #[CVSSv4.EnvironmentalVulnerableAvailability]#
86
- #[CVSSv4.EnvironmentalSubsequentConfidentiality]#
87
- #[CVSSv4.EnvironmentalSubsequentIntegrity]#
88
- #[CVSSv4.EnvironmentalSubsequentAvailability]#
89
- #[CVSSv4.EnvironmentalConfidentialityRequirements]#
90
- #[CVSSv4.EnvironmentalIntegrityRequirements]#
91
- #[CVSSv4.EnvironmentalAvailabilityRequirements]#
92
-
93
- #[CVSSv4.ThreatExploitMaturity]#
94
- </textarea>
71
+ <textarea class="d-none" name="cvss_fields"></textarea>
95
72
  </div>
96
73
  </div>
97
74
 
98
- <div class="form-actions">
75
+ <div class="form-actions sticky">
99
76
  <%= f.button :submit, nil, class: 'btn btn-primary' %> or
100
77
  <%= link_to 'Cancel', main_app.project_issue_path(current_project, @issue), class: 'cancel-link' %>
101
78
  </div>
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.executables = spec.files.grep(%r{^bin/}).map { |f| File.basename(f) }
20
20
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
21
 
22
- spec.add_dependency 'dradis-plugins', '~> 4.0'
22
+ spec.add_dependency 'dradis-plugins', '>= 4.0'
23
23
 
24
24
  spec.add_development_dependency 'bundler', '~> 2.0'
25
25
  spec.add_development_dependency 'rake', '~> 10.0'
@@ -6,6 +6,10 @@ module Dradis::Plugins::Calculators::CVSS
6
6
  provides :addon
7
7
  description 'Risk Calculator: CVSS'
8
8
 
9
+ addon_settings :cvss do
10
+ settings.default_v4_fields = 'CVSSv4.BaseVector,CVSSv4.BaseScore,CVSSv4.BaseSeverity'
11
+ end
12
+
9
13
  initializer 'calculator_cvss.asset_precompile_paths' do |app|
10
14
  app.config.assets.precompile += [
11
15
  'dradis/plugins/calculators/cvss/base.css',
@@ -22,13 +26,11 @@ module Dradis::Plugins::Calculators::CVSS
22
26
  end
23
27
 
24
28
  initializer 'calculator_cvss.mount_engine' do
25
- Rails.application.reloader.to_prepare do
26
- Rails.application.routes.append do
27
- # Enabling/disabling integrations calls Rails.application.reload_routes! we need the enable
28
- # check inside the block to ensure the routes can be re-enabled without a server restart
29
- if Engine.enabled?
30
- mount Engine => '/', as: :cvss_calculator
31
- end
29
+ Rails.application.routes.append do
30
+ # Enabling/disabling integrations calls Rails.application.reload_routes! we need the enable
31
+ # check inside the block to ensure the routes can be re-enabled without a server restart
32
+ if Engine.enabled?
33
+ mount Engine => '/', as: :cvss_calculator
32
34
  end
33
35
  end
34
36
  end
@@ -8,8 +8,8 @@ module Dradis
8
8
  end
9
9
 
10
10
  module VERSION
11
- MAJOR = 4
12
- MINOR = 18
11
+ MAJOR = 5
12
+ MINOR = 0
13
13
  TINY = 0
14
14
  PRE = nil
15
15
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dradis-calculator_cvss
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.18.0
4
+ version: 5.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Martin
@@ -13,14 +13,14 @@ dependencies:
13
13
  name: dradis-plugins
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
- - - "~>"
16
+ - - ">="
17
17
  - !ruby/object:Gem::Version
18
18
  version: '4.0'
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
- - - "~>"
23
+ - - ">="
24
24
  - !ruby/object:Gem::Version
25
25
  version: '4.0'
26
26
  - !ruby/object:Gem::Dependency
@@ -88,7 +88,6 @@ files:
88
88
  - app/controllers/dradis/plugins/calculators/cvss/issues_controller.rb
89
89
  - app/models/dradis/plugins/calculators/cvss/v3.rb
90
90
  - app/models/dradis/plugins/calculators/cvss/v4.rb
91
- - app/views/dradis/plugins/calculators/cvss/_ce_tools_menu.html.erb
92
91
  - app/views/dradis/plugins/calculators/cvss/_tools_menu.html.erb
93
92
  - app/views/dradis/plugins/calculators/cvss/_version_menu.html.erb
94
93
  - app/views/dradis/plugins/calculators/cvss/base/index.html.erb
@@ -101,7 +100,6 @@ files:
101
100
  - app/views/dradis/plugins/calculators/cvss/base/v4/_index.html.erb
102
101
  - app/views/dradis/plugins/calculators/cvss/base/v4/_supplemental.html.erb
103
102
  - app/views/dradis/plugins/calculators/cvss/base/v4/_threat.html.erb
104
- - app/views/dradis/plugins/calculators/cvss/issues/_show-content.html.erb
105
103
  - app/views/dradis/plugins/calculators/cvss/issues/_show-tabs.html.erb
106
104
  - app/views/dradis/plugins/calculators/cvss/issues/edit.html.erb
107
105
  - app/views/dradis/plugins/calculators/cvss/issues/edit/_v3.html.erb
@@ -1,3 +0,0 @@
1
- <li>
2
- <%= link_to 'Risk Calculators - CVSS', cvss_calculator.calculators_cvss_path, class: 'dropdown-item', data: { turbolinks: false } %>
3
- </li>
@@ -1,34 +0,0 @@
1
- <div class="tab-pane" id="cvss-tab">
2
- <div class="inner">
3
- <h4 class="header-underline">CVSS Risk Scoring -
4
- <span class="actions">
5
- <%= link_to cvss_calculator.cvss_project_issue_path(current_project, @issue) do %>
6
- <i class="fa-solid fa-pencil"></i> Edit
7
- <% end %>
8
- </h4>
9
-
10
- <div class="mb-4 content-textile">
11
- <% if @issue.fields['CVSSv4.BaseVector'] %>
12
- <%=
13
- markup(
14
- @issue.fields
15
- .select { |k,v| Dradis::Plugins::Calculators::CVSS::V4::FIELDS.include?(k) }
16
- .map { |k,v| "#[#{k}]#\n#{v}" }.join("\n\n")
17
- )
18
- %>
19
- <% end%>
20
-
21
- <br>
22
-
23
- <% if @issue.fields['CVSSv3.Vector'] %>
24
- <%=
25
- markup(
26
- @issue.fields
27
- .select { |k,v| Dradis::Plugins::Calculators::CVSS::V3::FIELDS.include?(k) }
28
- .map { |k,v| "#[#{k}]#\n#{v}" }.join("\n\n")
29
- )
30
- %>
31
- <% end %>
32
- </div>
33
- </div>
34
- </div>