Skip to content

Commit

Permalink
Initialize first version, with test
Browse files Browse the repository at this point in the history
  • Loading branch information
dannywillems committed Nov 27, 2024
1 parent bbf0a5d commit ee58a22
Show file tree
Hide file tree
Showing 6 changed files with 373 additions and 0 deletions.
26 changes: 26 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Rust

on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]

env:
CARGO_TERM_COLOR: always

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build
run: make release
- name: Run tests
run: make test-all
- name: Generate doc
run: make test-doc
- name: Clippy
run: make lint
- name: Generate doc
run: make generate-doc
9 changes: 9 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "l9event"
version = "0.1.0"
edition = "2021"

[dependencies]
serde = { version = "*", features = ["derive"] }
serde_json = "*"
chrono = { version = "*", features = ["serde"] }
38 changes: 38 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Clean the project
clean:
cargo clean

# Build the project
build:
cargo build --all-targets --all-features

# Build the project in release mode
release:
cargo build --release --all-targets --all-features

# Test the project's docs comments
test-doc:
cargo test --all-features --release --doc

# Test the project with all tests and using native cargo test runner
test-all:
cargo test --all-features --release $(CARGO_EXTRA_ARGS) -- --nocapture $(BIN_EXTRA_ARGS)

# Format the code
format:
cargo +nightly fmt -- --check

# Lint the code
lint:
cargo clippy --all-features --all-targets --tests $(CARGO_EXTRA_ARGS) -- -W clippy::all -D warnings

generate-doc:
@echo ""
@echo "Generating the documentation."
@echo ""
RUSTDOCFLAGS="-D warnings" cargo doc --all-features --no-deps
@echo ""
@echo "The documentation is available at: ./target/doc"
@echo ""

.PHONY: all clean build release test-doc test-all format lint generate-doc
157 changes: 157 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

pub const SEVERITY_CRITICAL: &str = "critical";
pub const SEVERITY_HIGH: &str = "high";
pub const SEVERITY_MEDIUM: &str = "medium";
pub const SEVERITY_LOW: &str = "low";
pub const SEVERITY_INFO: &str = "info";

pub const STAGE_OPEN: &str = "open";
pub const STAGE_EXPLORE: &str = "explore";
pub const STAGE_EXFILTRATE: &str = "exfiltrate";

