`.
- - Enabled SDO-to-SDO relationship creation with basic validation.
- - Supported bundle generation, download, and import with a modal interface.
- - Used Tailwind CSS for styling and Babel for JSX transpilation.
-- **Meta**: ` ` set to `380d42b4-f491-4f8b-b825-df384aafdc08`.
-- **Notes**: Initial implementation lacked SCO nesting constraints and advanced relationship validation. Specific timestamp not provided in history.
-
----
-
-**Notes**:
-- All versions maintain STIX 2.1 compliance, with progressive enhancements to enforce SCO nesting, relationship constraints, and property validation.
-- Timestamps are based on the provided conversation history, with the earliest version lacking a specific time.
-- The changelog assumes all listed `artifact_version_id` values from the history are included; if earlier versions exist, they were not provided.
-- For further details on any version, refer to the corresponding `index.html` artifact.
\ No newline at end of file
diff --git a/CNAME b/CNAME
deleted file mode 100644
index 9d78e48..0000000
--- a/CNAME
+++ /dev/null
@@ -1 +0,0 @@
-stix-generator.gurra.rocks
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index be80c0d..0000000
--- a/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2025 Gustav Alerby
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/README.md b/README.md
deleted file mode 100644
index 92f8d01..0000000
--- a/README.md
+++ /dev/null
@@ -1,160 +0,0 @@
-# STIX Bundle Generator
-
-
-
-The STIX Bundle Generator is a web-based application for creating, importing, editing, and exporting STIX 2.1 bundles containing STIX Cyber-observable Objects (SCOs). Built with React and Tailwind CSS, it provides a user-friendly interface for cybersecurity professionals to manage threat intelligence data in the Structured Threat Information Expression (STIX) format.
-
-## Table of Contents
-- [Purpose](#purpose)
-- [Features](#features)
-- [Installation](#installation)
-- [Usage](#usage)
-- [Contributing](#contributing)
-- [License](#license)
-- [Acknowledgments](#acknowledgments)
-
-## Purpose
-The STIX Bundle Generator simplifies the process of working with STIX 2.1 bundles, enabling users to:
-- Create SCOs (e.g., `email-addr`, `network-traffic`, `file`) with customizable fields.
-- Import existing STIX bundles to view and edit SCOs.
-- Export bundles for use in threat intelligence platforms.
-- Visualize and manage SCOs through an intuitive interface.
-
-This tool is ideal for threat analysts, incident responders, and developers building STIX-compatible applications.
-
-## Features
-- **Supported SCO Types**: 20 STIX 2.1 SCO types, including `artifact`, `autonomous-system`, `domain-name`, `email-addr`, `email-message`, `file`, `ipv4-addr`, `ipv6-addr`, `network-traffic`, `user-account`, `x509-certificate`, and more.
-- **Interactive UI**:
- - Clickable SCO chips for editing, with single-line inputs for primary and additional fields.
- - Aggregated SCO display (e.g., `user-account (2)` for multiple `user-account` SCOs).
- - Modal-based JSON import with a single "Import" button.
-- **Bundle Management**:
- - Generate STIX 2.1 bundles with unique IDs and timestamps.
- - Download bundles as JSON files.
- - Copy bundle JSON to clipboard.
- - Clear all SCOs with a single button.
-- **Customizable Fields**:
- - Primary fields (e.g., `value` for `email-addr`, `protocols` for `network-traffic`) with single-value submission.
- - Additional fields (e.g., `rir`, `is_multipart`, `src_ref`, `dst_ref`) with text, number, or checkbox inputs.
- - Special handling for `x509-certificate` hashes (MD5, SHA-1, SHA-256, SHA-512).
-- **Accessibility**: Non-selectable "Select SCO Type" placeholder and ARIA labels for buttons.
-- **Styling**: Responsive design using Tailwind CSS.
-- **Limitations** (current version):
- - May produce duplicate `email-addr`, `ipv4-addr`, `ipv6-addr` SCOs during import.
- - `from_ref`, `src_ref`, `dst_ref` display IDs (e.g., `email-addr--55555555-...`) instead of resolved values.
- - Potential runtime errors (`openModal`, `downloadBundle`) due to direct `onClick` handlers.
-
-## Installation
-The STIX Bundle Generator is a single-page web application that runs in the browser, requiring no server-side setup.
-
-### Prerequisites
-- A modern web browser (e.g., Chrome, Firefox, Edge).
-- No additional software or dependencies are required, as all libraries are loaded via CDN.
-
-### Steps
-1. **Clone or Download**:
- ```bash
- git clone https://github.com/your-username/stix-bundle-generator.git
- ```
- Alternatively, download the `index.html` file from the repository.
-
-2. **Open in Browser**:
- - Open `index.html` directly in a web browser (e.g., double-click the file or use `file://` protocol).
- - No local server is required, as the app uses CDN-hosted dependencies (React 18.2.0, ReactDOM 18.2.0, Babel Standalone 7.22.9, Tailwind CSS).
-
-3. **Optional: Serve Locally** (for development):
- - Use a local server to avoid CORS issues with file-based access:
- ```bash
- npx http-server
- ```
- - Navigate to `http://localhost:8080/index.html`.
-
-## Usage
-1. **Launch the Application**:
- - Open `index.html` in your browser.
- - The interface displays a "Select SCO Type" dropdown and an "Import" button.
-
-2. **Create an SCO**:
- - Select an SCO type (e.g., `user-account`).
- - Enter the primary field value (e.g., `account_login: user1`) in the single-line input.
- - Fill in additional fields (e.g., `user_id`, `account_type`) if applicable.
- - Click "Add SCO" to add the SCO to "Added SCOs".
- - Repeat to add multiple SCOs; chips show aggregated counts (e.g., `user-account (2)`).
-
-3. **Edit an SCO**:
- - Click a chip in "Added SCOs" (e.g., `user-account (2)`) to edit the last SCO of that type.
- - Update fields and click "Update SCO" or "Cancel".
-
-4. **Remove an SCO**:
- - Click the `×` button on a chip to remove the last SCO of that type.
-
-5. **Import a Bundle**:
- - Click "Import", paste a STIX 2.1 bundle JSON, and click "Submit".
- - SCOs appear as chips in "Added SCOs" (note: duplicates may occur).
-
-6. **Generate and Export**:
- - Click "Generate STIX Bundle" to create a bundle.
- - Use "Download JSON" to save as `stix_bundle.json` or "Copy to Clipboard" to copy the JSON.
- - Click "Clear All SCOs" to reset.
-
-### Example Bundle
-```json
-{
- "type": "bundle",
- "id": "bundle--11111111-1111-1111-1111-111111111111",
- "objects": [
- {
- "type": "email-addr",
- "id": "email-addr--55555555-aaaa-5555-aaaa-555555555555",
- "spec_version": "2.1",
- "value": "user@example.com"
- },
- {
- "type": "email-message",
- "id": "email-message--66666666-aaaa-6666-aaaa-666666666666",
- "spec_version": "2.1",
- "is_multipart": false,
- "date": "2023-01-01T12:34:56Z",
- "from_ref": "email-addr--55555555-aaaa-5555-aaaa-555555555555",
- "subject": "Test Email"
- }
- ]
-}
-```
-
-## Contributing
-Contributions are welcome! To contribute:
-1. **Fork the Repository**:
- ```bash
- git fork https://github.com/your-username/stix-bundle-generator.git
- ```
-2. **Create a Branch**:
- ```bash
- git checkout -b feature/your-feature
- ```
-3. **Make Changes**:
- - Address known issues (e.g., duplicate SCOs, unresolved `from_ref`/`src_ref`/`dst_ref`, runtime errors).
- - Add features (e.g., email/IP validation, confirmation for "Clear All SCOs").
- - Update `CHANGELOG.md` with your changes.
-4. **Test Locally**:
- - Ensure `index.html` runs without errors.
- - Test with sample bundles.
-5. **Submit a Pull Request**:
- - Push your branch and create a PR with a clear description of changes.
- - Reference relevant issues or artifact versions.
-
-### Known Issues
-- Duplicate `email-addr`, `ipv4-addr`, `ipv6-addr` SCOs during import.
-- `from_ref`, `src_ref`, `dst_ref` display IDs instead of values.
-- Potential runtime errors (`openModal`, `downloadBundle`) due to direct `onClick` handlers.
-
-## License
-This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
-
-## Acknowledgments
-- Created by Grok, narrated by gbyx3.
-- Built with [React](https://reactjs.org/), [Tailwind CSS](https://tailwindcss.com/), and [Babel](https://babeljs.io/).
-- Inspired by the need for accessible STIX 2.1 tools in cybersecurity.
-
----
-*Last Updated: May 13, 2025*
\ No newline at end of file
diff --git a/bundles/stix_bundle_bundle--4ea55bac-1713-42d6-b837-636097e71d6d.json b/bundles/stix_bundle_bundle--4ea55bac-1713-42d6-b837-636097e71d6d.json
new file mode 100644
index 0000000..ea6fcac
--- /dev/null
+++ b/bundles/stix_bundle_bundle--4ea55bac-1713-42d6-b837-636097e71d6d.json
@@ -0,0 +1,32 @@
+{
+ "type": "bundle",
+ "id": "bundle--4ea55bac-1713-42d6-b837-636097e71d6d",
+ "objects": [
+ {
+ "type": "indicator",
+ "id": "indicator--7ffb8cdc-efa5-47b5-9a09-6be37a614fa0",
+ "spec_version": "2.1",
+ "created": "2025-06-14T12:24:06.780Z",
+ "modified": "2025-06-14T12:24:06.780Z",
+ "pattern": "IP = \"214.5.6.14\"",
+ "labels": [
+ "C2"
+ ],
+ "valid_from": "2025-06-14T12:24:06.780Z",
+ "description": "Mythic"
+ },
+ {
+ "type": "indicator",
+ "id": "indicator--8305e123-d956-4f7a-b82e-d3df4d759da9",
+ "spec_version": "2.1",
+ "created": "2025-06-14T12:25:05.324Z",
+ "modified": "2025-06-14T12:25:05.324Z",
+ "pattern": "IP = \"40.14.5.13\"",
+ "labels": [
+ "C2"
+ ],
+ "valid_from": "2025-06-14T12:25:05.324Z",
+ "description": "Emotet"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/index.html b/index.html
index ea2318e..b768eee 100644
--- a/index.html
+++ b/index.html
@@ -1,1343 +1,864 @@
-
-
-
- STIX Bundle Generator
-
-
-
-
-
-
-
-
+ if (!currentBundle.objects || !Array.isArray(currentBundle.objects)) {
+ validationResults.errors.push("Bundle must contain an 'objects' array");
+ validationResults.valid = false;
+ }
+
+
+ currentBundle.objects.forEach(obj => {
+ if (obj.type === 'observed-data') {
+ if (!obj.number_observed || obj.number_observed < 1) {
+ validationResults.errors.push(`observed-data ${obj.id} must have number_observed >= 1`);
+ validationResults.valid = false;
+ }
+
+ if (!obj.first_observed || !obj.last_observed) {
+ validationResults.errors.push(`observed-data ${obj.id} must have first_observed and last_observed`);
+ validationResults.valid = false;
+ }
+ }
+ });
+
+ displayValidationResults(validationResults);
+ }
+
+ function displayValidationResults(results) {
+ const container = document.getElementById('bundleValidation');
+
+ let html = '';
+
+ if (results.valid) {
+ html = '✅ Bundle validation passed!
';
+ } else {
+ html = '❌ Bundle validation failed
';
+ }
+
+ if (results.errors.length > 0) {
+ html += '';
+ html += '
Errors: ';
+ results.errors.forEach(error => {
+ html += `
${error}
`;
+ });
+ html += '
';
+ }
+
+ if (results.warnings.length > 0) {
+ html += '';
+ html += '
Warnings: ';
+ results.warnings.forEach(warning => {
+ html += `
${warning}
`;
+ });
+ html += '
';
+ }
+
+ container.innerHTML = html;
+ }
+
+ async function saveBundle() {
+ if (!currentBundle) {
+ showStatus('No bundle to save', 'warning');
+ return;
+ }
+
+ try {
+ const response = await fetch('/api/save-bundle', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify(currentBundle)
+ });
+
+ const result = await response.json();
+
+ if (response.ok) {
+ showStatus(`Bundle saved as ${result.filename}`, 'success');
+ loadBundles();
+ } else {
+ showStatus(`Error saving bundle: ${result.error}`, 'error');
+ }
+ } catch (error) {
+ showStatus(`Error saving bundle: ${error.message}`, 'error');
+ }
+ }
+
+ function exportBundle() {
+ if (!currentBundle) {
+ showStatus('No bundle to export', 'warning');
+ return;
+ }
+
+ const dataStr = JSON.stringify(currentBundle, null, 2);
+ const dataUri = 'data:application/json;charset=utf-8,'+ encodeURIComponent(dataStr);
+
+ const exportFileDefaultName = `stix_bundle_${currentBundle.id}.json`;
+
+ const linkElement = document.createElement('a');
+ linkElement.setAttribute('href', dataUri);
+ linkElement.setAttribute('download', exportFileDefaultName);
+ linkElement.click();
+
+ showStatus('Bundle exported successfully!', 'success');
+ }
+
+ async function loadBundles() {
+ try {
+ const response = await fetch('/api/bundles');
+ const result = await response.json();
+
+ const container = document.getElementById('bundlesList');
+
+ if (result.bundles && result.bundles.length > 0) {
+ container.innerHTML = result.bundles.map(bundle => `
+
+
${bundle.filename}
+
+ ID: ${bundle.id}
+ Objects: ${bundle.objects_count}
+ Created: ${new Date(bundle.created * 1000).toLocaleString()}
+
+
+ `).join('');
+ } else {
+ container.innerHTML = 'No saved bundles
';
+ }
+ } catch (error) {
+ showStatus(`Error loading bundles: ${error.message}`, 'error');
+ }
+ }
+
+ async function loadBundle(filename) {
+ try {
+ const response = await fetch(`/api/bundle/${filename}`);
+ const bundle = await response.json();
+
+ if (response.ok) {
+ currentBundle = bundle;
+ currentObjects = [...bundle.objects];
+ updateObjectsList();
+ document.getElementById('jsonOutput').textContent = JSON.stringify(bundle, null, 2);
+ document.getElementById('validateBtn').disabled = false;
+ document.getElementById('saveBundleBtn').disabled = false;
+ showStatus(`Bundle ${filename} loaded successfully!`, 'success');
+ } else {
+ showStatus(`Error loading bundle: ${bundle.error}`, 'error');
+ }
+ } catch (error) {
+ showStatus(`Error loading bundle: ${error.message}`, 'error');
+ }
+ }
+
+ function clearForm() {
+ document.getElementById('objectType').value = '';
+ document.getElementById('objectForm').innerHTML = '';
+ document.getElementById('addObjectBtn').disabled = true;
+ }
+
+ function showStatus(message, type) {
+ const container = document.getElementById('statusMessage');
+ const statusClass = `status-${type}`;
+
+ container.innerHTML = `${message}
`;
+
+
+ setTimeout(() => {
+ container.innerHTML = '';
+ }, 5000);
+ }
+
+ function generateUUID() {
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
+ const r = Math.random() * 16 | 0;
+ const v = c == 'x' ? r : (r & 0x3 | 0x8);
+ return v.toString(16);
+ });
+ }
+
+
+ document.addEventListener('DOMContentLoaded', function() {
+ loadBundles();
+ });
+
-
+