aura-gui 0.2.2

UI nativa acelerada por GPU para escritorio, Android e iOS, en un solo crate: estilo tipo Tailwind, componentes, sombras, animaciones y agentes de IA. Reposo a cero. Licencia AGPL-3.0 o comercial.
//! Administrador de credenciales de Windows (`CredWriteW`, `CredReadW`, `CredDeleteW`).
//!
//! Una credencial admite 2560 bytes; `secrets` ya reparte los valores largos en trozos menores.

use super::windows::wide;
use std::ffi::c_void;
use std::ptr::null_mut;

#[link(name = "advapi32")]
unsafe extern "system" {
    fn CredWriteW(credential: *const Credential, flags: u32) -> i32;
    fn CredReadW(target: *const u16, kind: u32, flags: u32, credential: *mut *mut Credential) -> i32;
    fn CredDeleteW(target: *const u16, kind: u32, flags: u32) -> i32;
    fn CredFree(buffer: *mut c_void);
}

unsafe extern "system" {
    fn GetLastError() -> u32;
}

/// `CREDENTIALW` de wincred.h.
#[repr(C)]
struct Credential {
    flags: u32,
    kind: u32,
    target_name: *mut u16,
    comment: *mut u16,
    last_written: [u32; 2],
    blob_size: u32,
    blob: *mut u8,
    persist: u32,
    attribute_count: u32,
    attributes: *mut c_void,
    target_alias: *mut u16,
    user_name: *mut u16,
}

const CRED_TYPE_GENERIC: u32 = 1;
const CRED_PERSIST_LOCAL_MACHINE: u32 = 2;
const ERROR_NOT_FOUND: u32 = 1168;

fn target(service: &str, account: &str) -> Vec<u16> {
    wide(format!("{service}/{account}"))
}

fn write_one(target: &[u16], bytes: &[u8]) -> Result<(), String> {
    let user = wide("aura");
    let credential = Credential {
        flags: 0,
        kind: CRED_TYPE_GENERIC,
        target_name: target.as_ptr().cast_mut(),
        comment: null_mut(),
        last_written: [0; 2],
        blob_size: bytes.len() as u32,
        blob: bytes.as_ptr().cast_mut(),
        persist: CRED_PERSIST_LOCAL_MACHINE,
        attribute_count: 0,
        attributes: null_mut(),
        target_alias: null_mut(),
        user_name: user.as_ptr().cast_mut(),
    };
    if unsafe { CredWriteW(&credential, 0) } != 0 {
        Ok(())
    } else {
        Err(format!("CredWriteW falló (error {})", unsafe { GetLastError() }))
    }
}

fn read_one(target: &[u16]) -> Option<Vec<u8>> {
    let mut found: *mut Credential = null_mut();
    if unsafe { CredReadW(target.as_ptr(), CRED_TYPE_GENERIC, 0, &mut found) } == 0 || found.is_null() {
        return None;
    }
    unsafe {
        let credential = &*found;
        let bytes = match credential.blob.is_null() {
            true => Vec::new(),
            false => std::slice::from_raw_parts(credential.blob, credential.blob_size as usize).to_vec(),
        };
        CredFree(found.cast());
        Some(bytes)
    }
}

fn delete_one(target: &[u16]) -> Result<(), String> {
    if unsafe { CredDeleteW(target.as_ptr(), CRED_TYPE_GENERIC, 0) } != 0 {
        return Ok(());
    }
    match unsafe { GetLastError() } {
        ERROR_NOT_FOUND => Ok(()),
        code => Err(format!("CredDeleteW falló (error {code})")),
    }
}

pub fn secret_set(service: &str, account: &str, value: &str) -> Result<(), String> {
    write_one(&target(service, account), value.as_bytes())
}

pub fn secret_get(service: &str, account: &str) -> Option<String> {
    String::from_utf8(read_one(&target(service, account))?).ok()
}

pub fn secret_remove(service: &str, account: &str) -> Result<(), String> {
    delete_one(&target(service, account))
}