Functional Weave
Code in TypeScript

auth.validate-password-change@1.0.0

impl/rust.rs

2,352 bytes · the Rust implementation · view raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

use super::funejson::Value;  ← the fune runtime: the JSON value the test vectors use; fune build keeps it only where a signature takes one
use super::auth_password_policy_check_password::{check_password, password_policy_from_value};
use super::auth_password_policy_types::PasswordPolicy;

/// A change-password form checked in one call: the current password must be
/// given and correct, the new one must meet the policy and differ from it.
///
/// # Panics
/// Panics on a policy whose numbers make no sense.
pub fn validate_password_change(
    current_password: &str,
    new_password: &str,
    current_password_matches: bool,
    email: &str,
    name: &str,
    policy: &PasswordPolicy,
) -> PasswordChangeCheck {
    let mut fields: Vec<(String, String)> = Vec::new();

    if current_password.is_empty() {
        fields.push(("currentPassword".to_string(), "Enter your current password.".to_string()));
    } else if !current_password_matches {
        fields.push(("currentPassword".to_string(), "That is not your current password.".to_string()));
    }

    // Checked even when empty, so a nonsensical policy always panics.
    let check = check_password(new_password, Some(email), Some(name), policy);
    if new_password.is_empty() {
        fields.push(("newPassword".to_string(), "Enter a new password.".to_string()));
    } else {
        let mut messages: Vec<&str> = check.failures.iter().map(|f| f.message.as_str()).collect();
        if new_password == current_password {
            messages.push("Choose a password that is different from your current one.");
        }
        if !messages.is_empty() {
            fields.push(("newPassword".to_string(), messages.join(" ")));
        }
    }

    PasswordChangeCheck { valid: fields.is_empty(), fields }
}

pub fn password_change_check_to_value(check: &PasswordChangeCheck) -> Value {
    Value::obj(vec![
        ("valid", Value::Bool(check.valid)),
        (
            "fields",
            Value::Obj(check.fields.iter().map(|(k, v)| (k.clone(), Value::str(v))).collect()),
        ),
    ])
}

pub fn fune_vector(args: &[Value]) -> Value {
    // A non-string is an empty field, as in TypeScript and Python.
    let policy = password_policy_from_value(&args[5]);
    password_change_check_to_value(&validate_password_change(
        args[0].as_str(),
        args[1].as_str(),
        args[2].as_bool(),
        args[3].as_str(),
        args[4].as_str(),
        &policy,
    ))
}