Initial commit

This commit is contained in:
Philip (a-0) 2023-07-02 20:40:33 +02:00
commit 2fd06a5e83
40 changed files with 1354 additions and 0 deletions

10
src/lib.rs Normal file
View file

@ -0,0 +1,10 @@
macro_rules! expose_submodules {
( $( $x:ident ),* ) => {
$(
mod $x;
pub use self::$x::*;
)*
};
}
pub mod v1;

11
src/v1/mod.rs Normal file
View file

@ -0,0 +1,11 @@
macro_rules! default_derive {
($i:item) => {
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, PartialEq, Debug)]
$i
};
}
mod schemas;
pub use schemas::*;

View file

@ -0,0 +1,11 @@
default_derive!{
pub struct Attribute {
//TODO
}
}
#[test]
fn valid1() {
todo!()
}

View file

@ -0,0 +1,47 @@
use regex_macro::regex;
default_derive!{
pub struct AttributeAttachment {
content: String
}
}
impl TryFrom<&str> for AttributeAttachment {
type Error = &'static str;
fn try_from(value: &str) -> Result<Self, Self::Error> {
let re = regex!("^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$");
if re.is_match(value) {
Ok(AttributeAttachment { content: String::from(value) })
}
else {
Err("Failed to parse AttributeAttachment")
}
}
}
impl Into<String> for AttributeAttachment {
fn into(self) -> String {
self.content
}
}
#[test]
fn forbidden_char() {
let att: Result<AttributeAttachment, _> = "uqiolgfnluiqoegn&".try_into();
println!("{:?}", att);
assert!(att.is_err())
}
#[test]
fn valid1() {
let att: Result<AttributeAttachment, _> = "".try_into();
assert_eq!(att, Ok(AttributeAttachment {content: String::from("")}))
}
#[test]
fn valid2() {
let att: Result<AttributeAttachment, _> = "TWFueSBoYW5kcyBtYWtlIGxpZ2h0IHdvcmsu".try_into();
assert_eq!(att, Ok(AttributeAttachment{content: String::from("TWFueSBoYW5kcyBtYWtlIGxpZ2h0IHdvcmsu")}))
}

View file

@ -0,0 +1,53 @@
use phf::phf_set;
default_derive!{
pub struct AttributeCategory {
cat: String,
}
}
impl TryFrom<&str> for AttributeCategory {
type Error = &'static str;
fn try_from(value: &str) -> Result<Self, Self::Error> {
let valid_categories: phf::Set<&'static str> = phf_set!("Internal reference", "Targeting data", "Antivirus detection", "Payload delivery", "Artifacts dropped", "Payload installation", "Persistence mechanism", "Network activity", "Payload type", "Attribution", "External analysis", "Financial fraud", "Support Tool", "Social network", "Person", "Other");
if value.len() <= 255 && valid_categories.contains(value) {
Ok(AttributeCategory { cat: value.to_string() })
}
else {
Err("Failed to parse AttributeCategory")
}
}
}
impl Into<String> for AttributeCategory {
fn into(self) -> String {
self.cat
}
}
#[test]
fn empty() {
let cat: Result<AttributeCategory, _> = "".try_into();
assert!(cat.is_err())
}
#[test]
fn oversized() {
let cat: Result<AttributeCategory, _> = format!("{:>256}", "Test").as_str().try_into();
assert!(cat.is_err())
}
#[test]
fn valid1() {
let cat: Result<AttributeCategory, _> = "Internal reference".try_into();
assert_eq!(cat, Ok(AttributeCategory { cat: "Internal reference".to_string() }))
}
#[test]
fn valid2() {
let cat: Result<AttributeCategory, _> = "Person".try_into();
assert_eq!(cat, Ok(AttributeCategory {cat: String::from("Person")}))
}

View file

