Skip to content

Commit

Permalink
Add: NASL bultin functions for isotime
Browse files Browse the repository at this point in the history
This includes

- isotime_add
- isotime_is_valid
- isotime_now
- isotime_print
- isotime_scan
  • Loading branch information
Kraemii committed Sep 9, 2024
1 parent 9320f9a commit cc5d8a1
Show file tree
Hide file tree
Showing 8 changed files with 290 additions and 1 deletion.
12 changes: 12 additions & 0 deletions rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ members = [
"nasl-builtin-knowledge-base",
"nasl-builtin-raw-ip",
"nasl-builtin-cryptographic",
"nasl-builtin-isotime",
"nasl-builtin-ssh",
"nasl-builtin-http",
"nasl-builtin-host",
Expand Down
16 changes: 16 additions & 0 deletions rust/nasl-builtin-isotime/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "nasl-builtin-isotime"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
nasl-builtin-utils = { path = "../nasl-builtin-utils" }
nasl-function-proc-macro = { path = "../nasl-function-proc-macro" }
nasl-syntax = { path = "../nasl-syntax" }

chrono = "0.4.23"

[dev-dependencies]
nasl-interpreter = { path = "../nasl-interpreter" }
7 changes: 7 additions & 0 deletions rust/nasl-builtin-isotime/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
## Implements

- isotime_add
- isotime_is_valid
- isotime_now
- isotime_print
- isotime_scan
130 changes: 130 additions & 0 deletions rust/nasl-builtin-isotime/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
// SPDX-FileCopyrightText: 2023 Greenbone AG
//
// SPDX-License-Identifier: GPL-2.0-or-later WITH x11vnc-openssl-exception

//! Defines NASL functions regarding isotime.

use chrono::{Datelike, Months, NaiveDate, NaiveDateTime, TimeDelta};
use nasl_builtin_utils::{function_set, FunctionErrorKind};
use nasl_function_proc_macro::nasl_function;

const ISOFORMAT: &str = "yyyymmddThhmmss";
const READABLEFORMAT: &str = "yyyy-mm-dd hh:mm:ss";

fn parse_isotime(time: &str) -> Option<NaiveDateTime> {
NaiveDateTime::parse_from_str(time, "%Y%m%dT%H%M%S").ok()
}

fn parse_readable_time(time: &str) -> Option<NaiveDateTime> {
if let Ok(time) = NaiveDateTime::parse_from_str(time, "%Y-%m-%d %H:%M:%S") {
return Some(time);
}
if let Ok(time) = NaiveDateTime::parse_from_str(time, "%Y-%m-%d %H:%M") {
return Some(time);
}
if let Some((date, hours)) = time.split_once(" ") {
if let Ok(date) = NaiveDate::parse_from_str(date, "%Y-%m-%d") {
if let Ok(hours) = hours.parse::<u32>() {
if let Some(time) = date.and_hms_opt(hours, 0, 0) {
return Some(time);
}
}
}
}
if let Ok(date) = NaiveDate::parse_from_str(time, "%Y-%m-%d") {
// Cannot fail, since we add no time to the date
return Some(date.and_hms_opt(0, 0, 0).unwrap());
}

None
}

fn parse_time(time: &str) -> Result<NaiveDateTime, FunctionErrorKind> {
if let Some(time) = parse_isotime(time) {
return Ok(time);
}
if let Some(time) = parse_readable_time(time) {
return Ok(time);
}
Err(FunctionErrorKind::Diagnostic(
format!(
"The given time is not in the correct isotime ({}) or readable time format ({}): {}",
ISOFORMAT, READABLEFORMAT, time
),
None,
))
}

#[nasl_function(named(years, days, seconds))]
fn isotime_add(
time: &str,
years: Option<i64>,
days: Option<i64>,
seconds: Option<i64>,
) -> Result<String, FunctionErrorKind> {
let mut time = parse_time(time)?;

if let Some(years) = years {
if years < 0 {
time = time - Months::new((-years) as u32 * 12);
} else {
time = time + Months::new(years as u32 * 12);
}
}

if let Some(days) = days {
time += TimeDelta::days(days);
}

if let Some(seconds) = seconds {
time += TimeDelta::seconds(seconds);
}

if time.year() < 0 || time.year() > 9999 {
return Err(FunctionErrorKind::Diagnostic(
format!(
"The resulting year is out of range (0000-9999): {}.",
time.year()
),
None,
));
}

Ok(time.format("%Y%m%dT%H%M%S").to_string())
}

#[nasl_function]
fn isotime_is_valid(time: &str) -> bool {
parse_time(time).is_ok()
}

#[nasl_function]
fn isotime_now() -> String {
chrono::Utc::now().format("%Y%m%dT%H%M%S").to_string()
}

#[nasl_function]
fn isotime_print(time: &str) -> Result<String, FunctionErrorKind> {
Ok(parse_time(time)?.format("%Y-%m-%d %H:%M:%S").to_string())
}

#[nasl_function]
fn isotime_scan(time: &str) -> Result<String, FunctionErrorKind> {
let time = parse_time(time)?;

Ok(time.format("%Y%m%dT%H%M%S").to_string())
}

pub struct NaslIsotime;

function_set! {
NaslIsotime,
sync_stateless,
(
isotime_add,
isotime_is_valid,
isotime_now,
isotime_print,
isotime_scan
)
}
121 changes: 121 additions & 0 deletions rust/nasl-builtin-isotime/tests/isotime.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// SPDX-FileCopyrightText: 2023 Greenbone AG
//
// SPDX-License-Identifier: GPL-2.0-or-later WITH x11vnc-openssl-exception
#[cfg(test)]
mod tests {
use nasl_interpreter::{check_err_matches, test_utils::check_code_result, FunctionErrorKind};

#[test]
fn isotime_is_valid() {
check_code_result("isotime_is_valid(\"\");", false);
check_code_result("isotime_is_valid(\"a8691002T123456\");", false);
check_code_result("isotime_is_valid(\"18691002T123456\");", true);
check_code_result("isotime_is_valid(\"18691002T1234\");", false);
check_code_result("isotime_is_valid(\"18691002T1234512\");", false);
check_code_result("isotime_is_valid(\"1869-10-02 12:34:56\");", true);
check_code_result("isotime_is_valid(\"1869-10-02 12:34\");", true);
check_code_result("isotime_is_valid(\"1869-10-02 12\");", true);
check_code_result("isotime_is_valid(\"1869-10-02\");", true);
check_code_result("isotime_is_valid(\"1869-10-02T12:34:56\");", false);
}

#[test]
fn isotime_scan() {
check_err_matches!("isotime_scan(\"\");", FunctionErrorKind::Diagnostic { .. });
check_err_matches!(
"isotime_scan(\"a8691002T123456\");",
FunctionErrorKind::Diagnostic { .. }
);
check_err_matches!(
"isotime_scan(\"18691002T1234\");",
FunctionErrorKind::Diagnostic { .. }
);
check_err_matches!(
"isotime_scan(\"18691002T1234512\");",
FunctionErrorKind::Diagnostic { .. }
);
check_err_matches!(
"isotime_scan(\"1869-10-02T12:34:56\");",
FunctionErrorKind::Diagnostic { .. }
);

check_code_result("isotime_scan(\"18691002T123456\");", "18691002T123456");
check_code_result("isotime_scan(\"1869-10-02 12:34:56\");", "18691002T123456");
check_code_result("isotime_scan(\"1869-10-02 12:34\");", "18691002T123400");
check_code_result("isotime_scan(\"1869-10-02 12\");", "18691002T120000");
}

#[test]
fn isotime_print() {
check_err_matches!("isotime_print(\"\");", FunctionErrorKind::Diagnostic { .. });
check_err_matches!(
"isotime_print(\"a8691002T123456\");",
FunctionErrorKind::Diagnostic { .. }
);
check_err_matches!(
"isotime_print(\"18691002T1234\");",
FunctionErrorKind::Diagnostic { .. }
);
check_err_matches!(
"isotime_print(\"1869-10-02T12:34:56\");",
FunctionErrorKind::Diagnostic { .. }
);

check_code_result("isotime_print(\"18691002T123456\");", "1869-10-02 12:34:56");
check_code_result("isotime_print(\"18691002T123451\");", "1869-10-02 12:34:51");
check_code_result(
"isotime_print(\"1869-10-02 12:34:56\");",
"1869-10-02 12:34:56",
);
check_code_result(
"isotime_print(\"1869-10-02 12:34\");",
"1869-10-02 12:34:00",
);
check_code_result("isotime_print(\"1869-10-02 12\");", "1869-10-02 12:00:00");
}

#[test]
fn isotime_add() {
check_err_matches!(
"isotime_add(\"\", years: 0);",
FunctionErrorKind::Diagnostic { .. }
);
check_err_matches!(
"isotime_add(\"50001002T120000\", years: 5000);",
FunctionErrorKind::Diagnostic { .. }
);
check_err_matches!(
"isotime_add(\"50001002T120000\", years: -5001);",
FunctionErrorKind::Diagnostic { .. }
);

check_code_result(
"isotime_add(\"20240228T000000\", days: 1);",
"20240229T000000",
);
check_code_result(
"isotime_add(\"20240228T000000\", years: 1);",
"20250228T000000",
);
check_code_result(
"isotime_add(\"20240228T000000\", seconds: 1);",
"20240228T000001",
);
check_code_result(
"isotime_add(\"20240228T000000\", days: -1);",
"20240227T000000",
);
check_code_result(
"isotime_add(\"20240228T000000\", years: -1);",
"20230228T000000",
);
check_code_result(
"isotime_add(\"20240228T000000\", seconds: -1);",
"20240227T235959",
);
check_code_result(
"isotime_add(\"20240228T000000\", years: 1, days: -1, seconds: -1);",
"20250226T235959",
);
}
}
1 change: 1 addition & 0 deletions rust/nasl-builtin-std/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ nasl-builtin-description = { path = "../nasl-builtin-description" }
nasl-builtin-network = { path = "../nasl-builtin-network" }
nasl-builtin-misc = { path = "../nasl-builtin-misc" }
nasl-builtin-regex = { path = "../nasl-builtin-regex" }
nasl-builtin-isotime = { path = "../nasl-builtin-isotime" }
nasl-function-proc-macro = { path = "../nasl-function-proc-macro" }
storage = { path = "../storage" }
models = { path = "../models" }
Expand Down
3 changes: 2 additions & 1 deletion rust/nasl-builtin-std/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ pub fn nasl_std_functions() -> Executor {
.add_set(nasl_builtin_network::network::Network)
.add_set(nasl_builtin_regex::RegularExpressions)
.add_set(nasl_builtin_cryptographic::Cryptographic)
.add_set(nasl_builtin_description::Description);
.add_set(nasl_builtin_description::Description)
.add_set(nasl_builtin_isotime::NaslIsotime);

#[cfg(feature = "nasl-builtin-ssh")]
executor.add_set(nasl_builtin_ssh::Ssh::default());
Expand Down

0 comments on commit cc5d8a1

Please sign in to comment.