taler-rust

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

api.rs (6688B)


      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 observability;
     29 pub mod params;
     30 pub mod prepared;
     31 pub mod revenue;
     32 pub mod wire;
     33 
     34 #[derive(
     35     Debug,
     36     Clone,
     37     Copy,
     38     PartialEq,
     39     Eq,
     40     PartialOrd,
     41     Ord,
     42     Hash,
     43     serde_with::DeserializeFromStr,
     44     serde_with::SerializeDisplay,
     45 )]
     46 pub struct LibtoolVersion {
     47     pub current: u32,
     48     pub revision: u32,
     49     pub age: u32,
     50 }
     51 
     52 impl LibtoolVersion {
     53     pub const fn new(current: u32, revision: u32, age: u32) -> Self {
     54         assert!(age <= current);
     55         Self {
     56             current,
     57             revision,
     58             age,
     59         }
     60     }
     61 }
     62 
     63 #[derive(Debug, thiserror::Error)]
     64 pub enum LibtoolVersionError {
     65     #[error("age exceeds current")]
     66     AgeExceedsCurrent,
     67     #[error("invalid format")]
     68     InvalidFormat,
     69     #[error(transparent)]
     70     ParseIntError(#[from] ParseIntError),
     71 }
     72 
     73 impl FromStr for LibtoolVersion {
     74     type Err = LibtoolVersionError;
     75 
     76     fn from_str(s: &str) -> Result<Self, Self::Err> {
     77         let mut parts = s.split(':');
     78 
     79         let current = parts
     80             .next()
     81             .ok_or(LibtoolVersionError::InvalidFormat)?
     82             .parse::<u32>()?;
     83 
     84         let revision = match parts.next() {
     85             Some(p) => p.parse::<u32>()?,
     86             None => 0,
     87         };
     88 
     89         let age = match parts.next() {
     90             Some(p) => p.parse::<u32>()?,
     91             None => 0,
     92         };
     93 
     94         if parts.next().is_some() {
     95             return Err(LibtoolVersionError::InvalidFormat);
     96         }
     97 
     98         Ok(Self::new(current, revision, age))
     99     }
    100 }
    101 
    102 impl Display for LibtoolVersion {
    103     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    104         write!(f, "{}:{}:{}", self.current, self.revision, self.age)
    105     }
    106 }
    107 
    108 /// <https://docs.taler.net/core/api-common.html#tsref-type-ErrorDetail>
    109 #[derive(Debug, Clone, Serialize, Deserialize)]
    110 pub struct ErrorDetail {
    111     pub code: u16,
    112     pub hint: Option<Box<str>>,
    113     pub detail: Option<Box<str>>,
    114     pub parameter: Option<Box<str>>,
    115     pub path: Option<Box<str>>,
    116     pub offset: Option<Box<str>>,
    117     pub index: Option<Box<str>>,
    118     pub object: Option<Box<str>>,
    119     pub currency: Option<Box<str>>,
    120     pub type_expected: Option<Box<str>>,
    121     pub type_actual: Option<Box<str>>,
    122     pub extra: Option<Box<RawValue>>,
    123 }
    124 
    125 /// 64-byte hash code
    126 pub type HashCode = Base32<64>;
    127 /// 32-bytes hash code
    128 pub type ShortHashCode = Base32<32>;
    129 pub type WadId = Base32<24>;
    130 pub type EddsaSignature = Base32<64>;
    131 
    132 /// EdDSA and ECDHE public keys always point on Curve25519
    133 /// and represented  using the standard 256 bits Ed25519 compact format,
    134 /// converted to Crockford Base32.
    135 #[derive(Clone, Copy, PartialEq, Eq)]
    136 pub struct EddsaPublicKey(Base32<32>);
    137 
    138 impl Deref for EddsaPublicKey {
    139     type Target = Base32<32>;
    140 
    141     fn deref(&self) -> &Self::Target {
    142         &self.0
    143     }
    144 }
    145 
    146 impl Serialize for EddsaPublicKey {
    147     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    148     where
    149         S: serde::Serializer,
    150     {
    151         self.0.serialize(serializer)
    152     }
    153 }
    154 
    155 impl<'de> Deserialize<'de> for EddsaPublicKey {
    156     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    157     where
    158         D: Deserializer<'de>,
    159     {
    160         let raw = Cow::<str>::deserialize(deserializer)?;
    161         Self::from_str(&raw).map_err(serde::de::Error::custom)
    162     }
    163 }
    164 
    165 impl Display for EddsaPublicKey {
    166     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    167         self.0.fmt(f)
    168     }
    169 }
    170 
    171 impl std::fmt::Debug for EddsaPublicKey {
    172     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    173         Display::fmt(&self.0, f)
    174     }
    175 }
    176 
    177 #[derive(Debug, thiserror::Error)]
    178 pub enum EddsaPublicKeyError {
    179     #[error(transparent)]
    180     Base32(#[from] Base32Error<32>),
    181     #[error(transparent)]
    182     Invalid(#[from] KeyRejected),
    183 }
    184 
    185 impl FromStr for EddsaPublicKey {
    186     type Err = EddsaPublicKeyError;
    187 
    188     fn from_str(s: &str) -> Result<Self, Self::Err> {
    189         let encoded = Base32::<32>::from_str(s)?;
    190         Self::try_from(encoded)
    191     }
    192 }
    193 
    194 impl TryFrom<&[u8]> for EddsaPublicKey {
    195     type Error = EddsaPublicKeyError;
    196 
    197     fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
    198         let encoded = Base32::try_from(value)?;
    199         Self::try_from(encoded)
    200     }
    201 }
    202 
    203 impl TryFrom<[u8; 32]> for EddsaPublicKey {
    204     type Error = EddsaPublicKeyError;
    205 
    206     fn try_from(value: [u8; 32]) -> Result<Self, Self::Error> {
    207         let encoded = Base32::from(value);
    208         Self::try_from(encoded)
    209     }
    210 }
    211 
    212 impl TryFrom<Base32<32>> for EddsaPublicKey {
    213     type Error = EddsaPublicKeyError;
    214 
    215     fn try_from(value: Base32<32>) -> Result<Self, Self::Error> {
    216         ParsedPublicKey::new(&signature::ED25519, value.as_ref())?;
    217         Ok(Self(value))
    218     }
    219 }
    220 
    221 impl EddsaPublicKey {
    222     pub fn rand() -> EddsaPublicKey {
    223         let signing_key = Ed25519KeyPair::generate().unwrap();
    224         let bytes: [u8; 32] = signing_key.public_key().as_ref().try_into().unwrap();
    225         Self(Base32::from(bytes))
    226     }
    227 }
    228 
    229 impl sqlx::Type<sqlx::Postgres> for EddsaPublicKey {
    230     fn type_info() -> sqlx::postgres::PgTypeInfo {
    231         <Base32<32>>::type_info()
    232     }
    233 }
    234 
    235 impl<'q> sqlx::Encode<'q, sqlx::Postgres> for EddsaPublicKey {
    236     fn encode_by_ref(
    237         &self,
    238         buf: &mut sqlx::postgres::PgArgumentBuffer,
    239     ) -> Result<sqlx::encode::IsNull, sqlx::error::BoxDynError> {
    240         self.0.encode_by_ref(buf)
    241     }
    242 }
    243 
    244 impl<'r> sqlx::Decode<'r, sqlx::Postgres> for EddsaPublicKey {
    245     fn decode(value: sqlx::postgres::PgValueRef<'r>) -> Result<Self, sqlx::error::BoxDynError> {
    246         let raw = <Base32<32>>::decode(value)?;
    247         Ok(Self(raw))
    248     }
    249 }