@ -0,0 +1,44 @@
default_derive!{
pub struct AttributeComment {
text: String
}
}
impl TryFrom<&str> for AttributeComment {
type Error = &'static str;
fn try_from(value: &str) -> Result<Self, Self::Error> {
if value.len() <= 65535 {
Ok(AttributeComment { text: value.to_string() })
}
else {
Err("Failed to parse AttributeComment")
}
}
}
impl Into<String> for AttributeComment {
fn into(self) -> String {
self.text
}
}
#[test]
fn oversized() {
let comment: Result<AttributeComment, _> = format!("{:>65536}", "Test").as_str().try_into();
assert!(comment.is_err())
}
#[test]
fn valid1() {
let comment: Result<AttributeComment, _> = "".try_into();
assert_eq!(comment, Ok(AttributeComment { text: "".to_string() }))
}
#[test]
fn valid2() {
let comment: Result<AttributeComment, _> = "Comment".try_into();
assert_eq!(comment, Ok(AttributeComment{text: String::from("Comment")}))
}

View file

@ -0,0 +1,44 @@
use super::UUID;
default_derive!{
pub struct AttributeEventUUID {
uuid: String
}
}
impl TryFrom<&str> for AttributeEventUUID {
type Error = &'static str;
fn try_from(value: &str) -> Result<Self, Self::Error> {
let uuid: Result<UUID, _> = value.try_into();
match uuid {
Ok(id) => Ok(AttributeEventUUID{uuid: id.into()}),
Err(_) => Err("Failed to parse AttributeEventUUID"),
}
}
}
impl Into<String> for AttributeEventUUID {
fn into(self) -> String {
self.uuid
}
}
#[test]
fn empty() {
let uuid: Result<AttributeEventUUID, _> = "".try_into();
assert!(uuid.is_err())
}
#[test]
fn oversized() {
let uuid: Result<AttributeEventUUID, _> = format!("{:>37}", "Test").as_str().try_into();
assert!(uuid.is_err())
}
#[test]
fn valid1() {
let uuid: Result<AttributeEventUUID, _> = "c99506a6-1255-4b71-afa5-7b8ba48c3b1b".try_into();
assert_eq!(uuid, Ok(AttributeEventUUID{ uuid: "c99506a6-1255-4b71-afa5-7b8ba48c3b1b".to_string() }))
}

View file

@ -0,0 +1,57 @@
use regex_macro::regex;
default_derive!{
pub struct AttributeId {
id: String
}
}
impl TryFrom<&str> for AttributeId {
type Error = &'static str;
fn try_from(value: &str) -> Result<Self, Self::Error> {
let re = regex!("^[[:digit:]]+$");
if re.is_match(value) && value.len() <= 10 {
Ok(AttributeId{ id: value.to_string() })
}
else {
Err("Failed to parse AttributeId")
}
}
}
impl Into<String> for AttributeId {
fn into(self) -> String {
self.id
}
}
#[test]
fn empty() {
let id: Result<AttributeId, _> = "".try_into();
assert!(id.is_err())
}
#[test]
fn oversized() {
let id: Result<AttributeId, _> = "12345678910".try_into();
assert!(id.is_err())
}
#[test]
fn forbidden_char() {
let id: Result<AttributeId, _> = "123r5".try_into();
assert!(id.is_err())
}
#[test]
fn valid1() {
let id: Result<AttributeId, _> = "0".try_into();
assert_eq!(id, Ok(AttributeId{id: String::from("0")}))
}
#[test]
fn valid2() {
let id: Result<AttributeId, _> = "123456789".try_into();
assert_eq!(id, Ok(AttributeId{id: String::from("123456789")}));
}

View file

@ -0,0 +1,25 @@
use super::Attribute;
default_derive!{
pub struct AttributeList {
attrs: Vec<Attribute>
}
}
impl From<Vec<Attribute>> for AttributeList {
fn from(value: Vec<Attribute>) -> Self {
AttributeList { attrs: value }
}
}
impl Into<Vec<Attribute>> for AttributeList {
fn into(self) -> Vec<Attribute> {
self.attrs
}
}
#[test]
fn valid1() {
todo!()
}

View file

@ -0,0 +1,11 @@
default_derive!{
pub struct AttributeWithoutId {
//TODO
}
}
#[test]
fn valid1() {
todo!()
}

View file

@ -0,0 +1,11 @@
default_derive!{
pub struct AttributeRestSearchFilter {
//TODO
}
}
#[test]
fn valid1() {
todo!()
}

View file

@ -0,0 +1,25 @@
use super::AttributeRestSearchListItem;
default_derive!{
pub struct AttributeRestSearchList {
items: Vec<AttributeRestSearchListItem>
}
}
impl From<Vec<AttributeRestSearchListItem>> for AttributeRestSearchList {
fn from(value: Vec<AttributeRestSearchListItem>) -> Self {
AttributeRestSearchList { items: value }
}
}
impl Into<Vec<AttributeRestSearchListItem>> for AttributeRestSearchList {
fn into(self) -> Vec<AttributeRestSearchListItem> {
self.items
}
}
#[test]
fn valid1() {
todo!()
}

View file

@ -0,0 +1,11 @@
default_derive!{
pub struct AttributeRestSearchListItem {
//TODO
}
}
#[test]
fn valid1() {
todo!()
}

View file

@ -0,0 +1,11 @@
default_derive!{
pub struct AttributeStatisticsResponse {
stats: Vec<(String, i64)>
}
}
#[test]
fn valid1() {
todo!()
}

View file

@ -0,0 +1,255 @@
use phf::phf_set;
default_derive! {
pub struct AttributeType {
t: String
}
}
impl TryFrom<&str> for AttributeType {
type Error = &'static str;
fn try_from(value: &str) -> Result<Self, Self::Error> {
let valid_types: phf::Set<&'static str> = phf_set!(
"md5",
"sha1",
"sha256",
"filename",
"pdb",
"filename|md5",
"filename|sha1",
"filename|sha256",
"ip-src",
"ip-dst",
"hostname",
"domain",
"domain|ip",
"email",
"email-src",
"eppn",
"email-dst",
"email-subject",
"email-attachment",
"email-body",
"float",
"git-commit-id",
"url",
"http-method",
"user-agent",
"ja3-fingerprint-md5",
"jarm-fingerprint",
"favicon-mmh3",
"hassh-md5",
"hasshserver-md5",
"regkey",
"regkey|value",
"AS",
"snort",
"bro",
"zeek",
"community-id",
"pattern-in-file",
"pattern-in-traffic",
"pattern-in-memory",
"pattern-filename",
"pgp-public-key",
"pgp-private-key",
"yara",
"stix2-pattern",
"sigma",
"gene",
"kusto-query",
"mime-type",
"identity-card-number",
"cookie",
"vulnerability",
"cpe",
"weakness",
"attachment",
"malware-sample",
"link",
"comment",
"text",
"hex",
"other",
"named pipe",
"mutex",
"process-state",
"target-user",
"target-email",
"target-machine",
"target-org",
"target-location",
"target-external",
"btc",
"dash",
"xmr",
"iban",
"bic",
"bank-account-nr",
"aba-rtn",
"bin",
"cc-number",
"prtn",
"phone-number",
"threat-actor",
"campaign-name",
"campaign-id",
"malware-type",
"uri",
"authentihash",
"vhash",
"ssdeep",
"imphash",
"telfhash",
"pehash",
"impfuzzy",
"sha224",
"sha384",
"sha512",
"sha512/224",
"sha512/256",
"sha3-224",
"sha3-256",
"sha3-384",
"sha3-512",
"tlsh",
"cdhash",
"filename|authentihash",
"filename|vhash",
"filename|ssdeep",
"filename|imphash",
"filename|impfuzzy",
"filename|pehash",
"filename|sha224",
"filename|sha384",
"filename|sha512",
"filename|sha512/224",
"filename|sha512/256",
"filename|sha3-224",
"filename|sha3-256",
"filename|sha3-384",
"filename|sha3-512",
"filename|tlsh",
"windows-scheduled-task",
"windows-service-name",
"windows-service-displayname",
"whois-registrant-email",
"whois-registrant-phone",
"whois-registrant-name",
"whois-registrant-org",
"whois-registrar",
"whois-creation-date",
"x509-fingerprint-sha1",
"x509-fingerprint-md5",
"x509-fingerprint-sha256",
"dns-soa-email",
"size-in-bytes",
"counter",
"datetime",
"port",
"ip-dst|port",
"ip-src|port",
"hostname|port",
"mac-address",
"mac-eui-64",
"email-dst-display-name",
"email-src-display-name",
"email-header",
"email-reply-to",
"email-x-mailer",
"email-mime-boundary",
"email-thread-index",
"email-message-id",
"github-username",
"github-repository",
"github-organisation",
"jabber-id",
"twitter-id",
"dkim",
"dkim-signature",
"first-name",
"middle-name",
"last-name",
"full-name",
"date-of-birth",
"place-of-birth",
"gender",
"passport-number",
"passport-country",
"passport-expiration",
"redress-number",
"nationality",
"visa-number",
"issue-date-of-the-visa",
"primary-residence",
"country-of-residence",
"special-service-request",
"frequent-flyer-number",
"travel-details",
"payment-details",
"place-port-of-original-embarkation",
"place-port-of-clearance",
"place-port-of-onward-foreign-destination",
"passenger-name-record-locator-number",
"mobile-application-id",
"chrome-extension-id",
"cortex",
"boolean",
"anonymised"
);
if value.len() <= 100 && valid_types.contains(value) {
Ok(AttributeType {
t: value.to_string(),
})
} else {
Err("Failed to parse AttributeType")
}
}
}
impl Into<String> for AttributeType {
fn into(self) -> String {
self.t
}
}
#[test]
fn empty() {
let t: Result<AttributeType, _> = "".try_into();
assert!(t.is_err())
}
#[test]
fn oversized() {
let t: Result<AttributeType, _> = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvw".try_into();
assert!(t.is_err())
}
#[test]
fn unknown() {
let t: Result<AttributeType, _> = "abcde".try_into();
assert!(t.is_err())
}
#[test]
fn valid1() {
let t: Result<AttributeType, _> = "text".try_into();
assert_eq!(
t,
Ok(AttributeType {
t: "text".to_string()
})
)
}
#[test]
fn valid2() {
let t: Result<AttributeType, _> = "filename|sha512/224".try_into();
assert_eq!(
t,
Ok(AttributeType {
t: "filename|sha512/224".to_string()
})
)
}

