Initial commit
This commit is contained in:
commit
2fd06a5e83
40 changed files with 1354 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/target
|
202
Cargo.lock
generated
Normal file
202
Cargo.lock
generated
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aho-corasick"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "1.0.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "misplib"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"phf",
|
||||||
|
"regex-macro",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.18.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf"
|
||||||
|
version = "0.11.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
|
||||||
|
dependencies = [
|
||||||
|
"phf_macros",
|
||||||
|
"phf_shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf_generator"
|
||||||
|
version = "0.11.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0"
|
||||||
|
dependencies = [
|
||||||
|
"phf_shared",
|
||||||
|
"rand",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf_macros"
|
||||||
|
version = "0.11.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b"
|
||||||
|
dependencies = [
|
||||||
|
"phf_generator",
|
||||||
|
"phf_shared",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf_shared"
|
||||||
|
version = "0.11.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b"
|
||||||
|
dependencies = [
|
||||||
|
"siphasher",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.63"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.29"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||||
|
dependencies = [
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex"
|
||||||
|
version = "1.8.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-macro"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "12fa36e7add16db296640bba993a65dae2a0088a8e5cd5f935c8bfbd3710145b"
|
||||||
|
dependencies = [
|
||||||
|
"once_cell",
|
||||||
|
"regex",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.7.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ryu"
|
||||||
|
version = "1.0.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde"
|
||||||
|
version = "1.0.164"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.164"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_json"
|
||||||
|
version = "1.0.99"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3"
|
||||||
|
dependencies = [
|
||||||
|
"itoa",
|
||||||
|
"ryu",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "siphasher"
|
||||||
|
version = "0.3.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.22"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2efbeae7acf4eabd6bcdcbd11c92f45231ddda7539edc7806bd1a04a03b24616"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
|
14
Cargo.toml
Normal file
14
Cargo.toml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
[package]
|
||||||
|
name = "misplib"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
phf = { version = "0.11", default-features = false, features = [ "macros" ] }
|
||||||
|
regex-macro = "0.2.0"
|
||||||
|
serde = { version = "1.0.164", features = ["derive"] }
|
||||||
|
serde_json = "1.0.99"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "misplib"
|
||||||
|
path = "src/lib.rs"
|
18
README.md
Normal file
18
README.md
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# misplib
|
||||||
|
This crate contains all data structures present in the [MISP API](https://www.misp-project.org/openapi/), and accompanying helper functions.
|
||||||
|
|
||||||
|
## Versioning system
|
||||||
|
For every commit in the [main MISP repository](https://github.com/MISP/MISP) which changes the [API definition](https://raw.githubusercontent.com/MISP/MISP/develop/app/webroot/doc/openapi.yaml) a new version of misplib is created. Version numbers are assigned as ascending integers.
|
||||||
|
|
||||||
|
Multiple versions of misplib can be accessed, they are defined in `src/v<version number>/mod.rs`, in this file you can also find the unique commit hash of the MISP repository this version is developed for.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
You can contribute to this project by
|
||||||
|
- adding tests to existing types
|
||||||
|
- proposing a new version if you detected a change in the MISP API
|
||||||
|
- adding helper functions (such as implementations of useful traits etc.)
|
||||||
|
- working on the serialization and deserialization of all types. The goal is to be automatically parse any MISP API object into valid rust misplib objects.
|
||||||
|
- anything else you can think of :)
|
||||||
|
|
||||||
|
## Contact
|
||||||
|
Feel free to discuss and ask questions in https://matrix.to/#/#misplib:a-0.me
|
10
src/lib.rs
Normal file
10
src/lib.rs
Normal 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
11
src/v1/mod.rs
Normal 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::*;
|
11
src/v1/schemas/attribute.rs
Normal file
11
src/v1/schemas/attribute.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
|
||||||
|
default_derive!{
|
||||||
|
pub struct Attribute {
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn valid1() {
|
||||||
|
todo!()
|
||||||
|
}
|
47
src/v1/schemas/attribute_attachment.rs
Normal file
47
src/v1/schemas/attribute_attachment.rs
Normal 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")}))
|
||||||
|
}
|
53
src/v1/schemas/attribute_category.rs
Normal file
53
src/v1/schemas/attribute_category.rs
Normal 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")}))
|
||||||
|
}
|
44
src/v1/schemas/attribute_comment.rs
Normal file
44
src/v1/schemas/attribute_comment.rs
Normal 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")}))
|
||||||
|
}
|
44
src/v1/schemas/attribute_event_uuid.rs
Normal file
44
src/v1/schemas/attribute_event_uuid.rs
Normal 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() }))
|
||||||
|
}
|
57
src/v1/schemas/attribute_id.rs
Normal file
57
src/v1/schemas/attribute_id.rs
Normal 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")}));
|
||||||
|
}
|
25
src/v1/schemas/attribute_list.rs
Normal file
25
src/v1/schemas/attribute_list.rs
Normal 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!()
|
||||||
|
}
|
11
src/v1/schemas/attribute_no_id.rs
Normal file
11
src/v1/schemas/attribute_no_id.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
|
||||||
|
default_derive!{
|
||||||
|
pub struct AttributeWithoutId {
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn valid1() {
|
||||||
|
todo!()
|
||||||
|
}
|
11
src/v1/schemas/attribute_rest_search_filter.rs
Normal file
11
src/v1/schemas/attribute_rest_search_filter.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
|
||||||
|
default_derive!{
|
||||||
|
pub struct AttributeRestSearchFilter {
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn valid1() {
|
||||||
|
todo!()
|
||||||
|
}
|
25
src/v1/schemas/attribute_rest_search_list.rs
Normal file
25
src/v1/schemas/attribute_rest_search_list.rs
Normal 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!()
|
||||||
|
}
|
11
src/v1/schemas/attribute_rest_search_list_item.rs
Normal file
11
src/v1/schemas/attribute_rest_search_list_item.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
|
||||||
|
default_derive!{
|
||||||
|
pub struct AttributeRestSearchListItem {
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn valid1() {
|
||||||
|
todo!()
|
||||||
|
}
|
11
src/v1/schemas/attribute_statistics_response.rs
Normal file
11
src/v1/schemas/attribute_statistics_response.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
|
||||||
|
default_derive!{
|
||||||
|
pub struct AttributeStatisticsResponse {
|
||||||
|
stats: Vec<(String, i64)>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn valid1() {
|
||||||
|
todo!()
|
||||||
|
}
|
255
src/v1/schemas/attribute_type.rs
Normal file
255
src/v1/schemas/attribute_type.rs
Normal 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()
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
44
src/v1/schemas/attribute_value.rs
Normal file
44
src/v1/schemas/attribute_value.rs
Normal 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")}))
|
||||||
|
}
|
17
src/v1/schemas/decay_score.rs
Normal file
17
src/v1/schemas/decay_score.rs
Normal 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!()
|
||||||
|
}
|
13
src/v1/schemas/decay_score_list.rs
Normal file
13
src/v1/schemas/decay_score_list.rs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
use super::DecayScore;
|
||||||
|
|
||||||
|
|
||||||
|
default_derive!{
|
||||||
|
pub struct DecayScoreList {
|
||||||
|
scores: Vec<DecayScore>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn valid1() {
|
||||||
|
todo!()
|
||||||
|
}
|
12
src/v1/schemas/decaying_model.rs
Normal file
12
src/v1/schemas/decaying_model.rs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
default_derive!{
|
||||||
|
pub struct DecayingModel {
|
||||||
|
id: String,
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn valid1() {
|
||||||
|
todo!()
|
||||||
|
}
|
15
src/v1/schemas/decaying_model_parameters.rs
Normal file
15
src/v1/schemas/decaying_model_parameters.rs
Normal 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!()
|
||||||
|
}
|
16
src/v1/schemas/describe_attribute_types_response.rs
Normal file
16
src/v1/schemas/describe_attribute_types_response.rs
Normal 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
11
src/v1/schemas/event.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
|
||||||
|
default_derive!{
|
||||||
|
pub struct Event {
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn valid1() {
|
||||||
|
todo!()
|
||||||
|
}
|
40
src/v1/schemas/event_attribute_count.rs
Normal file
40
src/v1/schemas/event_attribute_count.rs
Normal 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() }))
|
||||||
|
}
|
52
src/v1/schemas/event_id.rs
Normal file
52
src/v1/schemas/event_id.rs
Normal 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() }))
|
||||||
|
}
|
37
src/v1/schemas/event_info.rs
Normal file
37
src/v1/schemas/event_info.rs
Normal 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() }))
|
||||||
|
}
|
11
src/v1/schemas/event_no_id.rs
Normal file
11
src/v1/schemas/event_no_id.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
|
||||||
|
default_derive!{
|
||||||
|
pub struct EventWithoutId {
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn valid1() {
|
||||||
|
todo!()
|
||||||
|
}
|
11
src/v1/schemas/event_organisation.rs
Normal file
11
src/v1/schemas/event_organisation.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
|
||||||
|
default_derive!{
|
||||||
|
pub struct EventOrganisation {
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn valid1() {
|
||||||
|
todo!()
|
||||||
|
}
|
11
src/v1/schemas/event_proposal_email_lock.rs
Normal file
11
src/v1/schemas/event_proposal_email_lock.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
|
||||||
|
default_derive!{
|
||||||
|
pub struct EventProposalEmailLock {
|
||||||
|
lock: bool
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn valid1() {
|
||||||
|
todo!()
|
||||||
|
}
|
11
src/v1/schemas/event_report.rs
Normal file
11
src/v1/schemas/event_report.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
|
||||||
|
default_derive!{
|
||||||
|
pub struct EventReport {
|
||||||
|
//TODO, not described in OpenAPI documentation
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn valid1() {
|
||||||
|
assert!(true)
|
||||||
|
}
|
11
src/v1/schemas/event_tag.rs
Normal file
11
src/v1/schemas/event_tag.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
|
||||||
|
default_derive!{
|
||||||
|
pub struct EventTag {
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn valid1() {
|
||||||
|
todo!()
|
||||||
|
}
|
52
src/v1/schemas/event_tag_id.rs
Normal file
52
src/v1/schemas/event_tag_id.rs
Normal 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() }))
|
||||||
|
}
|
25
src/v1/schemas/event_tag_list.rs
Normal file
25
src/v1/schemas/event_tag_list.rs
Normal 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!()
|
||||||
|
}
|
11
src/v1/schemas/extended_attribute.rs
Normal file
11
src/v1/schemas/extended_attribute.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
|
||||||
|
default_derive!{
|
||||||
|
pub struct ExtendedAttribute {
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn valid1() {
|
||||||
|
todo!()
|
||||||
|
}
|
11
src/v1/schemas/full_decaying_model.rs
Normal file
11
src/v1/schemas/full_decaying_model.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
|
||||||
|
default_derive!{
|
||||||
|
pub struct FullDecayingModel {
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn valid1() {
|
||||||
|
todo!()
|
||||||
|
}
|
36
src/v1/schemas/mod.rs
Normal file
36
src/v1/schemas/mod.rs
Normal 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
46
src/v1/schemas/uuid.rs
Normal 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() }))
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue