use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::fmt::Formatter;
use std::fmt::{Debug, Display};
use std::ops::Deref;
pub struct SecString {
inner: String,
}
impl SecString {
pub const fn new() -> Self {
Self {
inner: String::new(),
}
}
pub fn push(&mut self, val: char) {
self.unlock();
self.inner.push(val);
self.lock();
}
pub fn clear(&mut self) {
self.unlock();
self.zeroize();
self.inner.clear();
self.lock();
}
pub fn insert(&mut self, pos: usize, val: char) {
self.unlock();
self.inner.insert(pos, val);
self.lock();
}
pub fn remove(&mut self, pos: usize) -> char {
self.unlock();
let val = self.inner.remove(pos);
self.lock();
val
}
pub fn into_buffer(mut self) -> String {
self.unlock();
std::mem::take(&mut self.inner)
}
fn lock(&self) {
let (ptr, len) = decompose(&self.inner);
unsafe { crate::misc::mlock(ptr, len) }
}
fn unlock(&self) {
let (ptr, len) = decompose(&self.inner);
unsafe { crate::misc::munlock(ptr, len) }
}
fn zeroize(&mut self) {
unsafe { crate::misc::zeroize(self.inner.as_ptr(), self.inner.len()) }
}
}
impl<T: Into<String>> From<T> for SecString {
fn from(inner: T) -> Self {
let this = Self {
inner: inner.into(),
};
this.lock();
this
}
}
impl Drop for SecString {
fn drop(&mut self) {
self.unlock();
self.zeroize();
}
}
impl Clone for SecString {
fn clone(&self) -> Self {
self.unlock();
let ret = Self::from(self.inner.clone());
self.unlock();
ret
}
}
impl Default for SecString {
fn default() -> Self {
Self::new()
}
}
impl Deref for SecString {
type Target = String;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl Debug for SecString {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "***SECRET***")
}
}
impl Display for SecString {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Debug::fmt(self, f)
}
}
fn decompose(input: &String) -> (*const u8, usize) {
let ptr = input.as_ptr();
let len = input.capacity();
(ptr, len)
}
impl Serialize for SecString {
fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
where
S: Serializer,
{
self.unlock();
let res = serializer.serialize_bytes(self.as_ref());
self.lock();
res
}
}
impl<'de> Deserialize<'de> for SecString {
fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error>
where
D: Deserializer<'de>,
{
Ok(Self::from(String::deserialize(deserializer)?))
}
}