kenobi-windows 0.1.0

A Windows Negotiate implementation.
use std::marker::PhantomData;

use crate::{
    buffer::NonResizableVec,
    client::{
        StepOut,
        error::InitializeContextError,
        typestate::{DelegationPolicy, EncryptionPolicy, SigningPolicy},
    },
    cred::Credentials,
};
use kenobi_core::typestate::{
    DeniedSigning, MaybeDelegation, MaybeEncryption, MaybeSigning, NoDelegation, NoEncryption, NoSigning,
};
use kenobi_core::{channel_bindings::Channel, cred::usage::OutboundUsable};

pub struct ClientBuilder<'cred, Usage, S = NoSigning, E = NoEncryption, D = NoDelegation> {
    cred: &'cred Credentials<Usage>,
    target_principal: Option<Box<[u16]>>,
    channel_bindings: Option<Box<[u8]>>,
    _enc: PhantomData<(S, E, D)>,
}
impl<Usage> ClientBuilder<'_, Usage, NoSigning, NoEncryption, NoDelegation> {
    pub fn new_from_credentials<'cred>(
        cred: &'cred Credentials<Usage>,
        target_principal: Option<&str>,
    ) -> ClientBuilder<'cred, Usage, NoSigning, NoEncryption, NoDelegation> {
        let target_principal = target_principal.map(crate::to_wide);
        ClientBuilder {
            cred,
            target_principal,
            channel_bindings: None,
            _enc: PhantomData,
        }
    }
}
impl<'cred, Usage, S, D> ClientBuilder<'cred, Usage, S, NoEncryption, D> {
    pub fn request_encryption(self) -> ClientBuilder<'cred, Usage, S, MaybeEncryption, D> {
        self.convert_policy()
    }
}
impl<'cred, Usage, E, D> ClientBuilder<'cred, Usage, NoSigning, E, D> {
    pub fn request_signing(self) -> ClientBuilder<'cred, Usage, MaybeSigning, E, D> {
        self.convert_policy()
    }
    pub fn deny_signing(self) -> ClientBuilder<'cred, Usage, DeniedSigning, E, D> {
        self.convert_policy()
    }
}
impl<'cred, Usage, S, E> ClientBuilder<'cred, Usage, S, E, NoDelegation> {
    pub fn allow_delegation(self) -> ClientBuilder<'cred, Usage, S, E, MaybeDelegation> {
        self.convert_policy()
    }
}
impl<'cred, Usage, S1, E1, D1> ClientBuilder<'cred, Usage, S1, E1, D1> {
    fn convert_policy<S2, E2, D2>(self) -> ClientBuilder<'cred, Usage, S2, E2, D2> {
        ClientBuilder {
            cred: self.cred,
            target_principal: self.target_principal,
            channel_bindings: self.channel_bindings,
            _enc: PhantomData,
        }
    }
    pub fn bind_to_channel<C: Channel>(self, channel: &C) -> Result<Self, C::Error> {
        let channel_bindings = channel.channel_bindings()?.map(|v| v.into_boxed_slice());
        Ok(Self {
            channel_bindings,
            ..self
        })
    }
}
impl<'cred, Usage: OutboundUsable, S: SigningPolicy, E: EncryptionPolicy, D: DelegationPolicy>
    ClientBuilder<'cred, Usage, S, E, D>
{
    pub fn initialize(self) -> Result<StepOut<'cred, Usage, S, E, D>, InitializeContextError> {
        match super::step(
            self.cred,
            self.target_principal,
            None,
            0,
            NonResizableVec::new(),
            self.channel_bindings.as_deref(),
            None,
        )? {
            StepOut::Pending(p) => Ok(StepOut::Pending(p)),
            StepOut::Completed(c) => Ok(StepOut::Completed(c)),
        }
    }
}