oscura 0.7.0__py3-none-any.whl → 0.10.0__py3-none-any.whl

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.
Files changed (175) hide show
  1. oscura/__init__.py +19 -19
  2. oscura/analyzers/__init__.py +2 -0
  3. oscura/analyzers/digital/extraction.py +2 -3
  4. oscura/analyzers/digital/quality.py +1 -1
  5. oscura/analyzers/digital/timing.py +1 -1
  6. oscura/analyzers/eye/__init__.py +5 -1
  7. oscura/analyzers/eye/generation.py +501 -0
  8. oscura/analyzers/jitter/__init__.py +6 -6
  9. oscura/analyzers/jitter/timing.py +419 -0
  10. oscura/analyzers/patterns/__init__.py +94 -0
  11. oscura/analyzers/patterns/reverse_engineering.py +991 -0
  12. oscura/analyzers/power/__init__.py +35 -12
  13. oscura/analyzers/power/basic.py +3 -3
  14. oscura/analyzers/power/soa.py +1 -1
  15. oscura/analyzers/power/switching.py +3 -3
  16. oscura/analyzers/signal_classification.py +529 -0
  17. oscura/analyzers/signal_integrity/sparams.py +3 -3
  18. oscura/analyzers/statistics/__init__.py +4 -0
  19. oscura/analyzers/statistics/basic.py +152 -0
  20. oscura/analyzers/statistics/correlation.py +47 -6
  21. oscura/analyzers/validation.py +1 -1
  22. oscura/analyzers/waveform/__init__.py +2 -0
  23. oscura/analyzers/waveform/measurements.py +329 -163
  24. oscura/analyzers/waveform/measurements_with_uncertainty.py +91 -35
  25. oscura/analyzers/waveform/spectral.py +498 -54
  26. oscura/api/dsl/commands.py +15 -6
  27. oscura/api/server/templates/base.html +137 -146
  28. oscura/api/server/templates/export.html +84 -110
  29. oscura/api/server/templates/home.html +248 -267
  30. oscura/api/server/templates/protocols.html +44 -48
  31. oscura/api/server/templates/reports.html +27 -35
  32. oscura/api/server/templates/session_detail.html +68 -78
  33. oscura/api/server/templates/sessions.html +62 -72
  34. oscura/api/server/templates/waveforms.html +54 -64
  35. oscura/automotive/__init__.py +1 -1
  36. oscura/automotive/can/session.py +1 -1
  37. oscura/automotive/dbc/generator.py +638 -23
  38. oscura/automotive/dtc/data.json +102 -17
  39. oscura/automotive/uds/decoder.py +99 -6
  40. oscura/cli/analyze.py +8 -2
  41. oscura/cli/batch.py +36 -5
  42. oscura/cli/characterize.py +18 -4
  43. oscura/cli/export.py +47 -5
  44. oscura/cli/main.py +2 -0
  45. oscura/cli/onboarding/wizard.py +10 -6
  46. oscura/cli/pipeline.py +585 -0
  47. oscura/cli/visualize.py +6 -4
  48. oscura/convenience.py +400 -32
  49. oscura/core/config/loader.py +0 -1
  50. oscura/core/measurement_result.py +286 -0
  51. oscura/core/progress.py +1 -1
  52. oscura/core/schemas/device_mapping.json +8 -2
  53. oscura/core/schemas/packet_format.json +24 -4
  54. oscura/core/schemas/protocol_definition.json +12 -2
  55. oscura/core/types.py +300 -199
  56. oscura/correlation/multi_protocol.py +1 -1
  57. oscura/export/legacy/__init__.py +11 -0
  58. oscura/export/legacy/wav.py +75 -0
  59. oscura/exporters/__init__.py +19 -0
  60. oscura/exporters/wireshark.py +809 -0
  61. oscura/hardware/acquisition/file.py +5 -19
  62. oscura/hardware/acquisition/saleae.py +10 -10
  63. oscura/hardware/acquisition/socketcan.py +4 -6
  64. oscura/hardware/acquisition/synthetic.py +1 -5
  65. oscura/hardware/acquisition/visa.py +6 -6
  66. oscura/hardware/security/side_channel_detector.py +5 -508
  67. oscura/inference/message_format.py +686 -1
  68. oscura/jupyter/display.py +2 -2
  69. oscura/jupyter/magic.py +3 -3
  70. oscura/loaders/__init__.py +17 -12
  71. oscura/loaders/binary.py +1 -1
  72. oscura/loaders/chipwhisperer.py +1 -2
  73. oscura/loaders/configurable.py +1 -1
  74. oscura/loaders/csv_loader.py +2 -2
  75. oscura/loaders/hdf5_loader.py +1 -1
  76. oscura/loaders/lazy.py +6 -1
  77. oscura/loaders/mmap_loader.py +0 -1
  78. oscura/loaders/numpy_loader.py +8 -7
  79. oscura/loaders/preprocessing.py +3 -5
  80. oscura/loaders/rigol.py +21 -7
  81. oscura/loaders/sigrok.py +2 -5
  82. oscura/loaders/tdms.py +3 -2
  83. oscura/loaders/tektronix.py +38 -32
  84. oscura/loaders/tss.py +20 -27
  85. oscura/loaders/vcd.py +13 -8
  86. oscura/loaders/wav.py +1 -6
  87. oscura/pipeline/__init__.py +76 -0
  88. oscura/pipeline/handlers/__init__.py +165 -0
  89. oscura/pipeline/handlers/analyzers.py +1045 -0
  90. oscura/pipeline/handlers/decoders.py +899 -0
  91. oscura/pipeline/handlers/exporters.py +1103 -0
  92. oscura/pipeline/handlers/filters.py +891 -0
  93. oscura/pipeline/handlers/loaders.py +640 -0
  94. oscura/pipeline/handlers/transforms.py +768 -0
  95. oscura/reporting/__init__.py +88 -1
  96. oscura/reporting/automation.py +348 -0
  97. oscura/reporting/citations.py +374 -0
  98. oscura/reporting/core.py +54 -0
  99. oscura/reporting/formatting/__init__.py +11 -0
  100. oscura/reporting/formatting/measurements.py +320 -0
  101. oscura/reporting/html.py +57 -0
  102. oscura/reporting/interpretation.py +431 -0
  103. oscura/reporting/summary.py +329 -0
  104. oscura/reporting/templates/enhanced/protocol_re.html +504 -503
  105. oscura/reporting/visualization.py +542 -0
  106. oscura/side_channel/__init__.py +38 -57
  107. oscura/utils/builders/signal_builder.py +5 -5
  108. oscura/utils/comparison/compare.py +7 -9
  109. oscura/utils/comparison/golden.py +1 -1
  110. oscura/utils/filtering/convenience.py +2 -2
  111. oscura/utils/math/arithmetic.py +38 -62
  112. oscura/utils/math/interpolation.py +20 -20
  113. oscura/utils/pipeline/__init__.py +4 -17
  114. oscura/utils/progressive.py +1 -4
  115. oscura/utils/triggering/edge.py +1 -1
  116. oscura/utils/triggering/pattern.py +2 -2
  117. oscura/utils/triggering/pulse.py +2 -2
  118. oscura/utils/triggering/window.py +3 -3
  119. oscura/validation/hil_testing.py +11 -11
  120. oscura/visualization/__init__.py +47 -284
  121. oscura/visualization/batch.py +160 -0
  122. oscura/visualization/plot.py +542 -53
  123. oscura/visualization/styles.py +184 -318
  124. oscura/workflows/__init__.py +2 -0
  125. oscura/workflows/batch/advanced.py +1 -1
  126. oscura/workflows/batch/aggregate.py +7 -8
  127. oscura/workflows/complete_re.py +251 -23
  128. oscura/workflows/digital.py +27 -4
  129. oscura/workflows/multi_trace.py +136 -17
  130. oscura/workflows/waveform.py +788 -0
  131. {oscura-0.7.0.dist-info → oscura-0.10.0.dist-info}/METADATA +59 -79
  132. {oscura-0.7.0.dist-info → oscura-0.10.0.dist-info}/RECORD +135 -149
  133. oscura/side_channel/dpa.py +0 -1025
  134. oscura/utils/optimization/__init__.py +0 -19
  135. oscura/utils/optimization/parallel.py +0 -443
  136. oscura/utils/optimization/search.py +0 -532
  137. oscura/utils/pipeline/base.py +0 -338
  138. oscura/utils/pipeline/composition.py +0 -248
  139. oscura/utils/pipeline/parallel.py +0 -449
  140. oscura/utils/pipeline/pipeline.py +0 -375
  141. oscura/utils/search/__init__.py +0 -16
  142. oscura/utils/search/anomaly.py +0 -424
  143. oscura/utils/search/context.py +0 -294
  144. oscura/utils/search/pattern.py +0 -288
  145. oscura/utils/storage/__init__.py +0 -61
  146. oscura/utils/storage/database.py +0 -1166
  147. oscura/visualization/accessibility.py +0 -526
  148. oscura/visualization/annotations.py +0 -371
  149. oscura/visualization/axis_scaling.py +0 -305
  150. oscura/visualization/colors.py +0 -451
  151. oscura/visualization/digital.py +0 -436
  152. oscura/visualization/eye.py +0 -571
  153. oscura/visualization/histogram.py +0 -281
  154. oscura/visualization/interactive.py +0 -1035
  155. oscura/visualization/jitter.py +0 -1042
  156. oscura/visualization/keyboard.py +0 -394
  157. oscura/visualization/layout.py +0 -400
  158. oscura/visualization/optimization.py +0 -1079
  159. oscura/visualization/palettes.py +0 -446
  160. oscura/visualization/power.py +0 -508
  161. oscura/visualization/power_extended.py +0 -955
  162. oscura/visualization/presets.py +0 -469
  163. oscura/visualization/protocols.py +0 -1246
  164. oscura/visualization/render.py +0 -223
  165. oscura/visualization/rendering.py +0 -444
  166. oscura/visualization/reverse_engineering.py +0 -838
  167. oscura/visualization/signal_integrity.py +0 -989
  168. oscura/visualization/specialized.py +0 -643
  169. oscura/visualization/spectral.py +0 -1226
  170. oscura/visualization/thumbnails.py +0 -340
  171. oscura/visualization/time_axis.py +0 -351
  172. oscura/visualization/waveform.py +0 -454
  173. {oscura-0.7.0.dist-info → oscura-0.10.0.dist-info}/WHEEL +0 -0
  174. {oscura-0.7.0.dist-info → oscura-0.10.0.dist-info}/entry_points.txt +0 -0
  175. {oscura-0.7.0.dist-info → oscura-0.10.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,284 +1,265 @@
1
- {% extends "base.html" %}
2
-
3
- {% block title %}Home - {{ title }}{% endblock %}
4
-
5
- {% block content %}
1
+ {% extends "base.html" %} {% block title %}Home - {{ title }}{% endblock %} {% block content %}
6
2
  <div class="row">
7
- <div class="col-lg-8 offset-lg-2">
8
- <div class="card mb-4">
9
- <div class="card-body">
10
- <h1 class="card-title mb-4">
11
- <i class="bi bi-cpu"></i> Protocol Analysis
12
- </h1>
13
- <p class="lead">
14
- Upload signal capture files for automated protocol reverse engineering.
15
- Supports VCD, WAV, PCAP, and other formats.
16
- </p>
17
- </div>
18
- </div>
3
+ <div class="col-lg-8 offset-lg-2">
4
+ <div class="card mb-4">
5
+ <div class="card-body">
6
+ <h1 class="card-title mb-4"><i class="bi bi-cpu"></i> Protocol Analysis</h1>
7
+ <p class="lead">
8
+ Upload signal capture files for automated protocol reverse engineering. Supports VCD, WAV, PCAP, and other
9
+ formats.
10
+ </p>
11
+ </div>
12
+ </div>
19
13
 
20
- <!-- File Upload -->
21
- <div class="card">
22
- <div class="card-body">
23
- <h5 class="card-title mb-4">Upload Capture File</h5>
24
-
25
- <form id="uploadForm" enctype="multipart/form-data">
26
- <!-- Dropzone -->
27
- <div class="dropzone mb-4" id="dropzone">
28
- <i class="bi bi-cloud-upload" style="font-size: 3rem; opacity: 0.5;"></i>
29
- <h5 class="mt-3">Drag & Drop File Here</h5>
30
- <p class="text-muted">or click to browse</p>
31
- <p class="text-muted small">Maximum file size: {{ max_file_size_mb }} MB</p>
32
- <input type="file" id="fileInput" name="file" class="d-none" accept=".vcd,.wav,.pcap,.pcapng,.csv,.bin">
33
- </div>
34
-
35
- <div id="fileInfo" class="mb-3 d-none">
36
- <div class="alert alert-info">
37
- <i class="bi bi-file-earmark"></i>
38
- <strong>Selected:</strong> <span id="fileName"></span>
39
- (<span id="fileSize"></span>)
40
- </div>
41
- </div>
42
-
43
- <!-- Analysis Options -->
44
- <div class="row mb-3">
45
- <div class="col-md-6">
46
- <label for="protocolHint" class="form-label">
47
- <i class="bi bi-hint"></i> Protocol Hint (Optional)
48
- </label>
49
- <select class="form-select" id="protocolHint" name="protocol_hint">
50
- <option value="">Auto-detect</option>
51
- <option value="uart">UART</option>
52
- <option value="spi">SPI</option>
53
- <option value="i2c">I2C</option>
54
- <option value="can">CAN Bus</option>
55
- <option value="usb">USB</option>
56
- <option value="ethernet">Ethernet</option>
57
- </select>
58
- </div>
59
- </div>
60
-
61
- <div class="row mb-4">
62
- <div class="col-md-4">
63
- <div class="form-check">
64
- <input class="form-check-input" type="checkbox" id="autoCRC" name="auto_crc" checked>
65
- <label class="form-check-label" for="autoCRC">
66
- Auto-detect CRC
67
- </label>
68
- </div>
69
- </div>
70
- <div class="col-md-4">
71
- <div class="form-check">
72
- <input class="form-check-input" type="checkbox" id="detectCrypto" name="detect_crypto" checked>
73
- <label class="form-check-label" for="detectCrypto">
74
- Detect Crypto
75
- </label>
76
- </div>
77
- </div>
78
- <div class="col-md-4">
79
- <div class="form-check">
80
- <input class="form-check-input" type="checkbox" id="generateTests" name="generate_tests" checked>
81
- <label class="form-check-label" for="generateTests">
82
- Generate Tests
83
- </label>
84
- </div>
85
- </div>
86
- </div>
87
-
88
- <!-- Submit Button -->
89
- <button type="submit" class="btn btn-primary btn-lg w-100" id="analyzeBtn">
90
- <i class="bi bi-play-circle"></i> Start Analysis
91
- </button>
92
- </form>
93
-
94
- <!-- Progress Indicator -->
95
- <div id="progressContainer" class="mt-4 d-none">
96
- <div class="progress">
97
- <div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" id="progressBar" style="width: 0%"></div>
98
- </div>
99
- <p class="text-center mt-2" id="progressText">Initializing...</p>
100
- </div>
14
+ <!-- File Upload -->
15
+ <div class="card">
16
+ <div class="card-body">
17
+ <h5 class="card-title mb-4">Upload Capture File</h5>
18
+
19
+ <form id="uploadForm" enctype="multipart/form-data">
20
+ <!-- Dropzone -->
21
+ <div class="dropzone mb-4" id="dropzone">
22
+ <i class="bi bi-cloud-upload" style="font-size: 3rem; opacity: 0.5"></i>
23
+ <h5 class="mt-3">Drag & Drop File Here</h5>
24
+ <p class="text-muted">or click to browse</p>
25
+ <p class="text-muted small">Maximum file size: {{ max_file_size_mb }} MB</p>
26
+ <input type="file" id="fileInput" name="file" class="d-none" accept=".vcd,.wav,.pcap,.pcapng,.csv,.bin" />
27
+ </div>
28
+
29
+ <div id="fileInfo" class="mb-3 d-none">
30
+ <div class="alert alert-info">
31
+ <i class="bi bi-file-earmark"></i>
32
+ <strong>Selected:</strong> <span id="fileName"></span> (<span id="fileSize"></span>)
33
+ </div>
34
+ </div>
35
+
36
+ <!-- Analysis Options -->
37
+ <div class="row mb-3">
38
+ <div class="col-md-6">
39
+ <label for="protocolHint" class="form-label"> <i class="bi bi-hint"></i> Protocol Hint (Optional) </label>
40
+ <select class="form-select" id="protocolHint" name="protocol_hint">
41
+ <option value="">Auto-detect</option>
42
+ <option value="uart">UART</option>
43
+ <option value="spi">SPI</option>
44
+ <option value="i2c">I2C</option>
45
+ <option value="can">CAN Bus</option>
46
+ <option value="usb">USB</option>
47
+ <option value="ethernet">Ethernet</option>
48
+ </select>
101
49
  </div>
50
+ </div>
51
+
52
+ <div class="row mb-4">
53
+ <div class="col-md-4">
54
+ <div class="form-check">
55
+ <input class="form-check-input" type="checkbox" id="autoCRC" name="auto_crc" checked />
56
+ <label class="form-check-label" for="autoCRC"> Auto-detect CRC </label>
57
+ </div>
58
+ </div>
59
+ <div class="col-md-4">
60
+ <div class="form-check">
61
+ <input class="form-check-input" type="checkbox" id="detectCrypto" name="detect_crypto" checked />
62
+ <label class="form-check-label" for="detectCrypto"> Detect Crypto </label>
63
+ </div>
64
+ </div>
65
+ <div class="col-md-4">
66
+ <div class="form-check">
67
+ <input class="form-check-input" type="checkbox" id="generateTests" name="generate_tests" checked />
68
+ <label class="form-check-label" for="generateTests"> Generate Tests </label>
69
+ </div>
70
+ </div>
71
+ </div>
72
+
73
+ <!-- Submit Button -->
74
+ <button type="submit" class="btn btn-primary btn-lg w-100" id="analyzeBtn">
75
+ <i class="bi bi-play-circle"></i> Start Analysis
76
+ </button>
77
+ </form>
78
+
79
+ <!-- Progress Indicator -->
80
+ <div id="progressContainer" class="mt-4 d-none">
81
+ <div class="progress">
82
+ <div
83
+ class="progress-bar progress-bar-striped progress-bar-animated"
84
+ role="progressbar"
85
+ id="progressBar"
86
+ style="width: 0%"
87
+ ></div>
88
+ </div>
89
+ <p class="text-center mt-2" id="progressText">Initializing...</p>
102
90
  </div>
91
+ </div>
92
+ </div>
103
93
 
104
- <!-- Recent Sessions -->
105
- <div class="card mt-4">
106
- <div class="card-body">
107
- <h5 class="card-title mb-3">
108
- <i class="bi bi-clock-history"></i> Quick Actions
109
- </h5>
110
- <div class="d-grid gap-2">
111
- <a href="/sessions" class="btn btn-outline-primary">
112
- <i class="bi bi-list-task"></i> View All Sessions
113
- </a>
114
- <a href="/protocols" class="btn btn-outline-primary">
115
- <i class="bi bi-diagram-3"></i> Browse Protocols
116
- </a>
117
- </div>
118
- </div>
94
+ <!-- Recent Sessions -->
95
+ <div class="card mt-4">
96
+ <div class="card-body">
97
+ <h5 class="card-title mb-3"><i class="bi bi-clock-history"></i> Quick Actions</h5>
98
+ <div class="d-grid gap-2">
99
+ <a href="/sessions" class="btn btn-outline-primary"> <i class="bi bi-list-task"></i> View All Sessions </a>
100
+ <a href="/protocols" class="btn btn-outline-primary"> <i class="bi bi-diagram-3"></i> Browse Protocols </a>
119
101
  </div>
102
+ </div>
120
103
  </div>
104
+ </div>
121
105
  </div>
122
- {% endblock %}
123
-
124
- {% block extra_scripts %}
106
+ {% endblock %} {% block extra_scripts %}
125
107
  <script>
126
- const dropzone = document.getElementById('dropzone');
127
- const fileInput = document.getElementById('fileInput');
128
- const fileInfo = document.getElementById('fileInfo');
129
- const fileName = document.getElementById('fileName');
130
- const fileSize = document.getElementById('fileSize');
131
- const uploadForm = document.getElementById('uploadForm');
132
- const progressContainer = document.getElementById('progressContainer');
133
- const progressBar = document.getElementById('progressBar');
134
- const progressText = document.getElementById('progressText');
135
- const analyzeBtn = document.getElementById('analyzeBtn');
136
-
137
- // Dropzone click
138
- dropzone.addEventListener('click', () => fileInput.click());
139
-
140
- // Drag and drop
141
- dropzone.addEventListener('dragover', (e) => {
142
- e.preventDefault();
143
- dropzone.classList.add('drag-over');
144
- });
145
-
146
- dropzone.addEventListener('dragleave', () => {
147
- dropzone.classList.remove('drag-over');
148
- });
149
-
150
- dropzone.addEventListener('drop', (e) => {
151
- e.preventDefault();
152
- dropzone.classList.remove('drag-over');
153
-
154
- const files = e.dataTransfer.files;
155
- if (files.length > 0) {
156
- fileInput.files = files;
157
- updateFileInfo(files[0]);
158
- }
159
- });
160
-
161
- // File selection
162
- fileInput.addEventListener('change', (e) => {
163
- const file = e.target.files[0];
164
- if (file) {
165
- updateFileInfo(file);
166
- }
167
- });
168
-
169
- function updateFileInfo(file) {
170
- fileName.textContent = file.name;
171
- fileSize.textContent = formatFileSize(file.size);
172
- fileInfo.classList.remove('d-none');
108
+ const dropzone = document.getElementById('dropzone');
109
+ const fileInput = document.getElementById('fileInput');
110
+ const fileInfo = document.getElementById('fileInfo');
111
+ const fileName = document.getElementById('fileName');
112
+ const fileSize = document.getElementById('fileSize');
113
+ const uploadForm = document.getElementById('uploadForm');
114
+ const progressContainer = document.getElementById('progressContainer');
115
+ const progressBar = document.getElementById('progressBar');
116
+ const progressText = document.getElementById('progressText');
117
+ const analyzeBtn = document.getElementById('analyzeBtn');
118
+
119
+ // Dropzone click
120
+ dropzone.addEventListener('click', () => fileInput.click());
121
+
122
+ // Drag and drop
123
+ dropzone.addEventListener('dragover', (e) => {
124
+ e.preventDefault();
125
+ dropzone.classList.add('drag-over');
126
+ });
127
+
128
+ dropzone.addEventListener('dragleave', () => {
129
+ dropzone.classList.remove('drag-over');
130
+ });
131
+
132
+ dropzone.addEventListener('drop', (e) => {
133
+ e.preventDefault();
134
+ dropzone.classList.remove('drag-over');
135
+
136
+ const files = e.dataTransfer.files;
137
+ if (files.length > 0) {
138
+ fileInput.files = files;
139
+ updateFileInfo(files[0]);
173
140
  }
141
+ });
174
142
 
175
- function formatFileSize(bytes) {
176
- if (bytes < 1024) return bytes + ' B';
177
- if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(2) + ' KB';
178
- return (bytes / (1024 * 1024)).toFixed(2) + ' MB';
143
+ // File selection
144
+ fileInput.addEventListener('change', (e) => {
145
+ const file = e.target.files[0];
146
+ if (file) {
147
+ updateFileInfo(file);
148
+ }
149
+ });
150
+
151
+ function updateFileInfo(file) {
152
+ fileName.textContent = file.name;
153
+ fileSize.textContent = formatFileSize(file.size);
154
+ fileInfo.classList.remove('d-none');
155
+ }
156
+
157
+ function formatFileSize(bytes) {
158
+ if (bytes < 1024) return bytes + ' B';
159
+ if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(2) + ' KB';
160
+ return (bytes / (1024 * 1024)).toFixed(2) + ' MB';
161
+ }
162
+
163
+ // Form submission
164
+ uploadForm.addEventListener('submit', async (e) => {
165
+ e.preventDefault();
166
+
167
+ const file = fileInput.files[0];
168
+ if (!file) {
169
+ alert('Please select a file first');
170
+ return;
179
171
  }
180
172
 
181
- // Form submission
182
- uploadForm.addEventListener('submit', async (e) => {
183
- e.preventDefault();
184
-
185
- const file = fileInput.files[0];
186
- if (!file) {
187
- alert('Please select a file first');
188
- return;
189
- }
190
-
191
- // Show progress
192
- progressContainer.classList.remove('d-none');
193
- analyzeBtn.disabled = true;
194
- progressBar.style.width = '10%';
195
- progressText.textContent = 'Uploading file...';
196
-
197
- // Create form data
198
- const formData = new FormData();
199
- formData.append('file', file);
200
- formData.append('protocol_hint', document.getElementById('protocolHint').value);
201
- formData.append('auto_crc', document.getElementById('autoCRC').checked);
202
- formData.append('detect_crypto', document.getElementById('detectCrypto').checked);
203
- formData.append('generate_tests', document.getElementById('generateTests').checked);
204
-
205
- try {
206
- // Upload file
207
- const response = await fetch('/api/upload', {
208
- method: 'POST',
209
- body: formData
210
- });
211
-
212
- if (!response.ok) {
213
- throw new Error('Upload failed');
214
- }
215
-
216
- const data = await response.json();
217
- const sessionId = data.session_id;
218
-
219
- // Update progress
220
- progressBar.style.width = '30%';
221
- progressText.textContent = 'Analysis started...';
222
-
223
- // Connect WebSocket for real-time updates
224
- const ws = new WebSocket(`ws://${window.location.host}/ws/${sessionId}`);
225
-
226
- ws.onmessage = (event) => {
227
- const update = JSON.parse(event.data);
228
-
229
- if (update.type === 'status') {
230
- progressBar.style.width = update.progress + '%';
231
- progressText.textContent = update.message;
232
-
233
- if (update.status === 'complete') {
234
- setTimeout(() => {
235
- window.location.href = `/session/${sessionId}`;
236
- }, 1000);
237
- }
238
- } else if (update.type === 'error') {
239
- progressBar.classList.add('bg-danger');
240
- progressText.textContent = 'Error: ' + update.message;
241
- analyzeBtn.disabled = false;
242
- }
243
- };
244
-
245
- ws.onerror = () => {
246
- // Fallback to polling if WebSocket fails
247
- pollSessionStatus(sessionId);
248
- };
249
-
250
- } catch (error) {
251
- alert('Upload failed: ' + error.message);
252
- progressContainer.classList.add('d-none');
253
- analyzeBtn.disabled = false;
173
+ // Show progress
174
+ progressContainer.classList.remove('d-none');
175
+ analyzeBtn.disabled = true;
176
+ progressBar.style.width = '10%';
177
+ progressText.textContent = 'Uploading file...';
178
+
179
+ // Create form data
180
+ const formData = new FormData();
181
+ formData.append('file', file);
182
+ formData.append('protocol_hint', document.getElementById('protocolHint').value);
183
+ formData.append('auto_crc', document.getElementById('autoCRC').checked);
184
+ formData.append('detect_crypto', document.getElementById('detectCrypto').checked);
185
+ formData.append('generate_tests', document.getElementById('generateTests').checked);
186
+
187
+ try {
188
+ // Upload file
189
+ const response = await fetch('/api/upload', {
190
+ method: 'POST',
191
+ body: formData,
192
+ });
193
+
194
+ if (!response.ok) {
195
+ throw new Error('Upload failed');
196
+ }
197
+
198
+ const data = await response.json();
199
+ const sessionId = data.session_id;
200
+
201
+ // Update progress
202
+ progressBar.style.width = '30%';
203
+ progressText.textContent = 'Analysis started...';
204
+
205
+ // Connect WebSocket for real-time updates
206
+ const ws = new WebSocket(`ws://${window.location.host}/ws/${sessionId}`);
207
+
208
+ ws.onmessage = (event) => {
209
+ const update = JSON.parse(event.data);
210
+
211
+ if (update.type === 'status') {
212
+ progressBar.style.width = update.progress + '%';
213
+ progressText.textContent = update.message;
214
+
215
+ if (update.status === 'complete') {
216
+ setTimeout(() => {
217
+ window.location.href = `/session/${sessionId}`;
218
+ }, 1000);
219
+ }
220
+ } else if (update.type === 'error') {
221
+ progressBar.classList.add('bg-danger');
222
+ progressText.textContent = 'Error: ' + update.message;
223
+ analyzeBtn.disabled = false;
254
224
  }
255
- });
256
-
257
- // Fallback polling function
258
- async function pollSessionStatus(sessionId) {
259
- const interval = setInterval(async () => {
260
- try {
261
- const response = await fetch(`/api/session/${sessionId}/status`);
262
- const data = await response.json();
263
-
264
- progressText.textContent = `Status: ${data.status}`;
265
-
266
- if (data.status === 'complete') {
267
- clearInterval(interval);
268
- progressBar.style.width = '100%';
269
- setTimeout(() => {
270
- window.location.href = `/session/${sessionId}`;
271
- }, 1000);
272
- } else if (data.status === 'error') {
273
- clearInterval(interval);
274
- progressBar.classList.add('bg-danger');
275
- progressText.textContent = 'Error: ' + data.error;
276
- analyzeBtn.disabled = false;
277
- }
278
- } catch (error) {
279
- console.error('Poll error:', error);
280
- }
281
- }, 2000);
225
+ };
226
+
227
+ ws.onerror = () => {
228
+ // Fallback to polling if WebSocket fails
229
+ pollSessionStatus(sessionId);
230
+ };
231
+ } catch (error) {
232
+ alert('Upload failed: ' + error.message);
233
+ progressContainer.classList.add('d-none');
234
+ analyzeBtn.disabled = false;
282
235
  }
236
+ });
237
+
238
+ // Fallback polling function
239
+ async function pollSessionStatus(sessionId) {
240
+ const interval = setInterval(async () => {
241
+ try {
242
+ const response = await fetch(`/api/session/${sessionId}/status`);
243
+ const data = await response.json();
244
+
245
+ progressText.textContent = `Status: ${data.status}`;
246
+
247
+ if (data.status === 'complete') {
248
+ clearInterval(interval);
249
+ progressBar.style.width = '100%';
250
+ setTimeout(() => {
251
+ window.location.href = `/session/${sessionId}`;
252
+ }, 1000);
253
+ } else if (data.status === 'error') {
254
+ clearInterval(interval);
255
+ progressBar.classList.add('bg-danger');
256
+ progressText.textContent = 'Error: ' + data.error;
257
+ analyzeBtn.disabled = false;
258
+ }
259
+ } catch (error) {
260
+ console.error('Poll error:', error);
261
+ }
262
+ }, 2000);
263
+ }
283
264
  </script>
284
265
  {% endblock %}
@@ -1,58 +1,54 @@
1
- {% extends "base.html" %}
2
-
3
- {% block title %}Protocols - {{ title }}{% endblock %}
4
-
5
- {% block content %}
1
+ {% extends "base.html" %} {% block title %}Protocols - {{ title }}{% endblock %} {% block content %}
6
2
  <div class="row">
7
- <div class="col-12">
8
- <div class="card">
9
- <div class="card-body">
10
- <h1 class="card-title mb-4">
11
- <i class="bi bi-diagram-3"></i> Discovered Protocols
12
- </h1>
13
-
14
- {% if protocols %}
15
- <div class="row">
16
- {% for protocol in protocols %}
17
- <div class="col-md-6 col-lg-4 mb-4">
18
- <div class="card h-100">
19
- <div class="card-body">
20
- <h5 class="card-title">{{ protocol.protocol_name }}</h5>
21
- <p class="text-muted small">{{ protocol.filename }}</p>
22
-
23
- <div class="mb-2">
24
- <strong>Confidence:</strong>
25
- <div class="progress" style="height: 20px;">
26
- <div class="progress-bar" role="progressbar"
27
- style="width: {{ (protocol.confidence * 100)|round }}%"
28
- aria-valuenow="{{ (protocol.confidence * 100)|round }}"
29
- aria-valuemin="0" aria-valuemax="100">
30
- {{ (protocol.confidence * 100)|round(1) }}%
31
- </div>
32
- </div>
33
- </div>
3
+ <div class="col-12">
4
+ <div class="card">
5
+ <div class="card-body">
6
+ <h1 class="card-title mb-4"><i class="bi bi-diagram-3"></i> Discovered Protocols</h1>
34
7
 
35
- <p class="mb-1"><strong>Messages:</strong> {{ protocol.message_count }}</p>
36
- <p class="mb-3"><strong>Fields:</strong> {{ protocol.field_count }}</p>
8
+ {% if protocols %}
9
+ <div class="row">
10
+ {% for protocol in protocols %}
11
+ <div class="col-md-6 col-lg-4 mb-4">
12
+ <div class="card h-100">
13
+ <div class="card-body">
14
+ <h5 class="card-title">{{ protocol.protocol_name }}</h5>
15
+ <p class="text-muted small">{{ protocol.filename }}</p>
37
16
 
38
- <a href="/session/{{ protocol.session_id }}" class="btn btn-primary btn-sm">
39
- <i class="bi bi-eye"></i> View Details
40
- </a>
41
- </div>
42
- <div class="card-footer text-muted small">
43
- {{ protocol.created_at[:19] }}
44
- </div>
45
- </div>
17
+ <div class="mb-2">
18
+ <strong>Confidence:</strong>
19
+ <div class="progress" style="height: 20px">
20
+ <div
21
+ class="progress-bar"
22
+ role="progressbar"
23
+ style="width: {{ (protocol.confidence * 100)|round }}%"
24
+ aria-valuenow="{{ (protocol.confidence * 100)|round }}"
25
+ aria-valuemin="0"
26
+ aria-valuemax="100"
27
+ >
28
+ {{ (protocol.confidence * 100)|round(1) }}%
46
29
  </div>
47
- {% endfor %}
30
+ </div>
48
31
  </div>
49
- {% else %}
50
- <div class="alert alert-info">
51
- <i class="bi bi-info-circle"></i> No protocols discovered yet. <a href="/">Upload a file</a> to analyze.
52
- </div>
53
- {% endif %}
32
+
33
+ <p class="mb-1"><strong>Messages:</strong> {{ protocol.message_count }}</p>
34
+ <p class="mb-3"><strong>Fields:</strong> {{ protocol.field_count }}</p>
35
+
36
+ <a href="/session/{{ protocol.session_id }}" class="btn btn-primary btn-sm">
37
+ <i class="bi bi-eye"></i> View Details
38
+ </a>
39
+ </div>
40
+ <div class="card-footer text-muted small">{{ protocol.created_at[:19] }}</div>
54
41
  </div>
42
+ </div>
43
+ {% endfor %}
44
+ </div>
45
+ {% else %}
46
+ <div class="alert alert-info">
47
+ <i class="bi bi-info-circle"></i> No protocols discovered yet. <a href="/">Upload a file</a> to analyze.
55
48
  </div>
49
+ {% endif %}
50
+ </div>
56
51
  </div>
52
+ </div>
57
53
  </div>
58
54
  {% endblock %}