View file

@ -0,0 +1,44 @@
default_derive!{
pub struct AttributeValue {
value: String
}
}
impl TryFrom<&str> for AttributeValue {
type Error = &'static str;
fn try_from(value: &str) -> Result<Self, Self::Error> {
if value.len() <= 131071 {
Ok(AttributeValue { value: value.to_string() })
}
else {
Err("Failed to parse AttributeValue")
}
}
}
impl Into<String> for AttributeValue {
fn into(self) -> String {
self.value
}
}
#[test]
fn oversized() {
let val: Result<AttributeValue, _> = format!("{:>131072}", "Test").as_str().try_into();
assert!(val.is_err())
}
#[test]
fn valid1() {
let val: Result<AttributeValue, _> = "".try_into();
assert_eq!(val, Ok(AttributeValue { value: "".to_string() }))
}
#[test]
fn valid2() {
let val: Result<AttributeValue, _> = "123456789".try_into();
assert_eq!(val, Ok(AttributeValue {value: String::from("123456789")}))
}

View file

@ -0,0 +1,17 @@
use super::{FullDecayingModel, DecayingModel};
default_derive!{
pub struct DecayScore {
score: f64,
base_score: f64,
decayed: bool,
decaying_model: DecayingModel,
full_decaying_model: FullDecayingModel,
}
}
#[test]
fn valid1() {
todo!()
}

View file

@ -0,0 +1,13 @@
use super::DecayScore;
default_derive!{
pub struct DecayScoreList {
scores: Vec<DecayScore>
}
}
#[test]
fn valid1() {
todo!()
}

View file

@ -0,0 +1,12 @@
default_derive!{
pub struct DecayingModel {
id: String,
name: String,
}
}
#[test]
fn valid1() {
todo!()
}

View file

@ -0,0 +1,15 @@
default_derive!{
pub struct DecayingModelParameters {
lifetime: f64,
decay_speed: f64,
threshold: f64,
default_base_score: f64,
base_score_config: Vec<(String, f64)>
}
}
#[test]
fn valid1() {
todo!()
}

View file

