openc3 6.5.1 → 6.6.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: 99470dde632de3fe5fd6db9eaf4d529b117ac3d7ff8bcdb77fec5e7451c20b77
4
- data.tar.gz: e8bfd360f210fef3a41c14605b561f9b6072b07b01dec9e2479069594fc67502
3
+ metadata.gz: d08bcc3b92811101e2096aa443b5459835d0396aba80b1067c8147388ec050e6
4
+ data.tar.gz: 2820795b23e3da0530d0306ee2665d69bb5ad86f494609ced199f985929c56f2
5
5
  SHA512:
6
- metadata.gz: 63177085f3628d368fe69a17a15bdbbb2d46fcf6b9eccc45cf32744cf4ff709925480176cc140026a55f0593c343f7a62ae435c858532a2a5c9e3d1d4d8cdfeb
7
- data.tar.gz: 3f55acbf143f0d8307d47533998cbc63144935226e6c0b774537321c2fe62b81a19949e3169ca4a53a1032b3132e13a23fabf5707625d9c7c24e273caa7f26b3
6
+ metadata.gz: 181ce42f3c55f78ee8e6adf3cc7145326974c8239a82478b501def91314169cacb62a9e53c4d0d760e0b0125a1b77e437127f7992d7e4fe42838035640b87dbe
7
+ data.tar.gz: 957334977c15e7d8e3fe49d14bec6c2e11c7cba09bbaea70cefe3f85a408255f1e7f2620b642c6f7a137d6ff9bdc1b4b49007fca58a9c6c5f9562b81daa0263e
@@ -76,3 +76,6 @@ VARIABLE_BIT_SIZE:
76
76
  required: false
77
77
  description: Offset in Bits to Apply to Length Field Value. Defaults to 0
78
78
  values: \d+
79
+ OBFUSCATE:
80
+ summary: Hides the item value in the UI, text logs, and raw binary file
81
+ since: 6.6.0
@@ -30,9 +30,11 @@ require 'openc3/topics/command_decom_topic'
30
30
  require 'openc3/topics/decom_interface_topic'
31
31
  require 'openc3/topics/interface_topic'
32
32
  require 'openc3/script/extract'
33
+ require 'openc3/utilities/cmd_log'
33
34
 
34
35
  module OpenC3
35
36
  module Api
37
+ include OpenC3::CmdLog
36
38
  WHITELIST ||= []
