dradis-calculator_cvss 4.19.0 → 5.1.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: f4cb44d80784997ffd2cf5416fb4687d521f3bc30753e7f4a60edeb1f5be59d1
4
- data.tar.gz: 80bba699853b1b173eaafd9d069df3a96a8bb8cc23a0d0f2d117b4ea1402f4f0
3
+ metadata.gz: 6a1a2072b667c860a4b3fd935ab8fb241f6c36a0650572ded51717a2787942c7
4
+ data.tar.gz: f39277db07d072d179b1951c97d32ffc2c8f2e4ddf527156213ace741ee20fc8
5
5
  SHA512:
6
- metadata.gz: ec893d5419528c35558cfe18c5866dc4933fc0b30fbfa99d245fbbcea3f300a53a5f042df6a90cd3f35cbbb35beabd3029a1ee18ac18ce2128378aefa06f0253
7
- data.tar.gz: 7a955f2ab965190472befb591deadde143ba16b2fa024d6825b290f1582b52d0d7c67f1ac89105b60b0a83b1ba4e57fee871e94b88f3096c6affb8c565121af2
6
+ metadata.gz: 95956efbf3a2a1fe8552c7695641700ce136d9b16acbc911f8f515ca1d5b6d8b3141ca9527255c602da85027efdce716a9ad97b6c4dc46e392378de3aa3ccb9a
7
+ data.tar.gz: 89c187a8dc111632c4458d362f7c9e3e975fe2d782f00410530bfbca6c96935a79a221a2775ab28d127aab67b282f1d054715fc2eee86808e02f92249f6ceb9f
data/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ v5.1.0 (May 2026)
2
+ - No changes
3
+
4
+ v5.0.0 (March 2026)
5
+ - No changes
6
+
7
+ v4.20.0 (Month 2026)
8
+ - Calculator: Remove extra click to access the calculator
9
+ - CVSSv4: configure fields you care about
10
+
1
11
  v4.19.0 (November 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
- <% unless 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 = 19
11
+ MAJOR = 5
12
+ MINOR = 1
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.19.0
4
+ version: 5.1.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
@@ -100,7 +100,6 @@ files:
100
100
  - app/views/dradis/plugins/calculators/cvss/base/v4/_index.html.erb
101
101
  - app/views/dradis/plugins/calculators/cvss/base/v4/_supplemental.html.erb
102
102
  - app/views/dradis/plugins/calculators/cvss/base/v4/_threat.html.erb
103
- - app/views/dradis/plugins/calculators/cvss/issues/_show-content.html.erb
104
103
  - app/views/dradis/plugins/calculators/cvss/issues/_show-tabs.html.erb
105
104
  - app/views/dradis/plugins/calculators/cvss/issues/edit.html.erb
106
105
  - app/views/dradis/plugins/calculators/cvss/issues/edit/_v3.html.erb
@@ -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>