@ -0,0 +1,16 @@
use super::{AttributeType, AttributeCategory};
default_derive!{
pub struct DescribeAttributeTypesResponse {
sane_defaults: Vec<(AttributeType, (String, i64))>,
types: Vec<AttributeType>,
categories: Vec<AttributeCategory>,
category_type_mappings: Vec<(AttributeCategory, Vec<AttributeType>)>
}
}
#[test]
fn valid1() {
todo!()
}

11
src/v1/schemas/event.rs Normal file
View file

@ -0,0 +1,11 @@
default_derive!{
pub struct Event {
//TODO
}
}
#[test]
fn valid1() {
todo!()
}

View file

@ -0,0 +1,40 @@
use regex_macro::regex;
default_derive!{
pub struct EventAttributeCount {
count: String
}
}
impl TryFrom<&str> for EventAttributeCount {
type Error = &'static str;
fn try_from(value: &str) -> Result<Self, Self::Error> {
let re = regex!("^[[:digit:]]+$");
if re.is_match(value) {
Ok(EventAttributeCount { count: value.to_string() })
}
else {
Err("Failed to parse EventId")
}
}
}
impl Into<String> for EventAttributeCount {
fn into(self) -> String {
self.count
}
}
#[test]
fn empty() {
let id: Result<EventAttributeCount, _> = "".try_into();
assert!(id.is_err())
}
#[test]
fn valid1() {
let id: Result<EventAttributeCount, _> = "12345".try_into();
assert_eq!(id, Ok(EventAttributeCount { count: "12345".to_string() }))
}

View file

@ -0,0 +1,52 @@
use regex_macro::regex;
default_derive!{
pub struct EventId {
id: String,
}
}
impl TryFrom<&str> for EventId {
type Error = &'static str;
fn try_from(value: &str) -> Result<Self, Self::Error> {
let re = regex!("^[[:digit:]]+$");
if value.len() <= 10 && re.is_match(value) {
Ok(EventId { id: value.to_string() })
}
else {
Err("Failed to parse EventId")
}
}
}
impl Into<String> for EventId {
fn into(self) -> String {
self.id
}
}
#[test]
fn empty() {
let id: Result<EventId, _> = "".try_into();
assert!(id.is_err())
}
#[test]
fn oversized() {
let id: Result<EventId, _> = "12345678910".try_into();
assert!(id.is_err())
}
#[test]
fn valid1() {
let id: Result<EventId, _> = "12345".try_into();
assert_eq!(id, Ok(EventId { id: "12345".to_string() }))
}
#[test]
fn valid2() {
let id: Result<EventId, _> = "0123456789".try_into();
assert_eq!(id, Ok(EventId { id: "0123456789".to_string() }))
}

View file

@ -0,0 +1,37 @@
default_derive!{
pub struct EventInfo {
text: String
}
}
impl TryFrom<&str> for EventInfo {
type Error = &'static str;
fn try_from(value: &str) -> Result<Self, Self::Error> {
if value.len() <= 65535 {
Ok(EventInfo { text: value.to_string() })
}
else {
Err("Failed to parse EventInfo")
}
}
}
impl Into<String> for EventInfo {
fn into(self) -> String {
self.text
}
}
#[test]
fn oversized() {
let info: Result<EventInfo, _> = format!("{:>65536}", "Test").as_str().try_into();
assert!(info.is_err())
}
#[test]
fn valid1() {
let info: Result<EventInfo, _> = "Informational text".try_into();
assert_eq!(info, Ok(EventInfo { text: "Informational text".to_string() }))
}

View file

@ -0,0 +1,11 @@
default_derive!{
pub struct EventWithoutId {
//TODO
}
}
#[test]
fn valid1() {
todo!()
}

View file

@ -0,0 +1,11 @@
default_derive!{
pub struct EventOrganisation {
//TODO
}
}
#[test]
fn valid1() {
todo!()
}

View file

@ -0,0 +1,11 @@
default_derive!{
pub struct EventProposalEmailLock {
lock: bool
}
}
#[test]
fn valid1() {
todo!()
}

View file

@ -0,0 +1,11 @@
default_derive!{
pub struct EventReport {
//TODO, not described in OpenAPI documentation
}
}
#[test]
fn valid1() {
assert!(true)
}

View file

