taler-rust

GNU Taler code in Rust. Largely core banking integrations.
Log | Files | Refs | Submodules | README | LICENSE

api.rs (6659B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2024, 2025, 2026 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU Affero General Public License as published by the Free Software
      7   Foundation; either version 3, or (at your option) any later version.
      8 
      9   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
     10   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11   A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.
     12 
     13   You should have received a copy of the GNU Affero General Public License along with
     14   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 
     17 use std::{borrow::Cow, fmt::Display, num::ParseIntError, ops::Deref, str::FromStr};
     18 
     19 use aws_lc_rs::{
     20     error::KeyRejected,
     21     signature::{self, Ed25519KeyPair, KeyPair as _, ParsedPublicKey},
     22 };
     23 use serde::{Deserialize, Deserializer, Serialize};
     24 use serde_json::value::RawValue;
     25 
     26 use crate::{encoding::base32::Base32Error, types::base32::Base32};
     27 
     28 pub mod params;
     29 pub mod prepared;
     30 pub mod revenue;
     31 pub mod wire;
     32 
     33 #[derive(
     34     Debug,
     35     Clone,
     36     Copy,
     37     PartialEq,
     38     Eq,
     39     PartialOrd,
     40     Ord,
     41     Hash,
     42     serde_with::DeserializeFromStr,
     43     serde_with::SerializeDisplay,
     44 )]
     45 pub struct LibtoolVersion {
     46     pub current: u32,
     47     pub revision: u32,
     48     pub age: u32,
     49 }
     50 
     51 impl LibtoolVersion {
     52     pub const fn new(current: u32, revision: u32, age: u32) -> Self {
     53         assert!(age <= current);
     54         Self {
     55             current,
     56             revision,
     57             age,
     58         }
     59     }
     60 }
     61 
     62 #[derive(Debug, thiserror::Error)]
     63 pub enum LibtoolVersionError {
     64     #[error("age exceeds current")]
     65     AgeExceedsCurrent,
     66     #[error("invalid format")]
     67     InvalidFormat,
     68     #[error(transparent)]
     69     ParseIntError(#[from] ParseIntError),
     70 }
     71 
     72 impl FromStr for LibtoolVersion {
     73     type Err = LibtoolVersionError;
     74 
     75     fn from_str(s: &str) -> Result<Self, Self::Err> {
     76         let mut parts = s.split(':');
     77 
     78         let current = parts
     79             .next()
     80             .ok_or(LibtoolVersionError::InvalidFormat)?
     81             .parse::<u32>()?;
     82 
     83         let revision = match parts.next() {
     84             Some(p) => p.parse::<u32>()?,
     85             None => 0,
     86         };
     87 
     88         let age = match parts.next() {
     89             Some(p) => p.parse::<u32>()?,
     90             None => 0,
     91         };
     92 
     93         if parts.next().is_some() {
     94             return Err(LibtoolVersionError::InvalidFormat);
     95         }
     96 
     97         Ok(Self::new(current, revision, age))
     98     }
     99 }
    100 
    101 impl Display for LibtoolVersion {
    102     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    103         write!(f, "{}:{}:{}", self.current, self.revision, self.age)
    104     }
    105 }
    106 
    107 /// <https://docs.taler.net/core/api-common.html#tsref-type-ErrorDetail>
    108 #[derive(Debug, Clone, Serialize, Deserialize)]
    109 pub struct ErrorDetail {
    110     pub code: u16,
    111     pub hint: Option<Box<str>>,
    112     pub detail: Option<Box<str>>,
    113     pub parameter: Option<Box<str>>,
    114     pub path: Option<Box<str>>,
    115     pub offset: Option<Box<str>>,
    116     pub index: Option<Box<str>>,
    117     pub object: Option<Box<str>>,
    118     pub currency: Option<Box<str>>,
    119     pub type_expected: Option<Box<str>>,
    120     pub type_actual: Option<Box<str>>,
    121     pub extra: Option<Box<RawValue>>,
    122 }
    123 
    124 /// 64-byte hash code
    125 pub type HashCode = Base32<64>;
    126 /// 32-bytes hash code
    127 pub type ShortHashCode = Base32<32>;
    128 pub type WadId = Base32<24>;
    129 pub type EddsaSignature = Base32<64>;
    130 
    131 /// EdDSA and ECDHE public keys always point on Curve25519
    132 /// and represented  using the standard 256 bits Ed25519 compact format,
    133 /// converted to Crockford Base32.
    134 #[derive(Clone, PartialEq, Eq)]
    135 pub struct EddsaPublicKey(Base32<32>);
    136 
    137 impl Deref for EddsaPublicKey {
    138     type Target = Base32<32>;
    139 
    140     fn deref(&self) -> &Self::Target {
    141         &self.0
    142     }
    143 }
    144 
    145 impl Serialize for EddsaPublicKey {
    146     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    147     where
    148         S: serde::Serializer,
    149     {
    150         self.0.serialize(serializer)
    151     }
    152 }
    153 
    154 impl<'de> Deserialize<'de> for EddsaPublicKey {
    155     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    156     where
    157         D: Deserializer<'de>,
    158     {
    159         let raw = Cow::<str>::deserialize(deserializer)?;
    160         Self::from_str(&raw).map_err(serde::de::Error::custom)
    161     }
    162 }
    163 
    164 impl Display for EddsaPublicKey {
    165     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    166         self.0.fmt(f)
    167     }
    168 }
    169 
    170 impl std::fmt::Debug for EddsaPublicKey {
    171     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    172         Display::fmt(&self.0, f)
    173     }
    174 }
    175 
    176 #[derive(Debug, thiserror::Error)]
    177 pub enum EddsaPublicKeyError {
    178     #[error(transparent)]
    179     Base32(#[from] Base32Error<32>),
    180     #[error(transparent)]
    181     Invalid(#[from] KeyRejected),
    182 }
    183 
    184 impl FromStr for EddsaPublicKey {
    185     type Err = EddsaPublicKeyError;
    186 
    187     fn from_str(s: &str) -> Result<Self, Self::Err> {
    188         let encoded = Base32::<32>::from_str(s)?;
    189         Self::try_from(encoded)
    190     }
    191 }
    192 
    193 impl TryFrom<&[u8]> for EddsaPublicKey {
    194     type Error = EddsaPublicKeyError;
    195 
    196     fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
    197         let encoded = Base32::try_from(value)?;
    198         Self::try_from(encoded)
    199     }
    200 }
    201 
    202 impl TryFrom<[u8; 32]> for EddsaPublicKey {
    203     type Error = EddsaPublicKeyError;
    204 
    205     fn try_from(value: [u8; 32]) -> Result<Self, Self::Error> {
    206         let encoded = Base32::from(value);
    207         Self::try_from(encoded)
    208     }
    209 }
    210 
    211 impl TryFrom<Base32<32>> for EddsaPublicKey {
    212     type Error = EddsaPublicKeyError;
    213 
    214     fn try_from(value: Base32<32>) -> Result<Self, Self::Error> {
    215         ParsedPublicKey::new(&signature::ED25519, value.as_ref())?;
    216         Ok(Self(value))
    217     }
    218 }
    219 
    220 impl EddsaPublicKey {
    221     pub fn rand() -> EddsaPublicKey {
    222         let signing_key = Ed25519KeyPair::generate().unwrap();
    223         let bytes: [u8; 32] = signing_key.public_key().as_ref().try_into().unwrap();
    224         Self(Base32::from(bytes))
    225     }
    226 }
    227 
    228 impl sqlx::Type<sqlx::Postgres> for EddsaPublicKey {
    229     fn type_info() -> sqlx::postgres::PgTypeInfo {
    230         <Base32<32>>::type_info()
    231     }
    232 }
    233 
    234 impl<'q> sqlx::Encode<'q, sqlx::Postgres> for EddsaPublicKey {
    235     fn encode_by_ref(
    236         &self,
    237         buf: &mut sqlx::postgres::PgArgumentBuffer,
    238     ) -> Result<sqlx::encode::IsNull, sqlx::error::BoxDynError> {
    239         self.0.encode_by_ref(buf)
    240     }
    241 }
    242 
    243 impl<'r> sqlx::Decode<'r, sqlx::Postgres> for EddsaPublicKey {
    244     fn decode(value: sqlx::postgres::PgValueRef<'r>) -> Result<Self, sqlx::error::BoxDynError> {
    245         let raw = <Base32<32>>::decode(value)?;
    246         Ok(Self(raw))
    247     }
    248 }