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 }