freepass issuance API side
This commit is contained in:
@@ -135,7 +135,7 @@ pub struct FreePassRequest {
|
||||
// secp256k1 key associated with the admin account
|
||||
pub cosmos_pubkey: cosmrs::crypto::PublicKey,
|
||||
|
||||
pub inner_sign_request: BlindSignRequest,
|
||||
pub inner_sign_request: WithdrawalRequest,
|
||||
|
||||
// we need to include a nonce here to prevent replay attacks
|
||||
// (and not making the nym-api store the serial numbers of all issued credential)
|
||||
@@ -145,36 +145,33 @@ pub struct FreePassRequest {
|
||||
/// to prove the possession of the cosmos key/address
|
||||
pub nonce_signature: cosmrs::crypto::secp256k1::Signature,
|
||||
|
||||
pub public_attributes_plain: Vec<String>,
|
||||
pub ecash_pubkey: PublicKeyUser,
|
||||
|
||||
pub expiration_date: u64,
|
||||
}
|
||||
|
||||
impl FreePassRequest {
|
||||
pub fn new(
|
||||
cosmos_pubkey: cosmrs::crypto::PublicKey,
|
||||
inner_sign_request: BlindSignRequest,
|
||||
inner_sign_request: WithdrawalRequest,
|
||||
used_nonce: [u8; 16],
|
||||
nonce_signature: cosmrs::crypto::secp256k1::Signature,
|
||||
public_attributes_plain: Vec<String>,
|
||||
ecash_pubkey: PublicKeyUser,
|
||||
expiration_date: u64,
|
||||
) -> Self {
|
||||
FreePassRequest {
|
||||
cosmos_pubkey,
|
||||
inner_sign_request,
|
||||
used_nonce,
|
||||
nonce_signature,
|
||||
public_attributes_plain,
|
||||
ecash_pubkey,
|
||||
expiration_date,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tendermint_pubkey(&self) -> tendermint::PublicKey {
|
||||
self.cosmos_pubkey.into()
|
||||
}
|
||||
|
||||
pub fn public_attributes_hashed(&self) -> Vec<Attribute> {
|
||||
self.public_attributes_plain
|
||||
.iter()
|
||||
.map(hash_to_scalar)
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
|
||||
@@ -30,48 +30,6 @@ use time::OffsetDateTime;
|
||||
|
||||
mod helpers;
|
||||
|
||||
fn validate_freepass_public_attributes(res: &FreePassRequest) -> Result<()> {
|
||||
let public_attributes = &res.public_attributes_plain;
|
||||
|
||||
if public_attributes.len() != IssuanceBandwidthCredential::PUBLIC_ATTRIBUTES as usize {
|
||||
return Err(CoconutError::InvalidFreePassAttributes {
|
||||
got: public_attributes.len(),
|
||||
expected: IssuanceBandwidthCredential::PUBLIC_ATTRIBUTES as usize,
|
||||
});
|
||||
}
|
||||
|
||||
// SAFETY: we just ensured correct number of attributes
|
||||
let expiry_raw = public_attributes.first().unwrap();
|
||||
let type_raw = public_attributes.get(1).unwrap();
|
||||
|
||||
let parsed_type = type_raw.parse::<CredentialType>()?;
|
||||
if parsed_type != CredentialType::FreePass {
|
||||
return Err(CoconutError::InvalidFreePassTypeAttribute { got: parsed_type });
|
||||
}
|
||||
|
||||
let expiry_timestamp: i64 = expiry_raw
|
||||
.parse()
|
||||
.map_err(|source| CoconutError::ExpiryDateParsingFailure { source })?;
|
||||
|
||||
let expiry_date = OffsetDateTime::from_unix_timestamp(expiry_timestamp).map_err(|source| {
|
||||
CoconutError::InvalidExpiryDate {
|
||||
unix_timestamp: expiry_timestamp,
|
||||
source,
|
||||
}
|
||||
})?;
|
||||
let now = OffsetDateTime::now_utc();
|
||||
|
||||
if expiry_date > now + MAX_FREE_PASS_VALIDITY {
|
||||
return Err(CoconutError::TooLongFreePass { expiry_date });
|
||||
}
|
||||
|
||||
if expiry_date < now {
|
||||
return Err(CoconutError::FreePassExpiryInThePast { expiry_date });
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[get("/free-pass-nonce")]
|
||||
pub async fn get_current_free_pass_nonce(
|
||||
state: &RocketState<State>,
|
||||
@@ -94,7 +52,16 @@ pub async fn post_free_pass(
|
||||
debug!("Received free pass sign request");
|
||||
trace!("body: {:?}", freepass_request_body);
|
||||
|
||||
validate_freepass_public_attributes(&freepass_request_body)?;
|
||||
//check expiration date validity
|
||||
if freepass_request_body.expiration_date > freepass_exp_date_timestamp() {
|
||||
return Err(CoconutError::TooLongFreePass {
|
||||
expiry_date: OffsetDateTime::from_unix_timestamp(
|
||||
//safety : expiration date is a unix timestamp so these unwraps will not fail for 290 million years
|
||||
freepass_request_body.expiration_date.try_into().unwrap(),
|
||||
)
|
||||
.unwrap(),
|
||||
});
|
||||
}
|
||||
|
||||
// grab the admin of the bandwidth contract
|
||||
let Some(authorised_admin) = state.get_bandwidth_contract_admin().await? else {
|
||||
@@ -161,8 +128,10 @@ pub async fn post_free_pass(
|
||||
|
||||
// produce the partial signature
|
||||
debug!("producing the partial credential");
|
||||
let blinded_signature =
|
||||
blind_sign(freepass_request_body.deref(), signing_key.keys.secret_key())?;
|
||||
let blinded_signature = blind_sign(
|
||||
freepass_request_body.deref(),
|
||||
&signing_key.keys.secret_key(),
|
||||
)?;
|
||||
|
||||
// update the number of issued free passes
|
||||
state.storage.increment_issued_freepasses().await?;
|
||||
|
||||
@@ -51,12 +51,16 @@ impl CredentialRequest for BlindSignRequestBody {
|
||||
}
|
||||
|
||||
impl CredentialRequest for FreePassRequest {
|
||||
fn blind_sign_request(&self) -> &BlindSignRequest {
|
||||
fn withdrawal_request(&self) -> &WithdrawalRequest {
|
||||
&self.inner_sign_request
|
||||
}
|
||||
|
||||
fn public_attributes(&self) -> Vec<Attribute> {
|
||||
self.public_attributes_hashed()
|
||||
fn expiration_date(&self) -> u64 {
|
||||
self.expiration_date
|
||||
}
|
||||
|
||||
fn ecash_pubkey(&self) -> PublicKeyUser {
|
||||
self.ecash_pubkey.clone()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user