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 }