use serde::Serialize;
use serde::de::DeserializeOwned;
use serde_json::Value;
use trust_tasks_rs::Payload as _;
use trust_tasks_rs::specs::auth::oob as spec;
pub use spec::cancel::v0_1::{Payload as CancelPayload, Response as CancelResponse};
pub use spec::claim::v0_1::{Payload as ClaimPayload, Response as Step1Response};
pub use spec::grant::v0_1::{Payload as GrantPayload, PayloadDecision as GrantDecision};
pub use spec::grant::v0_2::Payload as GrantPayloadV0_2;
pub use spec::identify::v0_1::Payload as IdentifyPayload;
pub use spec::prove::v0_1::{Payload as ProvePayload, Response as Step2Response};
pub use spec::prove::v0_2::{Payload as ProvePayloadV0_2, Response as Step2ResponseV0_2};
pub use spec::redeem::v0_1::{Payload as RedeemPayload, Response as RedeemResponse};
pub use spec::request::v0_1::{Payload as RequestPayload, Response as RequestResponse};
pub use spec::respond::v0_1::{Payload as RespondPayload, Response as RespondResponse};
pub use spec::respond::v0_2::{Payload as RespondPayloadV0_2, Response as RespondResponseV0_2};
pub const TYPE_REQUEST: &str = RequestPayload::TYPE_URI;
pub const TYPE_CLAIM: &str = ClaimPayload::TYPE_URI;
pub const TYPE_PROVE: &str = ProvePayload::TYPE_URI;
pub const TYPE_IDENTIFY: &str = IdentifyPayload::TYPE_URI;
pub const TYPE_RESPOND: &str = RespondPayload::TYPE_URI;
pub const TYPE_GRANT: &str = GrantPayload::TYPE_URI;
pub const TYPE_REDEEM: &str = RedeemPayload::TYPE_URI;
pub const TYPE_CANCEL: &str = CancelPayload::TYPE_URI;
pub const TYPE_PROVE_V0_2: &str = ProvePayloadV0_2::TYPE_URI;
pub const TYPE_RESPOND_V0_2: &str = RespondPayloadV0_2::TYPE_URI;
pub const TYPE_GRANT_V0_2: &str = GrantPayloadV0_2::TYPE_URI;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OobVersion {
V0_1,
V0_2,
}
impl OobVersion {
pub fn prove_type(self) -> &'static str {
match self {
OobVersion::V0_1 => TYPE_PROVE,
OobVersion::V0_2 => TYPE_PROVE_V0_2,
}
}
pub fn respond_type(self) -> &'static str {
match self {
OobVersion::V0_1 => TYPE_RESPOND,
OobVersion::V0_2 => TYPE_RESPOND_V0_2,
}
}
pub fn grant_type(self) -> &'static str {
match self {
OobVersion::V0_1 => TYPE_GRANT,
OobVersion::V0_2 => TYPE_GRANT_V0_2,
}
}
}
pub fn read<T: DeserializeOwned>(value: &Value) -> Result<T, String> {
serde_json::from_value(value.clone()).map_err(|e| e.to_string())
}
pub fn write<T: DeserializeOwned + Serialize>(value: Value) -> Result<Value, String> {
let typed: T = read(&value)?;
serde_json::to_value(typed).map_err(|e| e.to_string())
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum OobState {
Pending,
Claimed,
Identified,
Approved,
Consumed,
Declined,
Cancelled,
Expired,
}
impl OobState {
pub fn as_str(self) -> &'static str {
match self {
OobState::Pending => "pending",
OobState::Claimed => "claimed",
OobState::Identified => "identified",
OobState::Approved => "approved",
OobState::Consumed => "consumed",
OobState::Declined => "declined",
OobState::Cancelled => "cancelled",
OobState::Expired => "expired",
}
}
pub fn is_final(self) -> bool {
matches!(
self,
OobState::Consumed | OobState::Declined | OobState::Cancelled | OobState::Expired
)
}
pub fn in_decision_window(self) -> bool {
matches!(
self,
OobState::Claimed | OobState::Identified | OobState::Approved
)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OobErrorCode {
PurposeUnsupported,
ModeUnsupported,
KeyUnsupported,
RateLimited,
RequestNotFound,
RequestExpired,
AlreadyClaimed,
NotClaimant,
NumberMismatch,
NotAuthorized,
AlreadyDecided,
ContextMismatch,
Pending,
Declined,
NotStarter,
MalformedRequest,
}
impl OobErrorCode {
pub fn as_str(self) -> &'static str {
use spec::{claim, prove, redeem, request, respond};
match self {
OobErrorCode::PurposeUnsupported => {
request::v0_1::error_codes::PURPOSE_UNSUPPORTED.code
}
OobErrorCode::ModeUnsupported => request::v0_1::error_codes::MODE_UNSUPPORTED.code,
OobErrorCode::KeyUnsupported => request::v0_1::error_codes::KEY_UNSUPPORTED.code,
OobErrorCode::RateLimited => request::v0_1::error_codes::RATE_LIMITED.code,
OobErrorCode::RequestNotFound => redeem::v0_1::error_codes::REQUEST_NOT_FOUND.code,
OobErrorCode::RequestExpired => redeem::v0_1::error_codes::REQUEST_EXPIRED.code,
OobErrorCode::AlreadyClaimed => claim::v0_1::error_codes::ALREADY_CLAIMED.code,
OobErrorCode::NotClaimant => prove::v0_1::error_codes::NOT_CLAIMANT.code,
OobErrorCode::NumberMismatch => prove::v0_1::error_codes::NUMBER_MISMATCH.code,
OobErrorCode::NotAuthorized => prove::v0_1::error_codes::NOT_AUTHORIZED.code,
OobErrorCode::AlreadyDecided => respond::v0_1::error_codes::ALREADY_DECIDED.code,
OobErrorCode::ContextMismatch => respond::v0_1::error_codes::CONTEXT_MISMATCH.code,
OobErrorCode::Pending => redeem::v0_1::error_codes::PENDING.code,
OobErrorCode::Declined => redeem::v0_1::error_codes::DECLINED.code,
OobErrorCode::NotStarter => redeem::v0_1::error_codes::NOT_STARTER.code,
OobErrorCode::MalformedRequest => "malformedRequest",
}
}
pub fn http_status(self) -> u16 {
match self {
OobErrorCode::RateLimited => 429,
OobErrorCode::RequestNotFound => 404,
OobErrorCode::NotAuthorized | OobErrorCode::NotClaimant | OobErrorCode::NotStarter => {
403
}
OobErrorCode::MalformedRequest
| OobErrorCode::KeyUnsupported
| OobErrorCode::PurposeUnsupported
| OobErrorCode::ModeUnsupported => 400,
_ => 409,
}
}
}