@ -0,0 +1,11 @@
default_derive!{
pub struct EventTag {
//TODO
}
}
#[test]
fn valid1() {
todo!()
}

View file

@ -0,0 +1,52 @@
use regex_macro::regex;
default_derive!{
pub struct EventTagId {
id: String
}
}
impl TryFrom<&str> for EventTagId {
type Error = &'static str;
fn try_from(value: &str) -> Result<Self, Self::Error> {
let re = regex!("^[[:digit:]]+$");
if value.len() <= 10 && re.is_match(value) {
Ok(EventTagId { id: value.to_string() })
}
else {
Err("Failed to parse EventTagId")
}
}
}
impl Into<String> for EventTagId {
fn into(self) -> String {
self.id
}
}
#[test]
fn empty() {
let id: Result<EventTagId, _> = "".try_into();
assert!(id.is_err())
}
#[test]
fn oversized() {
let id: Result<EventTagId, _> = "12345678910".try_into();
assert!(id.is_err())
}
#[test]
fn valid1() {
let id: Result<EventTagId, _> = "12345".try_into();
assert_eq!(id, Ok(EventTagId { id: "12345".to_string() }))
}
#[test]
fn valid2() {
let id: Result<EventTagId, _> = "0123456789".try_into();
assert_eq!(id, Ok(EventTagId { id: "0123456789".to_string() }))
}

View file

@ -0,0 +1,25 @@
use super::EventTag;
default_derive!{
pub struct EventTagList {
event_tags: Vec<EventTag>
}
}
impl From<Vec<EventTag>> for EventTagList {
fn from(value: Vec<EventTag>) -> Self {
EventTagList { event_tags: value }
}
}
impl Into<Vec<EventTag>> for EventTagList {
fn into(self) -> Vec<EventTag> {
self.event_tags
}
}
#[test]
fn valid1() {
todo!()
}

View file

@ -0,0 +1,11 @@
default_derive!{
pub struct ExtendedAttribute {
//TODO
}
}
#[test]
fn valid1() {
todo!()
}

View file

@ -0,0 +1,11 @@
default_derive!{
pub struct FullDecayingModel {
//TODO
}
}
#[test]
fn valid1() {
todo!()
}

36
src/v1/schemas/mod.rs Normal file
View file

@ -0,0 +1,36 @@
expose_submodules!(
attribute_attachment,
attribute_category,
attribute_comment,
attribute_event_uuid,
attribute_id,
attribute_list,
attribute_no_id,
attribute_rest_search_filter,
attribute_rest_search_list_item,
attribute_rest_search_list,
attribute_statistics_response,
attribute_type,
attribute_value,
attribute,
decay_score_list,
decay_score,
decaying_model_parameters,
decaying_model,
describe_attribute_types_response,
event_attribute_count,
event_id,
event_info,
event_no_id,
event_organisation,
event_proposal_email_lock,
event_report,
event_tag_id,
event_tag_list,
event_tag,
event,
extended_attribute,
full_decaying_model,
uuid
);

46
src/v1/schemas/uuid.rs Normal file
View file

@ -0,0 +1,46 @@
use regex_macro::regex;
default_derive!{
pub struct UUID {
id: String
}
}
impl TryFrom<&str> for UUID {
type Error = &'static str;
fn try_from(value: &str) -> Result<Self, Self::Error> {
let re = regex!("^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$");
if value.len() <= 36 && re.is_match(value) {
Ok(UUID { id: value.to_string() })
}
else {
Err("Failed to parse UUID")
}
}
}
impl Into<String> for UUID {
fn into(self) -> String {
self.id
}
}
#[test]
fn empty() {
let uuid: Result<UUID, _> = "".try_into();
assert!(uuid.is_err())
}
#[test]
fn oversized() {
let uuid: Result<UUID, _> = format!("{:>37}", "Test").as_str().try_into();
assert!(uuid.is_err())
}
#[test]
fn valid1() {
let uuid: Result<UUID, _> = "c99506a6-1255-4b71-afa5-7b8ba48c3b1b".try_into();
assert_eq!(uuid, Ok(UUID { id: "c99506a6-1255-4b71-afa5-7b8ba48c3b1b".to_string() }))
}