37
39
  WHITELIST.concat([
38
40
  'cmd',
@@ -500,6 +502,7 @@ module OpenC3
500
502
  # end
501
503
  # end
502
504
  end
505
+
503
506
  packet = TargetModel.packet(target_name, cmd_name, type: :CMD, scope: scope)
504
507
  if packet['disabled']
505
508
  error = DisabledError.new
@@ -507,7 +510,6 @@ module OpenC3
507
510
  error.cmd_name = cmd_name
508
511
  raise error
509
512
  end
510
-
511
513
  if log_message.nil? # This means the default was used, no argument was passed
512
514
  log_message = true # Default is true
513
515
  # If the packet has the DISABLE_MESSAGES keyword then no messages by default
@@ -520,7 +522,6 @@ module OpenC3
520
522
  end
521
523
  end
522
524
  end
523
-
524
525
  cmd_string = _build_cmd_output_string(method_name, target_name, cmd_name, cmd_params, packet)
525
526
  username = user && user['username'] ? user['username'] : 'anonymous'
526
527
  command = {
@@ -535,52 +536,11 @@ module OpenC3
535
536
  'validate' => validate.to_s,
536
537
  'manual' => manual.to_s,
537
538
  'log_message' => log_message.to_s,
539
+ 'obfuscated_items' => packet['obfuscated_items'].to_s
538
540
  }
539
541
  CommandTopic.send_command(command, timeout: timeout, scope: scope)
542
+ return command
540
543
  end
541
544
 
542
- def _build_cmd_output_string(method_name, target_name, cmd_name, cmd_params, packet)
543
- output_string = "#{method_name}(\""
544
- output_string << (target_name + ' ' + cmd_name)
545
- if cmd_params.nil? or cmd_params.empty?
546
- output_string << '")'
547
- else
548
- params = []
549
- cmd_params.each do |key, value|
550
- next if Packet::RESERVED_ITEM_NAMES.include?(key)
551
-
552
- item = packet['items'].find { |find_item| find_item['name'] == key.to_s }
553
-
554
- begin
555
- item_type = item['data_type'].intern
556
- rescue
557
- item_type = nil
558
- end
559
-
560
- if value.is_a?(String)
561
- value = value.dup
562
- if item_type == :BLOCK or item_type == :STRING
563
- if !value.is_printable?
564
- value = "0x" + value.simple_formatted
565
- else
566
- value = value.inspect
567
- end
568
- else
569
- value = value.convert_to_value.to_s
570
- end
571
- if value.length > 256
572
- value = value[0..255] + "...'"
573
- end
574
- value.tr!('"', "'")
575
- elsif value.is_a?(Array)
576
- value = "[#{value.join(", ")}]"
577
- end
578
- params << "#{key} #{value}"
579
- end
580
- params = params.join(", ")
581
- output_string << (' with ' + params + '")')
582
- end
583
- return output_string
584
- end
585
545
  end
586
546
  end
@@ -297,6 +297,8 @@ module OpenC3
297
297
 
298
298
  @interface.write(command)
299
299
 
300
+ command.obfuscate
301
+
300
302
  if command.validator and validate
301
303
  begin
302
304
  result, reason = command.validator.post_check(command)
@@ -24,6 +24,7 @@
24
24
  # See https://github.com/OpenC3/cosmos/pull/1963
25
25
 
26
26
  require 'openc3/packets/packet_config'
27
+ require 'openc3/utilities/cmd_log'
27
28
 
28
29
  module OpenC3
29
30
  # Commands uses PacketConfig to parse the command and telemetry
@@ -37,6 +38,7 @@ module OpenC3
37
38
  # Packet or PacketItem objects. While there are some overlapping methods between
38
39
  # the two, these are separate interfaces into the system.
39
40
  class Commands
41
+ include OpenC3::CmdLog
40
42
  attr_accessor :config
41
43
 
42
44
  LATEST_PACKET_NAME = 'LATEST'.freeze
@@ -203,60 +205,16 @@ module OpenC3
203
205
  raw = false
204
206
  end
205
207
  items.delete_if { |item_name, _item_value| ignored_parameters.include?(item_name) }
206
- return build_cmd_output_string(packet.target_name, packet.packet_name, items, raw)
208
+ return build_cmd_output_string(packet.target_name, packet.packet_name, items, raw, packet)
207
209
  end
208
210
 
209
- def build_cmd_output_string(target_name, cmd_name, cmd_params, raw = false)
210
- if raw
211
- output_string = 'cmd_raw("'
212
- else
213
- output_string = 'cmd("'
214
- end
211
+ def build_cmd_output_string(target_name, cmd_name, cmd_params, raw = false, packet)
212
+ method_name = raw ? "cmd_raw" : "cmd"
215
213
  target_name = 'UNKNOWN' unless target_name
216
214
  cmd_name = 'UNKNOWN' unless cmd_name
217
- output_string << (target_name + ' ' + cmd_name)
218
- if cmd_params.nil? or cmd_params.empty?
219
- output_string << '")'
220
- else
221
- begin
222
- command_items = packet(target_name, cmd_name).items
223
- rescue
224
- end
225
-
226
- params = []
227
- cmd_params.each do |key, value|
228
- next if Packet::RESERVED_ITEM_NAMES.include?(key)
229
-
230
- begin
231
- item_type = command_items[key].data_type
232
- rescue
233
- item_type = nil
234
- end
215
+ packet_hash = packet ? packet.as_json : {}
235
216
 
236
- if value.is_a?(String)
237
- value = value.dup
238
- if item_type == :BLOCK or item_type == :STRING
239
- if !value.is_printable?
240
- value = "0x" + value.simple_formatted
241
- else
242
- value = value.inspect
243
- end
244
- else
245
- value = value.convert_to_value.to_s
246
- end
247
- if value.length > 256
248
- value = value[0..255] + "...'"
249
- end
250
- value.tr!('"', "'")
251
- elsif value.is_a?(Array)
252
- value = "[#{value.join(", ")}]"
253
- end
254
- params << "#{key} #{value}"
255
- end
256
- params = params.join(", ")
257
- output_string << (' with ' + params + '")')
258
- end
259
- return output_string
217
+ _build_cmd_output_string(method_name, target_name, cmd_name, cmd_params, packet_hash)
260
218
  end
261
219
 
262
220
  # Returns whether the given command is hazardous. Commands are hazardous
@@ -156,6 +156,7 @@ module OpenC3
156
156
  @virtual = false
157
157
  @restricted = false
158
158
  @validator = nil
159
+ @obfuscated_items = []
159
160
  end
160
161
 
161
162
  # Sets the target name this packet is associated with. Unidentified packets
@@ -556,6 +557,7 @@ module OpenC3
556
557
  item = super(item)
557
558
  update_id_items(item)
558
559
  update_limits_items_cache(item)
560
+ update_obfuscated_items_cache(item)
559
561
  item
560
562
  end
561
563
 
@@ -905,6 +907,7 @@ module OpenC3
905
907
  @short_buffer_allowed = false
906
908
  @id_items = nil
907
909
  @limits_items = nil
910
+ @obfuscated_items = []
908
911
  new_items = {}
909
912
  new_sorted_items = []
910
913
  @items.each do |name, item|
@@ -957,6 +960,21 @@ module OpenC3
957
960
  end
958
961
  end
959
962
 
963
+ # Add an item to the obfuscate items cache if necessary.
964
+ # You MUST call this after adding obfuscation to an item
965
+ # This is an optimization so we don't have to iterate through all the items when
966
+ # checking for obfuscation.
967
+ def update_obfuscated_items_cache(item)
968
+ if item.obfuscate
969
+ @obfuscated_items ||= []
970
+ @obfuscated_items_hash ||= {}
971
+ unless @obfuscated_items_hash[item]
972
+ @obfuscated_items << item
973
+ @obfuscated_items_hash[item] = true
974
+ end
975
+ end
976
+ end
977
+
960
978
  # Return an array of arrays indicating all items in the packet that are out of limits
961
979
  # [[target name, packet name, item name, item limits state], ...]
962
980
  #
@@ -1158,6 +1176,7 @@ module OpenC3
1158
1176
  config['validator'] = @validator.class.to_s if @validator
1159
1177
  config['template'] = Base64.encode64(@template) if @template
1160
1178
  config['config_name'] = self.config_name
1179
+ config['obfuscated_items'] = @obfuscated_items&.map(&:name) || []
1161
1180
 
1162
1181
  if @processors
1163
1182
  processors = []
@@ -1287,6 +1306,52 @@ module OpenC3
1287
1306
  end
1288
1307
  end
1289
1308
 
1309
+ def obfuscate()
1310
+ return unless @buffer
1311
+ return unless @obfuscated_items
1312
+
1313
+ @obfuscated_items.each do |item|
1314
+ next if item.data_type == :DERIVED
1315
+
1316
+ begin
1317
+ current_value = read(item.name, :RAW)
1318
+
1319
+ case current_value
1320
+ when Array
1321
+ # For arrays, create a new array of zeros with the same size
1322
+ case item.data_type
1323
+ when :INT, :UINT
1324
+ obfuscated_value = Array.new(current_value.size, 0)
1325
+ when :FLOAT
1326
+ obfuscated_value = Array.new(current_value.size, 0.0)
1327
+ when :STRING, :BLOCK
1328
+ obfuscated_value = Array.new(current_value.size) { |i|
1329
+ "\x00" * current_value[i].length if current_value[i]
1330
+ }
1331
+ else
1332
+ obfuscated_value = Array.new(current_value.size, 0)
1333
+ end
1334
+ when String
1335
+ # For strings/blocks, create null bytes of the same length
1336
+ obfuscated_value = "\x00" * current_value.length
1337
+ else
1338
+ case item.data_type
1339
+ when :INT, :UINT
1340
+ obfuscated_value = 0
1341
+ when :FLOAT
1342
+ obfuscated_value = 0.0
1343
+ else
1344
+ obfuscated_value = 0
1345
+ end
1346
+ end
1347
+ write(item.name, obfuscated_value, :RAW)
1348
+ rescue => e
1349
+ Logger.instance.error "#{item.name} obfuscation failed with error: #{e.message}"
1350
+ next
1351
+ end
1352
+ end
1353
+ end
1354
+
1290
1355
  protected
1291
1356
 
1292
1357
  def handle_limits_states(item, value)
@@ -1404,4 +1469,4 @@ module OpenC3
1404
1469
  item
1405
1470
  end
1406
1471
  end
1407
- end
1472
+ end
@@ -14,7 +14,7 @@
14
14
  # GNU Affero General Public License for more details.
15
15
 
16
16
  # Modified by OpenC3, Inc.
17
- # All changes Copyright 2024, OpenC3, Inc.
17
+ # All changes Copyright 2025, OpenC3, Inc.
18
18
  # All Rights Reserved
19
19
  #
20
20
  # This file may also be used under the terms of a commercial license
@@ -234,7 +234,8 @@ module OpenC3
234
234
  'POLY_WRITE_CONVERSION', 'SEG_POLY_READ_CONVERSION', 'SEG_POLY_WRITE_CONVERSION',\
235
235
  'GENERIC_READ_CONVERSION_START', 'GENERIC_WRITE_CONVERSION_START', 'REQUIRED',\
236
236
  'LIMITS', 'LIMITS_RESPONSE', 'UNITS', 'FORMAT_STRING', 'DESCRIPTION',\
237
- 'MINIMUM_VALUE', 'MAXIMUM_VALUE', 'DEFAULT_VALUE', 'OVERFLOW', 'OVERLAP', 'KEY', 'VARIABLE_BIT_SIZE'
237
+ 'MINIMUM_VALUE', 'MAXIMUM_VALUE', 'DEFAULT_VALUE', 'OVERFLOW', 'OVERLAP', 'KEY', 'VARIABLE_BIT_SIZE',\
238
+ 'OBFUSCATE'
238
239
  raise parser.error("No current item for #{keyword}") unless @current_item
239
240
 
240
241
  process_current_item(parser, keyword, params)
@@ -692,6 +693,13 @@ module OpenC3
692
693
  @current_item.units_full = params[0]
693
694
  @current_item.units = params[1]
694
695
 
696
+ # Obfuscate the parameter in logs
697
+ when 'OBFUSCATE'
698
+ usage = "OBFUSCATE"
699
+ parser.verify_num_parameters(0, 0, usage)
700
+ @current_item.obfuscate = true
701
+ @current_packet.update_obfuscated_items_cache(@current_item)
702
+
695
703
  # Update the description for the current telemetry item
696
704
  when 'DESCRIPTION'
697
705
  usage = "DESCRIPTION <DESCRIPTION>"
@@ -14,7 +14,7 @@
14
14
  # GNU Affero General Public License for more details.
15
15
 
16
16
  # Modified by OpenC3, Inc.
17
- # All changes Copyright 2022, OpenC3, Inc.
17
+ # All changes Copyright 2025, OpenC3, Inc.
18
18
  # All Rights Reserved
19
19
  #
20
20
  # This file may also be used under the terms of a commercial license
@@ -93,6 +93,9 @@ module OpenC3
93
93
  # @return [PacketItemLimits] All information regarding limits for this PacketItem
94
94
  attr_reader :limits
95
95
 
96
+ # @return [Boolean] Whether the parameter must be obfuscated from logs or not
97
+ attr_accessor :obfuscate
98
+
96
99
  # (see StructureItem#initialize)
97
100
  # It also initializes the attributes of the PacketItem.
98
101
  def initialize(name, bit_offset, bit_size, data_type, endianness, array_size = nil, overflow = :ERROR)
@@ -109,6 +112,7 @@ module OpenC3
109
112
  @range = nil
110
113
  @required = false
111
114
  @hazardous = nil
115
+ @obfuscate = false
112
116
  @messages_disabled = nil
113
117
  @state_colors = nil
114
118
  @limits = PacketItemLimits.new
@@ -314,6 +318,7 @@ module OpenC3
314
318
  item.state_colors = self.state_colors.clone if self.state_colors
315
319
  item.limits = self.limits.clone if self.limits
316
320
  item.meta = self.meta.clone if @meta
321
+ item.obfuscate = self.obfuscate.clone if @obfuscate
317
322
  item
318
323
  end
319
324
  alias dup clone
@@ -345,6 +350,7 @@ module OpenC3
345
350
  hash['limits'] = self.limits.to_hash
346
351
  hash['meta'] = nil
347
352
  hash['meta'] = @meta if @meta
353
+ hash['obfuscate'] = self.obfuscate
348
354
  hash
349
355
  end
350
356
 
@@ -404,6 +410,7 @@ module OpenC3
404
410
  config << " FORMAT_STRING #{self.format_string.to_s.quote_if_necessary}\n" if self.format_string
405
411
  config << " UNITS #{self.units_full.to_s.quote_if_necessary} #{self.units.to_s.quote_if_necessary}\n" if self.units
406
412
  config << " OVERFLOW #{self.overflow}\n" if self.overflow != :ERROR
413
+ config << " OBFUSCATE\n" if self.obfuscate
407
414
 
408
415
  if @states
409
416
  @states.each do |state_name, state_value|
@@ -512,6 +519,7 @@ module OpenC3
512
519
 
513
520
  config['meta'] = @meta if @meta
514
521
  config['variable_bit_size'] = @variable_bit_size if @variable_bit_size
522
+ config['obfuscate'] = self.obfuscate
515
523
  config
516
524
  end
517
525
 
@@ -573,6 +581,7 @@ module OpenC3
573
581
  item.limits.values = values if values.length > 0
574
582
  end
575
583
  item.meta = hash['meta']
584
+ item.obfuscate = hash['obfuscate']
576
585
  item.variable_bit_size = hash['variable_bit_size']
577
586
  item
578
587
  end
@@ -14,12 +14,13 @@
14
14
  # GNU Affero General Public License for more details.
15
15
 
16
16
  # Modified by OpenC3, Inc.
17
- # All changes Copyright 2024, OpenC3, Inc.
17
+ # All changes Copyright 2025, OpenC3, Inc.
18
18
  # All Rights Reserved
19
19
  #
20
20
  # This file may also be used under the terms of a commercial license
21
21
  # if purchased from OpenC3, Inc.
22
22
 
23
+ require 'json'
23
24
  require 'openc3/packets/packet'
24
25
  require 'openc3/script/extract'
25
26
 
@@ -30,7 +31,14 @@ module OpenC3
30
31
  private
31
32
 
32
33
  # Format the command like it appears in a script
33
- def _cmd_string(target_name, cmd_name, cmd_params, raw)
34
+ def _cmd_string(target_name, cmd_name, cmd_params, raw, obfuscated_items)
35
+ # Normally obfuscated_items is returned as an Array formatted as a JSON string
36
+ # because we're hitting the API server, but in the case of a disconnect command, it is an Array
37
+ if obfuscated_items and obfuscated_items.is_a?(String)
38
+ obfuscated_items = JSON.parse(obfuscated_items)
39
+ elsif !obfuscated_items
40
+ obfuscated_items = []
41
+ end
34
42
  output_string = $disconnect ? 'DISCONNECT: ' : ''
35
43
  if raw
36
44
  output_string += 'cmd_raw("'
@@ -44,18 +52,21 @@ module OpenC3
44
52
  params = []
45
53
  cmd_params.each do |key, value|
46
54
  next if Packet::RESERVED_ITEM_NAMES.include?(key)
47
-
48
- if value.is_a?(String)
49
- if !value.is_printable?
50
- value = "BINARY"
51
- elsif value.length > 256
52
- value = value[0..255] + "...'"
55
+ if obfuscated_items and obfuscated_items.is_a?(Array) and obfuscated_items.include?(key)
56
+ params << "#{key} *****"
57
+ else
58
+ if value.is_a?(String)
59
+ if !value.is_printable?
60
+ value = "BINARY"
61
+ elsif value.length > 256
62
+ value = value[0..255] + "...'"
63
+ end
64
+ value.tr!('"', "'")
65
+ elsif value.is_a?(Array)
66
+ value = "[#{value.join(", ")}]"
53
67
  end
54
- value.tr!('"', "'")
55
- elsif value.is_a?(Array)
56
- value = "[#{value.join(", ")}]"
68
+ params << "#{key} #{value}"
57
69
  end
58
- params << "#{key} #{value}"
59
70
  end
60
71
  params = params.join(", ")
61
72
  output_string += ' with ' + params + '")'
@@ -65,14 +76,14 @@ module OpenC3
65
76
 
66
77
  # Log any warnings about disabling checks and log the command itself
67
78
  # NOTE: This is a helper method and should not be called directly
68
- def _log_cmd(target_name, cmd_name, cmd_params, raw, no_range, no_hazardous)
79
+ def _log_cmd(cmd, raw, no_range, no_hazardous)
69
80
  if no_range
70
- puts "WARN: Command #{target_name} #{cmd_name} being sent ignoring range checks"
81
+ puts "WARN: Command #{cmd['target_name']} #{cmd['cmd_name']} being sent ignoring range checks"
71
82
  end
72
83
  if no_hazardous
73
- puts "WARN: Command #{target_name} #{cmd_name} being sent ignoring hazardous warnings"
84
+ puts "WARN: Command #{cmd['target_name']} #{cmd['cmd_name']} being sent ignoring hazardous warnings"
74
85
  end
75
- puts _cmd_string(target_name, cmd_name, cmd_params, raw)
86
+ puts _cmd_string(cmd['target_name'], cmd['cmd_name'], cmd['cmd_params'], raw, cmd['obfuscated_items'])
76
87
  end
77
88
 
78
89
  def _cmd_disconnect(cmd, raw, no_range, no_hazardous, *args, scope: $openc3_scope)
@@ -94,14 +105,17 @@ module OpenC3
94
105
 
95
106
  # Get the command and validate the parameters
96
107
  command = $api_server.get_cmd(target_name, cmd_name, scope: scope)
108
+ # This returns a packet hash instead of the command hash so add missing fields
109
+ command['cmd_name'] = cmd_name
110
+ command['cmd_params'] = cmd_params
97
111
  cmd_params.each do |param_name, _param_value|
98
112
  param = command['items'].find { |item| item['name'] == param_name }
99
113
  unless param
100
114
  raise "Packet item '#{target_name} #{cmd_name} #{param_name}' does not exist"
101
115
  end
102
116
  end
103
- _log_cmd(target_name, cmd_name, cmd_params, raw, no_range, no_hazardous)
104
- end
117
+ _log_cmd(command, raw, no_range, no_hazardous)
118
+ end
105
119
 
106
120
  # Send the command and log the results
107
121
  # This method signature has to include the keyword params present in cmd_api.rb _cmd_implementation()
@@ -113,30 +127,29 @@ module OpenC3
113
127
  raw = cmd.include?('raw')
114
128
  no_range = cmd.include?('no_range') || cmd.include?('no_checks')
115
129
  no_hazardous = cmd.include?('no_hazardous') || cmd.include?('no_checks')
116
-
117
130
  if $disconnect
118
131
  _cmd_disconnect(cmd, raw, no_range, no_hazardous, *args, scope: scope)
119
132
  else
120
133
  begin
121
134
  begin
122
- target_name, cmd_name, cmd_params = $api_server.method_missing(cmd, *args, timeout: timeout, log_message: log_message, validate: validate, scope: scope, token: token)
135
+ command = $api_server.method_missing(cmd, *args, timeout: timeout, log_message: log_message, validate: validate, scope: scope, token: token)
123
136
  if log_message.nil? or log_message
124
- _log_cmd(target_name, cmd_name, cmd_params, raw, no_range, no_hazardous)
137
+ _log_cmd(command, raw, no_range, no_hazardous)
125
138
  end
126
139
  rescue HazardousError => e
127
140
  # This opens a prompt at which point they can cancel and stop the script
128
141
  # or say Yes and send the command. Thus we don't care about the return value.
129
142
  prompt_for_hazardous(e.target_name, e.cmd_name, e.hazardous_description)
130
- target_name, cmd_name, cmd_params = $api_server.method_missing(cmd_no_hazardous, *args, timeout: timeout, log_message: log_message, validate: validate, scope: scope, token: token)
143
+ command = $api_server.method_missing(cmd_no_hazardous, *args, timeout: timeout, log_message: log_message, validate: validate, scope: scope, token: token)
131
144
  if log_message.nil? or log_message
132
- _log_cmd(target_name, cmd_name, cmd_params, raw, no_range, no_hazardous)
145
+ _log_cmd(command, raw, no_range, no_hazardous)
133
146
  end
134
147
  end
135
148
  rescue CriticalCmdError => e
136
149
  # This should not return until the critical command has been approved
137
- prompt_for_critical_cmd(e.uuid, e.username, e.target_name, e.cmd_name, e.cmd_params, e.cmd_string)
150
+ prompt_for_critical_cmd(e.uuid, e.command['username'], e.command['target_name'], e.command['cmd_name'], e.command['cmd_params'], e.command['cmd_string'])
138
151
  if log_message.nil? or log_message
139
- _log_cmd(e.target_name, e.cmd_name, e.cmd_params, raw, no_range, no_hazardous)
152
+ _log_cmd(e.command, raw, no_range, no_hazardous)
140
153
  end
141
154
  end
142
155
  end
@@ -14,10 +14,10 @@
14
14
  # GNU Affero General Public License for more details.
15
15
 
16
16
  # Modified by OpenC3, Inc.
17
- # All changes Copyright 2022, OpenC3, Inc.
17
+ # All changes Copyright 2025, OpenC3, Inc.
18
18
  # All Rights Reserved
19
19
  #
20
- # This file may also be used under the terms of a commercial license
20
+ # This file may also be used under the terms of a commercial license
21
21
  # if purchased from OpenC3, Inc.
22
22
 
23
23
  require 'openc3/config/config_parser'
@@ -169,7 +169,7 @@ module OpenC3
169
169
  'GENERIC_WRITE_CONVERSION_START', 'REQUIRED', 'LIMITS',
170
170
  'LIMITS_RESPONSE', 'UNITS', 'FORMAT_STRING', 'DESCRIPTION',
171
171
  'HIDDEN', 'MINIMUM_VALUE', 'MAXIMUM_VALUE', 'DEFAULT_VALUE',
172
- 'OVERFLOW', 'UNEDITABLE'
172
+ 'OVERFLOW', 'UNEDITABLE', 'OBFUSCATE'
173
173
  unless @current_item
174
174
  raise parser.error("No current item for #{keyword}")
175
175
  end
@@ -14,7 +14,7 @@
14
14
  # GNU Affero General Public License for more details.
15
15
 
16
16
  # Modified by OpenC3, Inc.
17
- # All changes Copyright 2024, OpenC3, Inc.
17
+ # All changes Copyright 2025, OpenC3, Inc.
18
18
  # All Rights Reserved
19
19
  #
20
20
  # This file may also be used under the terms of a commercial license
@@ -51,11 +51,7 @@ end
51
51
 
52
52
  class CriticalCmdError < StandardError
53
53
  attr_accessor :uuid
54
- attr_accessor :username
55
- attr_accessor :target_name
56
- attr_accessor :cmd_name
57
- attr_accessor :cmd_params
58
- attr_accessor :cmd_string
54
+ attr_accessor :command
59
55
  end
60
56
 
61
57
  # If a disabled command is sent through the {OpenC3::Api} this error is raised.
@@ -14,7 +14,7 @@
14
14
  # GNU Affero General Public License for more details.
15
15
 
16
16
  # Modified by OpenC3, Inc.
17
- # All changes Copyright 2024, OpenC3, Inc.
17
+ # All changes Copyright 2025, OpenC3, Inc.
18
18
  # All Rights Reserved
19
19
  #
20
20
  # This file may also be used under the terms of a commercial license
@@ -41,7 +41,7 @@ module OpenC3
41
41
  end
42
42
 
43
43
  # @param command [Hash] Command hash structure read to be written to a topic
44
- def self.send_command(command, timeout: COMMAND_ACK_TIMEOUT_S, scope:)
44
+ def self.send_command(command, timeout: COMMAND_ACK_TIMEOUT_S, scope:, obfuscated_items: [])
45
45
  timeout = COMMAND_ACK_TIMEOUT_S unless timeout
46
46
  ack_topic = "{#{scope}__ACKCMD}TARGET__#{command['target_name']}"
47
47
  Topic.update_topic_offsets([ack_topic])
@@ -50,17 +50,18 @@ module OpenC3
50
50
  command['cmd_params'] = JSON.generate(command['cmd_params'].as_json(:allow_nan => true))
51
51
  OpenC3.inject_context(command)
52
52
  cmd_id = Topic.write_topic("{#{scope}__CMD}TARGET__#{command['target_name']}", command, '*', 100)
53
+ command["cmd_params"] = cmd_params # Restore the original cmd_params Hash
53
54
  time = Time.now
54
55
  while (Time.now - time) < timeout
55
56
  Topic.read_topics([ack_topic]) do |_topic, _msg_id, msg_hash, _redis|
56
57
  if msg_hash["id"] == cmd_id
57
58
  if msg_hash["result"] == "SUCCESS"
58
- return [command['target_name'], command['cmd_name'], cmd_params]
59
+ return command
59
60
  # Check for HazardousError which is a special case
60
61
  elsif msg_hash["result"].include?("HazardousError")
61
- raise_hazardous_error(msg_hash, command['target_name'], command['cmd_name'], cmd_params)
62
+ raise_hazardous_error(msg_hash, command)
62
63
  elsif msg_hash["result"].include?("CriticalCmdError")
63
- raise_critical_cmd_error(msg_hash, command['username'], command['target_name'], command['cmd_name'], cmd_params, command['cmd_string'])
64
+ raise_critical_cmd_error(msg_hash, command)
64
65
  else
65
66
  raise msg_hash["result"]
66
67
  end
@@ -74,14 +75,14 @@ module OpenC3
74
75
  # PRIVATE implementation details
75
76
  ###########################################################################
76
77
 
77
- def self.raise_hazardous_error(msg_hash, target_name, cmd_name, cmd_params)
78
+ def self.raise_hazardous_error(msg_hash, command)
78
79
  _, description, formatted = msg_hash["result"].split("\n")
79
80
  # Create and populate a new HazardousError and raise it up
80
81
  # The _cmd method in script/commands.rb rescues this and calls prompt_for_hazardous
81
82
  error = HazardousError.new
82
- error.target_name = target_name
83
- error.cmd_name = cmd_name
84
- error.cmd_params = cmd_params
83
+ error.target_name = command["target_name"]
84
+ error.cmd_name = command["cmd_name"]
85
+ error.cmd_params = command["cmd_params"]
85
86
  error.hazardous_description = description
86
87
  error.formatted = formatted
87
88
 
@@ -89,17 +90,13 @@ module OpenC3
89
90
  raise error
90
91
  end
91
92
 
92
- def self.raise_critical_cmd_error(msg_hash, username, target_name, cmd_name, cmd_params, cmd_string)
93
+ def self.raise_critical_cmd_error(msg_hash, command)
93
94
  _, uuid = msg_hash["result"].split("\n")
94
95
  # Create and populate a new CriticalCmdError and raise it up
95
96
  # The _cmd method in script/commands.rb rescues this and calls prompt_for_critical_cmd
96
97
  error = CriticalCmdError.new
97
98
  error.uuid = uuid
98
- error.username = username
99
- error.target_name = target_name
100
- error.cmd_name = cmd_name
101
- error.cmd_params = cmd_params
102
- error.cmd_string = cmd_string
99
+ error.command = command
103
100
  raise error
104
101
  end
105
102
  end
@@ -0,0 +1,70 @@
1
+ # encoding: ascii-8bit
2
+
3
+ # Copyright 2025 OpenC3, Inc.
4
+ # All Rights Reserved.
5
+ #
6
+ # This program is free software; you can modify and/or redistribute it
7
+ # under the terms of the GNU Affero General Public License
8
+ # as published by the Free Software Foundation; version 3 with
9
+ # attribution addendums as found in the LICENSE.txt
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU Affero General Public License for more details.
15
+
16
+ # This file may also be used under the terms of a commercial license
17
+ # if purchased from OpenC3, Inc.
18
+
19
+ require 'openc3/packets/packet'
20
+
21
+ module OpenC3
22
+ module CmdLog
23
+ def _build_cmd_output_string(method_name, target_name, cmd_name, cmd_params, packet)
24
+ output_string = "#{method_name}(\""
25
+ output_string << (target_name + ' ' + cmd_name)
26
+ if cmd_params.nil? or cmd_params.empty?
27
+ output_string << '")'
28
+ else
29
+ params = []
30
+ cmd_params.each do |key, value|
31
+ next if Packet::RESERVED_ITEM_NAMES.include?(key)
32
+
33
+ item = packet['items'].find { |find_item| find_item['name'] == key.to_s }
34
+ begin
35
+ item_type = item['data_type'].intern
36
+ rescue
37
+ item_type = nil
38
+ end
39
+
40
+ if (item and item['obfuscate'])
41
+ params << "#{key} *****"
42
+ else
43
+ if value.is_a?(String)
44
+ value = value.dup
45
+ if item_type == :BLOCK or item_type == :STRING
46
+ if !value.is_printable?
47
+ value = "0x" + value.simple_formatted
48
+ else
49
+ value = value.inspect
50
+ end
51
+ else
52
+ value = value.convert_to_value.to_s
53
+ end
54
+ if value.length > 256
55
+ value = value[0..255] + "...'"
56
+ end
57
+ value.tr!('"', "'")
58
+ elsif value.is_a?(Array)
59
+ value = "[#{value.join(", ")}]"
60
+ end
61
+ params << "#{key} #{value}"
62
+ end
63
+ end
64
+ params = params.join(", ")
65
+ output_string << (' with ' + params + '")')
66
+ end
67
+ return output_string
68
+ end
69
+ end
70
+ end
@@ -1,14 +1,14 @@
1
1
  # encoding: ascii-8bit
2
2
 
3
- OPENC3_VERSION = '6.5.1'
3
+ OPENC3_VERSION = '6.6.0'
4
4
  module OpenC3
5
5
  module Version
6
6
  MAJOR = '6'
7
- MINOR = '5'
8
- PATCH = '1'
7
+ MINOR = '6'
8
+ PATCH = '0'
9
9
  OTHER = ''
10
- BUILD = 'bccc9a29582eed0d565be2c5135676ce87c066f8'
10
+ BUILD = 'ceee2aabacbdfe57fe8b5de3580358db2ae3a19a'
11
11
  end
12
- VERSION = '6.5.1'
13
- GEM_VERSION = '6.5.1'
12
+ VERSION = '6.6.0'
13
+ GEM_VERSION = '6.6.0'
14
14
  end
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "<%= tool_name %>",
3
- "version": "6.5.1",
3
+ "version": "6.6.0",
4
4
  "scripts": {
5
5
  "ng": "ng",
6
6
  "start": "ng serve",
@@ -23,7 +23,7 @@
23
23
  "@angular/platform-browser-dynamic": "^18.2.6",
24
24
  "@angular/router": "^18.2.6",
25
25
  "@astrouxds/astro-web-components": "^7.24.0",
26
- "@openc3/js-common": "6.5.1",
26
+ "@openc3/js-common": "6.6.0",
27
27
  "rxjs": "~7.8.0",
28
28
  "single-spa": "^5.9.5",
29
29
  "single-spa-angular": "^9.2.0",
@@ -16,7 +16,7 @@
16
16
  "@emotion/react": "^11.13.3",
17
17
  "@emotion/styled": "^11.11.0",
18
18
  "@mui/material": "^6.1.1",
19
- "@openc3/js-common": "6.5.1",
19
+ "@openc3/js-common": "6.6.0",
20
20
  "react": "^18.2.0",
21
21
  "react-dom": "^18.2.0",
22
22
  "single-spa-react": "^5.1.4"
@@ -12,7 +12,7 @@
12
12
  },
13
13
  "dependencies": {
14
14
  "@astrouxds/astro-web-components": "^7.24.0",
15
- "@openc3/js-common": "6.5.1",
15
+ "@openc3/js-common": "6.6.0",
16
16
  "@smui/button": "^7.0.0",
17
17
  "@smui/common": "^7.0.0",
18
18
  "@smui/card": "^7.0.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "<%= tool_name %>",
3
- "version": "6.5.1",
3
+ "version": "6.6.0",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "scripts": {
@@ -11,8 +11,8 @@
11
11
  },
12
12
  "dependencies": {
13
13
  "@astrouxds/astro-web-components": "^7.24.0",
14
- "@openc3/js-common": "6.5.1",
15
- "@openc3/vue-common": "6.5.1",
14
+ "@openc3/js-common": "6.6.0",
15
+ "@openc3/vue-common": "6.6.0",
16
16
  "axios": "^1.7.7",
17
17
  "date-fns": "^4.1.0",
18
18
  "lodash": "^4.17.21",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "<%= widget_name %>",
3
- "version": "6.5.1",
3
+ "version": "6.6.0",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "scripts": {
@@ -8,7 +8,7 @@
8
8
  },
9
9
  "dependencies": {
10
10
  "@astrouxds/astro-web-components": "^7.24.0",
11
- "@openc3/vue-common": "6.5.1",
11
+ "@openc3/vue-common": "6.6.0",
12
12
  "vuetify": "^3.7.1"
13
13
  },
14
14
  "devDependencies": {
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openc3
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.5.1
4
+ version: 6.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Melton
@@ -766,20 +766,6 @@ dependencies:
766
766
  - - "~>"
767
767
  - !ruby/object:Gem::Version
768
768
  version: '2.1'
769
- - !ruby/object:Gem::Dependency
770
- name: simplecov_json_formatter
771
- requirement: !ruby/object:Gem::Requirement
772
- requirements:
773
- - - "~>"
774
- - !ruby/object:Gem::Version
775
- version: '0.1'
776
- type: :development
777
- prerelease: false
778
- version_requirements: !ruby/object:Gem::Requirement
779
- requirements:
780
- - - "~>"
781
- - !ruby/object:Gem::Version
782
- version: '0.1'
783
769
  description: |2
784
770
  OpenC3 provides all the functionality needed to send
785
771
  commands to and receive data from one or more embedded systems
@@ -1156,6 +1142,7 @@ files:
1156
1142
  - lib/openc3/utilities/bucket_require.rb
1157
1143
  - lib/openc3/utilities/bucket_utilities.rb
1158
1144
  - lib/openc3/utilities/cli_generator.rb
1145
+ - lib/openc3/utilities/cmd_log.rb
1159
1146
  - lib/openc3/utilities/cosmos_rails_formatter.rb
1160
1147
  - lib/openc3/utilities/crc.rb
1161
1148
  - lib/openc3/utilities/csv.rb