mirror of
https://github.com/trussed-dev/piv-authenticator.git
synced 2026-06-20 04:16:15 -07:00
Remove trussed from the persistent state
This commit is contained in:
+27
-29
@@ -115,18 +115,19 @@ where
|
||||
pub fn login(&mut self, login: commands::VerifyLogin) -> Result {
|
||||
if let commands::VerifyLogin::PivPin(pin) = login {
|
||||
// the actual PIN verification
|
||||
let mut persistent_state = self.state.persistent(&mut self.trussed);
|
||||
let persistent_state = self.state.persistent(&mut self.trussed)?;
|
||||
|
||||
if persistent_state.remaining_pin_retries() == 0 {
|
||||
return Err(Status::OperationBlocked);
|
||||
}
|
||||
|
||||
if persistent_state.verify_pin(&pin) {
|
||||
persistent_state.reset_consecutive_pin_mismatches();
|
||||
persistent_state.reset_consecutive_pin_mismatches(&mut self.trussed);
|
||||
self.state.runtime.app_security_status.pin_verified = true;
|
||||
Ok(())
|
||||
} else {
|
||||
let remaining = persistent_state.increment_consecutive_pin_mismatches();
|
||||
let remaining =
|
||||
persistent_state.increment_consecutive_pin_mismatches(&mut self.trussed);
|
||||
// should we logout here?
|
||||
self.state.runtime.app_security_status.pin_verified = false;
|
||||
Err(Status::RemainingRetries(remaining))
|
||||
@@ -155,7 +156,7 @@ where
|
||||
} else {
|
||||
let retries = self
|
||||
.state
|
||||
.persistent(&mut self.trussed)
|
||||
.persistent(&mut self.trussed)?
|
||||
.remaining_pin_retries();
|
||||
Err(Status::RemainingRetries(retries))
|
||||
}
|
||||
@@ -172,37 +173,39 @@ where
|
||||
}
|
||||
|
||||
pub fn change_pin(&mut self, old_pin: commands::Pin, new_pin: commands::Pin) -> Result {
|
||||
let mut persistent_state = self.state.persistent(&mut self.trussed);
|
||||
let persistent_state = self.state.persistent(&mut self.trussed)?;
|
||||
if persistent_state.remaining_pin_retries() == 0 {
|
||||
return Err(Status::OperationBlocked);
|
||||
}
|
||||
|
||||
if !persistent_state.verify_pin(&old_pin) {
|
||||
let remaining = persistent_state.increment_consecutive_pin_mismatches();
|
||||
let remaining =
|
||||
persistent_state.increment_consecutive_pin_mismatches(&mut self.trussed);
|
||||
self.state.runtime.app_security_status.pin_verified = false;
|
||||
return Err(Status::RemainingRetries(remaining));
|
||||
}
|
||||
|
||||
persistent_state.reset_consecutive_pin_mismatches();
|
||||
persistent_state.set_pin(new_pin);
|
||||
persistent_state.reset_consecutive_pin_mismatches(&mut self.trussed);
|
||||
persistent_state.set_pin(new_pin, &mut self.trussed);
|
||||
self.state.runtime.app_security_status.pin_verified = true;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn change_puk(&mut self, old_puk: commands::Puk, new_puk: commands::Puk) -> Result {
|
||||
let mut persistent_state = self.state.persistent(&mut self.trussed);
|
||||
let persistent_state = self.state.persistent(&mut self.trussed)?;
|
||||
if persistent_state.remaining_puk_retries() == 0 {
|
||||
return Err(Status::OperationBlocked);
|
||||
}
|
||||
|
||||
if !persistent_state.verify_puk(&old_puk) {
|
||||
let remaining = persistent_state.increment_consecutive_puk_mismatches();
|
||||
let remaining =
|
||||
persistent_state.increment_consecutive_puk_mismatches(&mut self.trussed);
|
||||
self.state.runtime.app_security_status.puk_verified = false;
|
||||
return Err(Status::RemainingRetries(remaining));
|
||||
}
|
||||
|
||||
persistent_state.reset_consecutive_puk_mismatches();
|
||||
persistent_state.set_puk(new_puk);
|
||||
persistent_state.reset_consecutive_puk_mismatches(&mut self.trussed);
|
||||
persistent_state.set_puk(new_puk, &mut self.trussed);
|
||||
self.state.runtime.app_security_status.puk_verified = true;
|
||||
Ok(())
|
||||
}
|
||||
@@ -385,8 +388,7 @@ where
|
||||
|
||||
if let Some(key) = self
|
||||
.state
|
||||
.persistent(&mut self.trussed)
|
||||
.state
|
||||
.persistent(&mut self.trussed)?
|
||||
.keys
|
||||
.authentication_key
|
||||
{
|
||||
@@ -418,13 +420,9 @@ where
|
||||
// )?
|
||||
// .signature;
|
||||
// blocking::dbg!(&signature);
|
||||
|
||||
self.state
|
||||
.persistent(&mut self.trussed)
|
||||
.state
|
||||
.keys
|
||||
.authentication_key = Some(key);
|
||||
self.state.persistent(&mut self.trussed).save();
|
||||
let persistent_state = self.state.persistent(&mut self.trussed)?;
|
||||
persistent_state.keys.authentication_key = Some(key);
|
||||
persistent_state.save(&mut self.trussed);
|
||||
|
||||
// let public_key = syscall!(self.trussed.derive_p256_public_key(
|
||||
let public_key = syscall!(self
|
||||
@@ -584,7 +582,7 @@ where
|
||||
|
||||
// '5FC1 02' (351B)
|
||||
Container::CardHolderUniqueIdentifier => {
|
||||
let guid = self.state.persistent(&mut self.trussed).guid();
|
||||
let guid = self.state.persistent(&mut self.trussed)?.guid();
|
||||
piv_types::CardHolderUniqueIdentifier::default()
|
||||
.with_guid(guid)
|
||||
.encode_to_heapless_vec(reply)
|
||||
@@ -668,12 +666,12 @@ where
|
||||
return Err(Status::IncorrectP1OrP2Parameter);
|
||||
}
|
||||
|
||||
let persistent_state = self.state.persistent(&mut self.trussed)?;
|
||||
|
||||
// TODO: find out what all needs resetting :)
|
||||
self.state.persistent(&mut self.trussed).reset_pin();
|
||||
self.state.persistent(&mut self.trussed).reset_puk();
|
||||
self.state
|
||||
.persistent(&mut self.trussed)
|
||||
.reset_management_key();
|
||||
persistent_state.reset_pin(&mut self.trussed);
|
||||
persistent_state.reset_puk(&mut self.trussed);
|
||||
persistent_state.reset_management_key(&mut self.trussed);
|
||||
self.state.runtime.app_security_status.pin_verified = false;
|
||||
self.state.runtime.app_security_status.puk_verified = false;
|
||||
self.state.runtime.app_security_status.management_verified = false;
|
||||
@@ -718,8 +716,8 @@ where
|
||||
}
|
||||
let new_management_key: [u8; 24] = new_management_key.try_into().unwrap();
|
||||
self.state
|
||||
.persistent(&mut self.trussed)
|
||||
.set_management_key(&new_management_key);
|
||||
.persistent(&mut self.trussed)?
|
||||
.set_management_key(&new_management_key, &mut self.trussed);
|
||||
}
|
||||
|
||||
_ => return Err(Status::FunctionNotSupported),
|
||||
|
||||
+119
-116
@@ -1,17 +1,15 @@
|
||||
use core::convert::{TryFrom, TryInto};
|
||||
|
||||
use iso7816::Status;
|
||||
use trussed::{
|
||||
block, syscall, try_syscall,
|
||||
types::{KeyId, Location, PathBuf},
|
||||
Client as TrussedClient,
|
||||
};
|
||||
|
||||
use crate::constants::*;
|
||||
|
||||
use crate::{Pin, Puk};
|
||||
|
||||
pub type Result<T> = core::result::Result<T, ()>;
|
||||
|
||||
pub enum Key {
|
||||
Ed25519(KeyId),
|
||||
P256(KeyId),
|
||||
@@ -149,33 +147,48 @@ pub struct Keys {
|
||||
pub retired_keys: [Option<KeyId>; 20],
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||
#[derive(Debug, Default, Eq, PartialEq)]
|
||||
pub struct State<const C: usize> {
|
||||
pub runtime: Runtime<C>,
|
||||
// temporary "state", to be removed again
|
||||
// pub hack: Hack,
|
||||
// trussed: RefCell<Trussed<S>>,
|
||||
pub persistent: Option<Persistent>,
|
||||
}
|
||||
|
||||
impl<const C: usize> State<C> {
|
||||
pub fn load(
|
||||
&mut self,
|
||||
client: &mut impl trussed::Client,
|
||||
) -> Result<LoadedState<'_, C>, Status> {
|
||||
if self.persistent.is_none() {
|
||||
self.persistent = Some(Persistent::load_or_initialize(client));
|
||||
}
|
||||
Ok(LoadedState {
|
||||
runtime: &mut self.runtime,
|
||||
persistent: self.persistent.as_mut().unwrap(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn persistent(
|
||||
&mut self,
|
||||
client: &mut impl trussed::Client,
|
||||
) -> Result<&mut Persistent, Status> {
|
||||
Ok(self.load(client)?.persistent)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct LoadedState<'t, const C: usize> {
|
||||
pub runtime: &'t mut Runtime<C>,
|
||||
pub persistent: &'t mut Persistent,
|
||||
}
|
||||
|
||||
impl<const C: usize> State<C> {
|
||||
pub fn new() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
// it would be nicer to do this during "board bringup", by using TrussedService as Syscall
|
||||
//
|
||||
// TODO: it is really not good to overwrite user data on failure to decode old state.
|
||||
// To fix this, need a flag to detect if we're "fresh", and/or initialize state in factory.
|
||||
pub fn persistent<'t, T>(&mut self, trussed: &'t mut T) -> Persistent<'t, T>
|
||||
where
|
||||
T: TrussedClient + trussed::client::Tdes,
|
||||
{
|
||||
Persistent::load_or_initialize(trussed)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
|
||||
pub struct PersistentState {
|
||||
pub struct Persistent {
|
||||
pub keys: Keys,
|
||||
consecutive_pin_mismatches: u8,
|
||||
consecutive_puk_mismatches: u8,
|
||||
@@ -192,18 +205,6 @@ pub struct PersistentState {
|
||||
guid: [u8; 16],
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct Persistent<'t, Trussed> {
|
||||
trussed: &'t mut Trussed,
|
||||
pub(crate) state: PersistentState,
|
||||
}
|
||||
|
||||
impl<T> AsRef<PersistentState> for Persistent<'_, T> {
|
||||
fn as_ref(&self) -> &PersistentState {
|
||||
&self.state
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||
pub struct Runtime<const C: usize> {
|
||||
// aid: Option<
|
||||
@@ -304,10 +305,7 @@ pub struct AuthenticateManagement {
|
||||
pub challenge: [u8; 8],
|
||||
}
|
||||
|
||||
impl<'t, T> Persistent<'t, T>
|
||||
where
|
||||
T: TrussedClient + trussed::client::Tdes,
|
||||
{
|
||||
impl Persistent {
|
||||
pub const PIN_RETRIES_DEFAULT: u8 = 3;
|
||||
// hmm...!
|
||||
pub const PUK_RETRIES_DEFAULT: u8 = 5;
|
||||
@@ -316,118 +314,130 @@ where
|
||||
const DEFAULT_PUK: &'static [u8] = b"12345678";
|
||||
|
||||
pub fn guid(&self) -> [u8; 16] {
|
||||
self.state.guid
|
||||
self.guid
|
||||
}
|
||||
|
||||
pub fn remaining_pin_retries(&self) -> u8 {
|
||||
if self.state.consecutive_pin_mismatches >= Self::PIN_RETRIES_DEFAULT {
|
||||
if self.consecutive_pin_mismatches >= Self::PIN_RETRIES_DEFAULT {
|
||||
0
|
||||
} else {
|
||||
Self::PIN_RETRIES_DEFAULT - self.state.consecutive_pin_mismatches
|
||||
Self::PIN_RETRIES_DEFAULT - self.consecutive_pin_mismatches
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remaining_puk_retries(&self) -> u8 {
|
||||
if self.state.consecutive_puk_mismatches >= Self::PUK_RETRIES_DEFAULT {
|
||||
if self.consecutive_puk_mismatches >= Self::PUK_RETRIES_DEFAULT {
|
||||
0
|
||||
} else {
|
||||
Self::PUK_RETRIES_DEFAULT - self.state.consecutive_puk_mismatches
|
||||
Self::PUK_RETRIES_DEFAULT - self.consecutive_puk_mismatches
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: revisit with trussed pin management
|
||||
pub fn verify_pin(&self, other_pin: &Pin) -> bool {
|
||||
// hprintln!("verifying pin {:?} against {:?}", other_pin, &self.pin).ok();
|
||||
self.state.pin == *other_pin
|
||||
self.pin == *other_pin
|
||||
}
|
||||
|
||||
// FIXME: revisit with trussed pin management
|
||||
pub fn verify_puk(&self, other_puk: &Puk) -> bool {
|
||||
// hprintln!("verifying puk {:?} against {:?}", other_puk, &self.puk).ok();
|
||||
self.state.puk == *other_puk
|
||||
self.puk == *other_puk
|
||||
}
|
||||
|
||||
pub fn set_pin(&mut self, new_pin: Pin) {
|
||||
self.state.pin = new_pin;
|
||||
self.save();
|
||||
pub fn set_pin(&mut self, new_pin: Pin, client: &mut impl trussed::Client) {
|
||||
self.pin = new_pin;
|
||||
self.save(client);
|
||||
}
|
||||
|
||||
pub fn set_puk(&mut self, new_puk: Puk) {
|
||||
self.state.puk = new_puk;
|
||||
self.save();
|
||||
pub fn set_puk(&mut self, new_puk: Puk, client: &mut impl trussed::Client) {
|
||||
self.puk = new_puk;
|
||||
self.save(client);
|
||||
}
|
||||
|
||||
pub fn reset_pin(&mut self) {
|
||||
self.set_pin(Pin::try_from(Self::DEFAULT_PIN).unwrap());
|
||||
self.reset_consecutive_pin_mismatches();
|
||||
pub fn reset_pin(&mut self, client: &mut impl trussed::Client) {
|
||||
self.set_pin(Pin::try_from(Self::DEFAULT_PIN).unwrap(), client);
|
||||
self.reset_consecutive_pin_mismatches(client);
|
||||
}
|
||||
|
||||
pub fn reset_puk(&mut self) {
|
||||
self.set_puk(Puk::try_from(Self::DEFAULT_PUK).unwrap());
|
||||
self.reset_consecutive_puk_mismatches();
|
||||
pub fn reset_puk(&mut self, client: &mut impl trussed::Client) {
|
||||
self.set_puk(Puk::try_from(Self::DEFAULT_PUK).unwrap(), client);
|
||||
self.reset_consecutive_puk_mismatches(client);
|
||||
}
|
||||
|
||||
pub fn increment_consecutive_pin_mismatches(&mut self) -> u8 {
|
||||
if self.state.consecutive_pin_mismatches >= Self::PIN_RETRIES_DEFAULT {
|
||||
pub fn increment_consecutive_pin_mismatches(
|
||||
&mut self,
|
||||
client: &mut impl trussed::Client,
|
||||
) -> u8 {
|
||||
if self.consecutive_pin_mismatches >= Self::PIN_RETRIES_DEFAULT {
|
||||
return 0;
|
||||
}
|
||||
|
||||
self.state.consecutive_pin_mismatches += 1;
|
||||
self.save();
|
||||
Self::PIN_RETRIES_DEFAULT - self.state.consecutive_pin_mismatches
|
||||
self.consecutive_pin_mismatches += 1;
|
||||
self.save(client);
|
||||
Self::PIN_RETRIES_DEFAULT - self.consecutive_pin_mismatches
|
||||
}
|
||||
|
||||
pub fn increment_consecutive_puk_mismatches(&mut self) -> u8 {
|
||||
if self.state.consecutive_puk_mismatches >= Self::PUK_RETRIES_DEFAULT {
|
||||
pub fn increment_consecutive_puk_mismatches(
|
||||
&mut self,
|
||||
client: &mut impl trussed::Client,
|
||||
) -> u8 {
|
||||
if self.consecutive_puk_mismatches >= Self::PUK_RETRIES_DEFAULT {
|
||||
return 0;
|
||||
}
|
||||
|
||||
self.state.consecutive_puk_mismatches += 1;
|
||||
self.save();
|
||||
Self::PUK_RETRIES_DEFAULT - self.state.consecutive_puk_mismatches
|
||||
self.consecutive_puk_mismatches += 1;
|
||||
self.save(client);
|
||||
Self::PUK_RETRIES_DEFAULT - self.consecutive_puk_mismatches
|
||||
}
|
||||
|
||||
pub fn reset_consecutive_pin_mismatches(&mut self) -> u8 {
|
||||
if self.state.consecutive_pin_mismatches != 0 {
|
||||
self.state.consecutive_pin_mismatches = 0;
|
||||
self.save();
|
||||
pub fn reset_consecutive_pin_mismatches(&mut self, client: &mut impl trussed::Client) -> u8 {
|
||||
if self.consecutive_pin_mismatches != 0 {
|
||||
self.consecutive_pin_mismatches = 0;
|
||||
self.save(client);
|
||||
}
|
||||
|
||||
Self::PIN_RETRIES_DEFAULT
|
||||
}
|
||||
|
||||
pub fn reset_consecutive_puk_mismatches(&mut self) -> u8 {
|
||||
if self.state.consecutive_puk_mismatches != 0 {
|
||||
self.state.consecutive_puk_mismatches = 0;
|
||||
self.save();
|
||||
pub fn reset_consecutive_puk_mismatches(&mut self, client: &mut impl trussed::Client) -> u8 {
|
||||
if self.consecutive_puk_mismatches != 0 {
|
||||
self.consecutive_puk_mismatches = 0;
|
||||
self.save(client);
|
||||
}
|
||||
|
||||
Self::PUK_RETRIES_DEFAULT
|
||||
}
|
||||
|
||||
pub fn reset_management_key(&mut self) {
|
||||
self.set_management_key(YUBICO_DEFAULT_MANAGEMENT_KEY);
|
||||
pub fn reset_management_key(&mut self, client: &mut impl trussed::Client) {
|
||||
self.set_management_key(YUBICO_DEFAULT_MANAGEMENT_KEY, client);
|
||||
}
|
||||
|
||||
pub fn set_management_key(&mut self, management_key: &[u8; 24]) {
|
||||
pub fn set_management_key(
|
||||
&mut self,
|
||||
management_key: &[u8; 24],
|
||||
client: &mut impl trussed::Client,
|
||||
) {
|
||||
// let new_management_key = syscall!(self.trussed.unsafe_inject_tdes_key(
|
||||
let new_management_key = syscall!(self
|
||||
.trussed
|
||||
.unsafe_inject_shared_key(management_key, trussed::types::Location::Internal,))
|
||||
.key;
|
||||
let old_management_key = self.state.keys.management_key;
|
||||
self.state.keys.management_key = new_management_key;
|
||||
self.save();
|
||||
syscall!(self.trussed.delete(old_management_key));
|
||||
let new_management_key =
|
||||
syscall!(client
|
||||
.unsafe_inject_shared_key(management_key, trussed::types::Location::Internal,))
|
||||
.key;
|
||||
let old_management_key = self.keys.management_key;
|
||||
self.keys.management_key = new_management_key;
|
||||
self.save(client);
|
||||
syscall!(client.delete(old_management_key));
|
||||
}
|
||||
|
||||
pub fn initialize(trussed: &'t mut T) -> Self {
|
||||
pub fn initialize(client: &mut impl trussed::Client) -> Self {
|
||||
info!("initializing PIV state");
|
||||
let management_key = syscall!(trussed.unsafe_inject_shared_key(
|
||||
let management_key = syscall!(client.unsafe_inject_shared_key(
|
||||
YUBICO_DEFAULT_MANAGEMENT_KEY,
|
||||
trussed::types::Location::Internal,
|
||||
))
|
||||
.key;
|
||||
|
||||
let mut guid: [u8; 16] = syscall!(trussed.random_bytes(16))
|
||||
let mut guid: [u8; 16] = syscall!(client.random_bytes(16))
|
||||
.bytes
|
||||
.as_ref()
|
||||
.try_into()
|
||||
@@ -446,24 +456,21 @@ where
|
||||
};
|
||||
|
||||
let mut state = Self {
|
||||
trussed,
|
||||
state: PersistentState {
|
||||
keys,
|
||||
consecutive_pin_mismatches: 0,
|
||||
consecutive_puk_mismatches: 0,
|
||||
pin: Pin::try_from(Self::DEFAULT_PIN).unwrap(),
|
||||
puk: Puk::try_from(Self::DEFAULT_PUK).unwrap(),
|
||||
timestamp: 0,
|
||||
guid,
|
||||
},
|
||||
keys,
|
||||
consecutive_pin_mismatches: 0,
|
||||
consecutive_puk_mismatches: 0,
|
||||
pin: Pin::try_from(Self::DEFAULT_PIN).unwrap(),
|
||||
puk: Puk::try_from(Self::DEFAULT_PUK).unwrap(),
|
||||
timestamp: 0,
|
||||
guid,
|
||||
};
|
||||
state.save();
|
||||
state.save(client);
|
||||
state
|
||||
}
|
||||
|
||||
#[allow(clippy::result_unit_err)]
|
||||
pub fn load(trussed: &'t mut T) -> Result<Self> {
|
||||
let data = block!(trussed
|
||||
pub fn load(client: &mut impl trussed::Client) -> Result<Self, ()> {
|
||||
let data = block!(client
|
||||
.read_file(Location::Internal, PathBuf::from(Self::FILENAME),)
|
||||
.unwrap())
|
||||
.map_err(|_err| {
|
||||
@@ -471,21 +478,17 @@ where
|
||||
})?
|
||||
.data;
|
||||
|
||||
let previous_state: PersistentState = trussed::cbor_deserialize(&data).map_err(|_err| {
|
||||
let previous_state: Self = trussed::cbor_deserialize(&data).map_err(|_err| {
|
||||
info!("cbor deser error: {_err:?}");
|
||||
info!("data: {:X?}", &data);
|
||||
})?;
|
||||
// horrible deser bug to forget Ok here :)
|
||||
Ok(Self {
|
||||
trussed,
|
||||
state: previous_state,
|
||||
})
|
||||
Ok(previous_state)
|
||||
}
|
||||
|
||||
pub fn load_or_initialize(trussed: &'t mut T) -> Self {
|
||||
pub fn load_or_initialize(client: &mut impl trussed::Client) -> Self {
|
||||
// todo: can't seem to combine load + initialize without code repetition
|
||||
let data =
|
||||
try_syscall!(trussed.read_file(Location::Internal, PathBuf::from(Self::FILENAME)));
|
||||
try_syscall!(client.read_file(Location::Internal, PathBuf::from(Self::FILENAME)));
|
||||
if let Ok(data) = data {
|
||||
let previous_state = trussed::cbor_deserialize(&data.data).map_err(|_err| {
|
||||
info!("cbor deser error: {_err:?}");
|
||||
@@ -493,17 +496,17 @@ where
|
||||
});
|
||||
if let Ok(state) = previous_state {
|
||||
// horrible deser bug to forget Ok here :)
|
||||
return Self { trussed, state };
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
Self::initialize(trussed)
|
||||
Self::initialize(client)
|
||||
}
|
||||
|
||||
pub fn save(&mut self) {
|
||||
let data: trussed::types::Message = trussed::cbor_serialize_bytes(self.as_ref()).unwrap();
|
||||
pub fn save(&mut self, client: &mut impl trussed::Client) {
|
||||
let data: trussed::types::Message = trussed::cbor_serialize_bytes(&self).unwrap();
|
||||
|
||||
syscall!(self.trussed.write_file(
|
||||
syscall!(client.write_file(
|
||||
Location::Internal,
|
||||
PathBuf::from(Self::FILENAME),
|
||||
data,
|
||||
@@ -511,9 +514,9 @@ where
|
||||
));
|
||||
}
|
||||
|
||||
pub fn timestamp(&mut self) -> u32 {
|
||||
self.state.timestamp += 1;
|
||||
self.save();
|
||||
self.state.timestamp
|
||||
pub fn timestamp(&mut self, client: &mut impl trussed::Client) -> u32 {
|
||||
self.timestamp += 1;
|
||||
self.save(client);
|
||||
self.timestamp
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user