#[derive(Debug, Serialize, Deserialize)]
pub struct L9Event {
pub event_type: String,
pub event_source: String,
pub event_pipeline: Vec<String>,
pub event_fingerprint: String,
pub ip: String,
pub host: String,
pub reverse: String,
pub port: String,
pub mac: String,
pub vendor: String,
#[serde(rename = "transport")]
pub transports: Vec<String>,
pub protocol: String,
pub http: L9HttpEvent,
pub summary: String,
pub time: DateTime<Utc>,
pub ssl: L9SSLEvent,
pub ssh: L9SSHEvent,
pub service: L9ServiceEvent,
pub leak: L9LeakEvent,
pub tags: Vec<String>,
pub geoip: GeoLocation,
pub network: Network,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct L9HttpEvent {
pub root: String,
pub url: String,
pub status: i32,
pub length: i64,
#[serde(rename = "header")]
pub headers: HashMap<String, String>,
pub title: String,
pub favicon_hash: String,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct L9ServiceEvent {
pub credentials: ServiceCredentials,
pub software: Software,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct L9SSHEvent {
pub fingerprint: String,
pub version: i32,
pub banner: String,
pub motd: String,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct L9LeakEvent {
pub stage: String,
#[serde(rename = "type")]
pub event_type: String,
pub severity: String,
pub dataset: DatasetSummary,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct L9SSLEvent {
pub detected: bool,
pub enabled: bool,
pub jarm: String,
pub cypher_suite: String,
pub version: String,
pub certificate: Certificate,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct DatasetSummary {
pub rows: i64,
pub files: i64,
pub size: i64,
pub collections: i64,
pub infected: bool,
pub ransom_notes: Vec<String>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Software {
pub name: String,
pub version: String,
pub operating_system: Option<String>,
pub modules: Vec<SoftwareModule>,
pub fingerprint: String,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct SoftwareModule {
pub name: String,
pub version: String,
pub fingerprint: String,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct ServiceCredentials {
pub noauth: bool,
pub username: String,
pub password: String,
pub key: String,
pub raw: Option<String>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Certificate {
pub cn: String,
pub domain: Vec<String>,
pub fingerprint: String,
pub key_algo: String,
pub key_size: i32,
pub issuer_name: String,
pub not_before: DateTime<Utc>,
pub not_after: DateTime<Utc>,
pub valid: bool,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct GeoLocation {
pub continent_name: Option<String>,
pub region_iso_code: Option<String>,
pub city_name: Option<String>,
pub country_iso_code: Option<String>,
pub country_name: Option<String>,
pub region_name: Option<String>,
pub location: Option<GeoPoint>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct GeoPoint {
pub lat: f64,
pub lon: f64,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Network {
pub organization_name: String,
pub asn: i32,
pub network: String,
}
123 changes: 123 additions & 0 deletions tests/data/sample_event.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
{
"event_type": "leak",
"event_source": "DotEnvConfigPlugin",
"event_pipeline": [
"ip4scout",
"l9tcpid",
"l9explore",
"DotEnvConfigPlugin"
],
"event_fingerprint": "ab2848eed8451d0ea0d48a691126d1aeab2848eed8451d0ea0d48a691126d1ae",
"ip": "127.0.0.1",
"host": "site1.example.com",
"reverse": "ptr1.example.com",
"port": "8080",
"mac": "",
"vendor": "",
"transport": [
"tcp",
"tls",
"http"
],
"protocol": "https",
"http": {
"root": "/site1",
"url": "/site1/.env",
"status": 200,
"length": 12423,
"header": {
"Content-Type": "application/text",
"Server": "Apache"
},
"title": "Apache welcome page",
"favicon_hash": "e7bc546316d2d0ec13a2d3117b13468f5e939f95"
},
"summary": "GET /... qwerqwer",
"time": "0001-01-01T00:00:00Z",
"ssl": {
"detected": true,
"enabled": true,
"jarm": "29d29d00029d29d21c41d41d00041dba71dd2df645850cf5f0b5af18a5fdcf",
"cypher_suite": "TLS_AES_128_GCM_SHA256",
"version": "TLSv1.3",
"certificate": {
"cn": "example.com",
"domain": [
"site.example.com",
"admin.example.com"
],
"fingerprint": "e998e371dd4678c9113e196bc5e4a5e901455750c6dbc9985c84403b91055260",
"key_algo": "RSA",
"key_size": 2048,
"issuer_name": "Rapid SSL",
"not_before": "0001-01-01T00:00:00Z",
"not_after": "0001-01-01T00:00:00Z",
"valid": false
}
},
"ssh": {
"fingerprint": "",
"version": 0,
"banner": "",
"motd": ""
},
"service": {
"credentials": {
"noauth": true,
"username": "",
"password": "",
"key": "",
"raw": "SSBhbSBhIGtleQo="
},
"software": {
"name": "Apache",
"version": "2.2.4",
"os": "Ubuntu",
"modules": [
{
"name": "PHP",
"version": "4.4.2",
"fingerprint": "php-4-4-2"
}
],
"fingerprint": "apache-2-2-4"
}
},
"leak": {
"stage": "open",
"type": "configuration",
"severity": "medium",
"dataset": {
"rows": 4,
"files": 1,
"size": 13223,
"collections": 1,
"infected": false,
"ransom_notes": [
"Do this",
"Don't do that",
"We love GDPR"
]
}
},
"tags": [
"plc"
],
"geoip": {
"continent_name": "",
"region_iso_code": "",
"city_name": "",
"country_iso_code": "",
"country_name": "",
"region_name": "",
"location": {
"lat": 0,
"lon": 0
}
},
"network": {
"organization_name": "",
"asn": 0,
"network": ""
}
}
20 changes: 20 additions & 0 deletions tests/test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use l9event::L9Event;
use std::fs;

#[test]
fn test_deserialize_l9event_from_file() {
// Path to the JSON file
let file_path = "tests/data/sample_event.json";

// Read the JSON file
let json_content = fs::read_to_string(file_path).expect("Failed to read the JSON file");
// Deserialize into L9Event
let event: L9Event =
serde_json::from_str(&json_content).expect("Failed to deserialize the JSON content");

// Verify some fields (adjust based on the actual file contents)
assert_eq!(event.event_type, "leak");
assert_eq!(event.host, "site1.example.com");
assert_eq!(event.ip, "127.0.0.1");
assert_eq!(event.http.status, 200);
}

0 comments on commit ee58a22

Please sign in to comment.