Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 23 additions & 3 deletions crates/claims/crates/jws/src/compact/bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ pub use base64::DecodeError as Base64DecodeError;
use base64::Engine;
use ssi_claims_core::{ProofValidationError, ResolverProvider, Verification};
use ssi_jwk::JWKResolver;
use std::{borrow::Cow, ops::Deref};
use std::{
borrow::{Borrow, Cow},
ops::Deref,
};

/// Borrowed JWS without any encoding guaranties.
///
Expand Down Expand Up @@ -243,6 +246,17 @@ impl JwsSlice {
}
}

impl ToOwned for JwsSlice {
type Owned = JwsVec;

fn to_owned(&self) -> Self::Owned {
unsafe {
// SAFETY: `Jws` represent a valid JWS by construction.
JwsVec::new_unchecked(self.0.to_owned())
}
}
}

/// Owned JWS without any encoding guaranties.
///
/// This type is similar to the [`JwsBuf`](crate::JwsBuf) type.
Expand Down Expand Up @@ -303,7 +317,7 @@ impl JwsVec {
Self::new_unchecked(bytes)
}

pub fn as_compact_jws(&self) -> &JwsSlice {
pub fn as_jws_slice(&self) -> &JwsSlice {
unsafe { JwsSlice::new_unchecked(&self.0) }
}

Expand Down Expand Up @@ -335,6 +349,12 @@ impl Deref for JwsVec {
type Target = JwsSlice;

fn deref(&self) -> &Self::Target {
self.as_compact_jws()
self.as_jws_slice()
}
}

impl Borrow<JwsSlice> for JwsVec {
fn borrow(&self) -> &JwsSlice {
self.as_jws_slice()
}
}
30 changes: 26 additions & 4 deletions crates/claims/crates/jws/src/compact/str.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use base64::Engine;
use core::fmt;
use std::{ops::Deref, str::FromStr};
use std::{borrow::Borrow, ops::Deref, str::FromStr};

use crate::{
utils::is_url_safe_base64_char, DecodeError, DecodedJws, Header, InvalidJws, JwsSlice,
Expand Down Expand Up @@ -105,6 +105,18 @@ impl JwsStr {
}
}

impl ToOwned for JwsStr {
type Owned = JwsString;

fn to_owned(&self) -> Self::Owned {
unsafe {
// SAFETY: a `JwsStr` represents a valid UTF-8 encoded JWS by
// construction.
JwsString::new_unchecked(self.0.to_owned().into_bytes())
}
}
}

impl Deref for JwsStr {
type Target = JwsSlice;

Expand Down Expand Up @@ -265,7 +277,7 @@ impl JwsString {
Self::new_unchecked(bytes)
}

pub fn as_compact_jws_str(&self) -> &JwsStr {
pub fn as_jws_str(&self) -> &JwsStr {
unsafe { JwsStr::new_unchecked(self.0.as_bytes()) }
}

Expand All @@ -278,6 +290,10 @@ impl JwsString {
self.0
}

pub fn into_bytes(self) -> Vec<u8> {
self.0.into_bytes()
}

/// Decodes the entire JWS while preserving the signing bytes so they can
/// be verified.
pub fn into_decoded(self) -> Result<DecodedJws<'static>, DecodeError> {
Expand All @@ -289,7 +305,13 @@ impl Deref for JwsString {
type Target = JwsStr;

fn deref(&self) -> &Self::Target {
self.as_compact_jws_str()
self.as_jws_str()
}
}

impl Borrow<JwsStr> for JwsString {
fn borrow(&self) -> &JwsStr {
self.as_jws_str()
}
}

Expand Down Expand Up @@ -332,7 +354,7 @@ impl<'de> serde::Deserialize<'de> for JwsString {
type Value = JwsString;

fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("compact JWS")
formatter.write_str("UTF-8 encoded JWS")
}

fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
Expand Down
31 changes: 26 additions & 5 deletions crates/claims/crates/jws/src/compact/url_safe.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use base64::Engine;
use core::fmt;
use ssi_core::BytesBuf;
use std::{ops::Deref, str::FromStr};
use std::{borrow::Borrow, ops::Deref, str::FromStr};

use crate::{
utils::is_url_safe_base64_char, DecodeError, DecodedJws, Header, InvalidJws, JwsSlice, JwsStr,
Expand Down Expand Up @@ -134,6 +134,17 @@ impl Jws {
}
}

impl ToOwned for Jws {
type Owned = JwsBuf;

fn to_owned(&self) -> Self::Owned {
unsafe {
// SAFETY: a `Jws` is a valid URL-safe JWS by construction.
JwsBuf::new_unchecked(self.0.to_owned().into_bytes())
}
}
}

impl Deref for Jws {
type Target = JwsSlice;

Expand Down Expand Up @@ -286,8 +297,12 @@ impl JwsBuf {
Self::new_unchecked(bytes)
}

pub fn as_compact_jws_str(&self) -> &Jws {
unsafe { Jws::new_unchecked(self.0.as_bytes()) }
pub fn as_jws_str(&self) -> &Jws {
unsafe {
// SAFETY: we validated that the inner value is an URL-safe JWS in
// the `new` function.
Jws::new_unchecked(self.0.as_bytes())
}
}

pub fn into_signing_bytes(mut self) -> String {
Expand All @@ -310,7 +325,13 @@ impl Deref for JwsBuf {
type Target = Jws;

fn deref(&self) -> &Self::Target {
self.as_compact_jws_str()
self.as_jws_str()
}
}

impl Borrow<Jws> for JwsBuf {
fn borrow(&self) -> &Jws {
self.as_jws_str()
}
}

Expand Down Expand Up @@ -353,7 +374,7 @@ impl<'de> serde::Deserialize<'de> for JwsBuf {
type Value = JwsBuf;

fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("compact JWS")
formatter.write_str("URL-safe JWS")
}

fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
Expand Down
13 changes: 13 additions & 0 deletions crates/claims/crates/jws/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,11 @@ impl<'a, T> DecodedJws<'a, T> {
.unwrap()
}

/// Takes ownership of the signing bytes, cloning them if necessary.
pub fn into_owned_signing_bytes(self) -> DecodedJws<'static, T> {
DecodedJws::new(self.signing_bytes.into_owned_bytes(), self.signature)
}

/// Verify the JWS signature.
///
/// This will check the signature and the validity of the decoded payload.
Expand Down Expand Up @@ -318,6 +323,14 @@ impl<'a, T> DecodedSigningBytes<'a, T> {
payload: f(self.payload)?,
})
}

pub fn into_owned_bytes(self) -> DecodedSigningBytes<'static, T> {
DecodedSigningBytes {
bytes: Cow::Owned(self.bytes.into_owned()),
header: self.header,
payload: self.payload,
}
}
}

impl<T: ?Sized + ToOwned> DecodedSigningBytes<'_, &T> {
Expand Down
17 changes: 11 additions & 6 deletions crates/claims/crates/jwt/src/decoding.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use serde::de::DeserializeOwned;
use ssi_claims_core::{DateTimeProvider, ProofValidationError, ResolverProvider, Verification};
use ssi_jwk::JWKResolver;
use ssi_jws::{DecodeError as JWSDecodeError, DecodedJws, JwsSlice, JwsStr, JwsString, JwsVec};
use ssi_jws::{
DecodeError as JWSDecodeError, DecodedJws, Jws, JwsBuf, JwsSlice, JwsStr, JwsString, JwsVec,
};

use crate::{AnyClaims, JWTClaims};

Expand Down Expand Up @@ -73,7 +75,7 @@ impl ToDecodedJwt for JwsStr {
}
}

impl ToDecodedJwt for JwsVec {
impl ToDecodedJwt for Jws {
fn to_decoded_custom_jwt<C: DeserializeOwned>(&self) -> Result<DecodedJwt<C>, DecodeError> {
JwsSlice::to_decoded_custom_jwt(self)
}
Expand All @@ -88,13 +90,16 @@ impl IntoDecodedJwt for JwsVec {
}
}

impl ToDecodedJwt for JwsString {
fn to_decoded_custom_jwt<C: DeserializeOwned>(&self) -> Result<DecodedJwt<C>, DecodeError> {
JwsSlice::to_decoded_custom_jwt(self)
impl IntoDecodedJwt for JwsString {
fn into_decoded_custom_jwt<C: DeserializeOwned>(
self,
) -> Result<DecodedJwt<'static, C>, DecodeError> {
self.into_decoded()?
.try_map(|bytes| serde_json::from_slice(&bytes).map_err(Into::into))
}
}

impl IntoDecodedJwt for JwsString {
impl IntoDecodedJwt for JwsBuf {
fn into_decoded_custom_jwt<C: DeserializeOwned>(
self,
) -> Result<DecodedJwt<'static, C>, DecodeError> {
Expand Down