api_common.rs (6295B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2024, 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, ops::Deref, str::FromStr}; 18 19 use aws_lc_rs::{ 20 error::KeyRejected, 21 signature::{self, Ed25519KeyPair, KeyPair, ParsedPublicKey}, 22 }; 23 use serde::{Deserialize, Deserializer, Serialize, de::Error}; 24 use serde_json::value::RawValue; 25 26 use crate::types::base32::{Base32, Base32Error}; 27 28 /// <https://docs.taler.net/core/api-common.html#tsref-type-ErrorDetail> 29 #[derive(Debug, Clone, Serialize, Deserialize)] 30 pub struct ErrorDetail { 31 pub code: u32, 32 pub hint: Option<Box<str>>, 33 pub detail: Option<Box<str>>, 34 pub parameter: Option<Box<str>>, 35 pub path: Option<Box<str>>, 36 pub offset: Option<Box<str>>, 37 pub index: Option<Box<str>>, 38 pub object: Option<Box<str>>, 39 pub currency: Option<Box<str>>, 40 pub type_expected: Option<Box<str>>, 41 pub type_actual: Option<Box<str>>, 42 pub extra: Option<Box<RawValue>>, 43 } 44 45 pub fn safe_u64(nb: u64) -> SafeU64 { 46 SafeU64::try_from(nb).expect("invalid safe u64") 47 } 48 49 /// <https://docs.taler.net/core/api-common.html#tsref-type-SafeUint64> 50 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize)] 51 pub struct SafeU64(u64); 52 53 impl Deref for SafeU64 { 54 type Target = u64; 55 56 fn deref(&self) -> &Self::Target { 57 &self.0 58 } 59 } 60 61 #[derive(Debug, thiserror::Error)] 62 pub enum SafeU64Error { 63 #[error("{0} unsafe, {0} > (2^53 - 1)")] 64 Unsafe(u64), 65 #[error("{0} is negative")] 66 Negative(i64), 67 } 68 69 impl TryFrom<u64> for SafeU64 { 70 type Error = SafeU64Error; 71 72 fn try_from(nb: u64) -> Result<Self, Self::Error> { 73 if nb < (1 << 53) - 1 { 74 Ok(SafeU64(nb)) 75 } else { 76 Err(SafeU64Error::Unsafe(nb)) 77 } 78 } 79 } 80 81 impl TryFrom<i64> for SafeU64 { 82 type Error = SafeU64Error; 83 84 fn try_from(nb: i64) -> Result<Self, Self::Error> { 85 u64::try_from(nb) 86 .map_err(|_| SafeU64Error::Negative(nb)) 87 .and_then(|it| it.try_into()) 88 } 89 } 90 91 impl TryFrom<i32> for SafeU64 { 92 type Error = SafeU64Error; 93 94 fn try_from(nb: i32) -> Result<Self, Self::Error> { 95 u64::try_from(nb) 96 .map_err(|_| SafeU64Error::Negative(nb as i64)) 97 .and_then(|it| it.try_into()) 98 } 99 } 100 101 impl<'de> Deserialize<'de> for SafeU64 { 102 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 103 where 104 D: Deserializer<'de>, 105 { 106 SafeU64::try_from(u64::deserialize(deserializer)?).map_err(D::Error::custom) 107 } 108 } 109 110 impl Display for SafeU64 { 111 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 112 self.0.fmt(f) 113 } 114 } 115 116 /// 64-byte hash code 117 pub type HashCode = Base32<64>; 118 /// 32-bytes hash code 119 pub type ShortHashCode = Base32<32>; 120 pub type WadId = Base32<24>; 121 pub type EddsaSignature = Base32<64>; 122 123 /// EdDSA and ECDHE public keys always point on Curve25519 124 /// and represented using the standard 256 bits Ed25519 compact format, 125 /// converted to Crockford Base32. 126 #[derive(Debug, Clone, PartialEq, Eq)] 127 pub struct EddsaPublicKey(Base32<32>); 128 129 impl AsRef<Base32<32>> for EddsaPublicKey { 130 fn as_ref(&self) -> &Base32<32> { 131 &self.0 132 } 133 } 134 135 impl Serialize for EddsaPublicKey { 136 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 137 where 138 S: serde::Serializer, 139 { 140 self.0.serialize(serializer) 141 } 142 } 143 144 impl<'de> Deserialize<'de> for EddsaPublicKey { 145 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 146 where 147 D: Deserializer<'de>, 148 { 149 let raw = Cow::<str>::deserialize(deserializer)?; 150 Self::from_str(&raw).map_err(D::Error::custom) 151 } 152 } 153 154 impl Display for EddsaPublicKey { 155 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 156 self.0.fmt(f) 157 } 158 } 159 160 #[derive(Debug, thiserror::Error)] 161 pub enum EddsaPublicKeyError { 162 #[error(transparent)] 163 Base32(#[from] Base32Error<32>), 164 #[error(transparent)] 165 Invalid(#[from] KeyRejected), 166 } 167 168 impl FromStr for EddsaPublicKey { 169 type Err = EddsaPublicKeyError; 170 171 fn from_str(s: &str) -> Result<Self, Self::Err> { 172 let encoded = Base32::<32>::from_str(s)?; 173 Self::try_from(encoded) 174 } 175 } 176 177 impl TryFrom<&[u8]> for EddsaPublicKey { 178 type Error = EddsaPublicKeyError; 179 180 fn try_from(value: &[u8]) -> Result<Self, Self::Error> { 181 let encoded = Base32::try_from(value)?; 182 Self::try_from(encoded) 183 } 184 } 185 186 impl TryFrom<Base32<32>> for EddsaPublicKey { 187 type Error = EddsaPublicKeyError; 188 189 fn try_from(value: Base32<32>) -> Result<Self, Self::Error> { 190 ParsedPublicKey::new(&signature::ED25519, value.as_ref())?; 191 Ok(Self(value)) 192 } 193 } 194 195 impl EddsaPublicKey { 196 pub fn slice(&self) -> &[u8; 32] { 197 self.0.deref() 198 } 199 200 pub fn rand() -> EddsaPublicKey { 201 let signing_key = Ed25519KeyPair::generate().unwrap(); 202 let bytes: [u8; 32] = signing_key.public_key().as_ref().try_into().unwrap(); 203 Self(Base32::from(bytes)) 204 } 205 } 206 207 impl sqlx::Type<sqlx::Postgres> for EddsaPublicKey { 208 fn type_info() -> sqlx::postgres::PgTypeInfo { 209 <Base32<32>>::type_info() 210 } 211 } 212 213 impl<'q> sqlx::Encode<'q, sqlx::Postgres> for EddsaPublicKey { 214 fn encode_by_ref( 215 &self, 216 buf: &mut sqlx::postgres::PgArgumentBuffer, 217 ) -> Result<sqlx::encode::IsNull, sqlx::error::BoxDynError> { 218 self.0.encode_by_ref(buf) 219 } 220 } 221 222 impl<'r> sqlx::Decode<'r, sqlx::Postgres> for EddsaPublicKey { 223 fn decode(value: sqlx::postgres::PgValueRef<'r>) -> Result<Self, sqlx::error::BoxDynError> { 224 let raw = <Base32<32>>::decode(value)?; 225 Ok(Self(raw)) 226 } 227 }