Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
nanderstabel committed Oct 9, 2024
1 parent f62388e commit eae028b
Show file tree
Hide file tree
Showing 33 changed files with 569 additions and 219 deletions.
280 changes: 226 additions & 54 deletions Cargo.lock

Large diffs are not rendered by default.

31 changes: 20 additions & 11 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,28 +19,37 @@ edition = "2021"
rust-version = "1.76.0"

[workspace.dependencies]
did_manager = { git = "https://[email protected]/impierce/did-manager.git", tag = "v1.0.0-beta.3" }
siopv2 = { git = "https://[email protected]/impierce/openid4vc.git", rev = "12fed14" }
oid4vci = { git = "https://[email protected]/impierce/openid4vc.git", rev = "12fed14" }
oid4vc-core = { git = "https://[email protected]/impierce/openid4vc.git", rev = "12fed14" }
oid4vc-manager = { git = "https://[email protected]/impierce/openid4vc.git", rev = "12fed14" }
oid4vp = { git = "https://[email protected]/impierce/openid4vc.git", rev = "12fed14" }
did_manager = { path = "../did-manager" }
# did_manager = { git = "https://[email protected]/impierce/did-manager.git", tag = "v1.0.0-beta.3" }
siopv2 = { path = "../openid4vc/siopv2" }
oid4vci = { path = "../openid4vc/oid4vci" }
oid4vc-core = { path = "../openid4vc/oid4vc-core" }
oid4vc-manager = { path = "../openid4vc/oid4vc-manager" }
oid4vp = { path = "../openid4vc/oid4vp" }
# siopv2 = { git = "https://[email protected]/impierce/openid4vc.git", rev = "12fed14" }
# oid4vci = { git = "https://[email protected]/impierce/openid4vc.git", rev = "12fed14" }
# oid4vc-core = { git = "https://[email protected]/impierce/openid4vc.git", rev = "12fed14" }
# oid4vc-manager = { git = "https://[email protected]/impierce/openid4vc.git", rev = "12fed14" }
# oid4vp = { git = "https://[email protected]/impierce/openid4vc.git", rev = "12fed14" }

async-trait = "0.1"
axum = { version = "0.7", features = ["tracing"] }
base64 = "0.22"
cqrs-es = "0.4.2"
futures = "0.3"
identity_core = "1.3"
identity_credential = { version = "1.3", default-features = false, features = [
identity_core = { path = "../identity.rs/identity_core" }
identity_credential = { path = "../identity.rs/identity_credential", default-features = false, features = [
"validator",
"credential",
"presentation",
"domain-linkage",
"sd-jwt-vc"
] }
identity_did = { version = "1.3" }
identity_iota = { version = "1.3" }
identity_verification = { version = "1.3", default-features = false }

identity_did = { path = "../identity.rs/identity_did" }
identity_document = { path = "../identity.rs/identity_document" }
identity_iota = { path = "../identity.rs/identity_iota" }
identity_verification = { path = "../identity.rs/identity_verification", default-features = false }
jsonwebtoken = "9.3"
lazy_static = "1.4"
mime = { version = "0.3" }
Expand Down
104 changes: 70 additions & 34 deletions agent_api_rest/postman/ssi-agent.postman_collection.json
Original file line number Diff line number Diff line change
Expand Up @@ -800,13 +800,18 @@
"exec": [
"const jsonData = JSON.parse(responseBody);",
"",
"if (jsonData && typeof jsonData === 'object') {",
" const receivedOfferId = Object.keys(jsonData)[0];",
"if (Array.isArray(jsonData) && jsonData.length > 0) {",
" const firstItem = jsonData[0];",
"",
" if (receivedOfferId) {",
" pm.collectionVariables.set(\"RECEIVED_OFFER_ID\", receivedOfferId);",
" if (firstItem && typeof firstItem === 'object') {",
" const receivedOfferId = firstItem.received_offer_id;",
"",
" if (receivedOfferId) {",
" pm.collectionVariables.set(\"RECEIVED_OFFER_ID\", receivedOfferId);",
" }",
" }",
"}"
"}",
""
],
"type": "text/javascript",
"packages": {}
Expand Down Expand Up @@ -911,13 +916,18 @@
"exec": [
"const jsonData = JSON.parse(responseBody);",
"",
"if (jsonData && typeof jsonData === 'object') {",
" const holderCredentialId = Object.keys(jsonData)[0];",
"if (Array.isArray(jsonData) && jsonData.length > 0) {",
" const firstItem = jsonData[0];",
"",
" if (firstItem && typeof firstItem === 'object') {",
" const holderCredentialId = firstItem.holder_credential_id;",
"",
" if (holderCredentialId) {",
" pm.collectionVariables.set(\"HOLDER_CREDENTIAL_ID\", holderCredentialId);",
" if (holderCredentialId) {",
" pm.collectionVariables.set(\"HOLDER_CREDENTIAL_ID\", holderCredentialId);",
" }",
" }",
"}"
"}",
""
],
"type": "text/javascript",
"packages": {}
Expand All @@ -926,8 +936,11 @@
{
"listen": "prerequest",
"script": {
"exec": [],
"type": "text/javascript"
"exec": [
""
],
"type": "text/javascript",
"packages": {}
}
}
],
Expand Down Expand Up @@ -977,13 +990,18 @@
"exec": [
"const jsonData = JSON.parse(responseBody);",
"",
"if (jsonData && typeof jsonData === 'object') {",
" const presentationId = Object.keys(jsonData)[0];",
"if (Array.isArray(jsonData) && jsonData.length > 0) {",
" const firstItem = jsonData[0];",
"",
" if (firstItem && typeof firstItem === 'object') {",
" const presentationId = firstItem.presentation_id;",
"",
" if (presentationId) {",
" pm.collectionVariables.set(\"PRESENTATION_ID\", presentationId);",
" if (presentationId) {",
" pm.collectionVariables.set(\"PRESENTATION_ID\", presentationId);",
" }",
" }",
"}"
"}",
""
],
"type": "text/javascript",
"packages": {}
Expand All @@ -992,8 +1010,11 @@
{
"listen": "prerequest",
"script": {
"exec": [],
"type": "text/javascript"
"exec": [
""
],
"type": "text/javascript",
"packages": {}
}
}
],
Expand Down Expand Up @@ -1125,13 +1146,18 @@
"exec": [
"const jsonData = JSON.parse(responseBody);",
"",
"if (jsonData && typeof jsonData === 'object') {",
" const connectionId = Object.keys(jsonData)[0];",
"if (Array.isArray(jsonData) && jsonData.length > 0) {",
" const firstItem = jsonData[0];",
"",
" if (firstItem && typeof firstItem === 'object') {",
" const connectionId = firstItem.connection_id;",
"",
" if (connectionId) {",
" pm.collectionVariables.set(\"CONNECTION_ID\", connectionId);",
" if (connectionId) {",
" pm.collectionVariables.set(\"CONNECTION_ID\", connectionId);",
" }",
" }",
"}"
"}",
""
],
"type": "text/javascript",
"packages": {}
Expand Down Expand Up @@ -1173,13 +1199,18 @@
"exec": [
"const jsonData = JSON.parse(responseBody);",
"",
"if (jsonData && typeof jsonData === 'object') {",
" const connectionId = Object.keys(jsonData)[0];",
"if (Array.isArray(jsonData) && jsonData.length > 0) {",
" const firstItem = jsonData[0];",
"",
" if (connectionId) {",
" pm.collectionVariables.set(\"CONNECTION_ID\", connectionId);",
" if (firstItem && typeof firstItem === 'object') {",
" const connectionId = firstItem.connection_id;",
"",
" if (connectionId) {",
" pm.collectionVariables.set(\"CONNECTION_ID\", connectionId);",
" }",
" }",
"}"
"}",
""
],
"type": "text/javascript",
"packages": {}
Expand Down Expand Up @@ -1227,13 +1258,18 @@
"exec": [
"const jsonData = JSON.parse(responseBody);",
"",
"if (jsonData && typeof jsonData === 'object') {",
" const connectionId = Object.keys(jsonData)[0];",
"if (Array.isArray(jsonData) && jsonData.length > 0) {",
" const firstItem = jsonData[0];",
"",
" if (firstItem && typeof firstItem === 'object') {",
" const connectionId = firstItem.connection_id;",
"",
" if (connectionId) {",
" pm.collectionVariables.set(\"CONNECTION_ID\", connectionId);",
" if (connectionId) {",
" pm.collectionVariables.set(\"CONNECTION_ID\", connectionId);",
" }",
" }",
"}"
"}",
""
],
"type": "text/javascript",
"packages": {}
Expand Down
10 changes: 9 additions & 1 deletion agent_api_rest/src/holder/holder/credentials/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,15 @@ use serde_json::json;
#[axum_macros::debug_handler]
pub(crate) async fn credentials(State(state): State<HolderState>) -> Response {
match query_handler("all_holder_credentials", &state.query.all_holder_credentials).await {
Ok(Some(all_credentials_view)) => (StatusCode::OK, Json(all_credentials_view)).into_response(),
Ok(Some(all_credentials_view)) => {
let all_credentials = all_credentials_view
.credentials
.into_iter()
.map(|(_, credential_view)| credential_view)
.collect::<Vec<_>>();

(StatusCode::OK, Json(all_credentials)).into_response()
}
Ok(None) => (StatusCode::OK, Json(json!({}))).into_response(),
_ => StatusCode::INTERNAL_SERVER_ERROR.into_response(),
}
Expand Down
30 changes: 18 additions & 12 deletions agent_api_rest/src/holder/holder/offers/accept.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,23 @@ use axum::{
use hyper::StatusCode;

#[axum_macros::debug_handler]
pub(crate) async fn accept(State(state): State<HolderState>, Path(offer_id): Path<String>) -> Response {
pub(crate) async fn accept(State(state): State<HolderState>, Path(received_offer_id): Path<String>) -> Response {
// TODO: General note that also applies to other endpoints: currently we are using Application Layer logic in the
// REST API. This is not ideal and should be changed. The REST API should only be responsible for handling HTTP
// Requests and Responses.
// Furthermore, the Application Layer (not implemented yet) should be kept very thin as well. See: https://github.com/impierce/ssi-agent/issues/114

// Accept the Credential Offer if it exists
match query_handler(&offer_id, &state.query.received_offer).await {
match query_handler(&received_offer_id, &state.query.received_offer).await {
Ok(Some(ReceivedOfferView { .. })) => {
let command = OfferCommand::AcceptCredentialOffer {
offer_id: offer_id.clone(),
received_offer_id: received_offer_id.clone(),
};

if command_handler(&offer_id, &state.command.offer, command).await.is_err() {
if command_handler(&received_offer_id, &state.command.offer, command)
.await
.is_err()
{
// TODO: add better Error responses. This needs to be done properly in all endpoints once
// https://github.com/impierce/openid4vc/issues/78 is fixed.
return StatusCode::INTERNAL_SERVER_ERROR.into_response();
Expand All @@ -36,42 +39,45 @@ pub(crate) async fn accept(State(state): State<HolderState>, Path(offer_id): Pat
}

let command = OfferCommand::SendCredentialRequest {
offer_id: offer_id.clone(),
received_offer_id: received_offer_id.clone(),
};

// Send the Credential Request
if command_handler(&offer_id, &state.command.offer, command).await.is_err() {
if command_handler(&received_offer_id, &state.command.offer, command)
.await
.is_err()
{
// TODO: add better Error responses. This needs to be done properly in all endpoints once
// https://github.com/impierce/openid4vc/issues/78 is fixed.
return StatusCode::INTERNAL_SERVER_ERROR.into_response();
}

let credentials = match query_handler(&offer_id, &state.query.received_offer).await {
let credentials = match query_handler(&received_offer_id, &state.query.received_offer).await {
Ok(Some(ReceivedOfferView { credentials, .. })) => credentials,
_ => return StatusCode::INTERNAL_SERVER_ERROR.into_response(),
};

for OfferCredential {
credential_id,
holder_credential_id,
credential,
} in credentials
{
let command = CredentialCommand::AddCredential {
credential_id: credential_id.clone(),
offer_id: offer_id.clone(),
holder_credential_id: holder_credential_id.clone(),
received_offer_id: received_offer_id.clone(),
credential,
};

// Add the Credential to the state.
if command_handler(&credential_id, &state.command.credential, command)
if command_handler(&holder_credential_id, &state.command.credential, command)
.await
.is_err()
{
return StatusCode::INTERNAL_SERVER_ERROR.into_response();
}
}

match query_handler(&offer_id, &state.query.received_offer).await {
match query_handler(&received_offer_id, &state.query.received_offer).await {
Ok(Some(received_offer_view)) => (StatusCode::OK, Json(received_offer_view)).into_response(),
Ok(None) => StatusCode::NOT_FOUND.into_response(),
_ => StatusCode::INTERNAL_SERVER_ERROR.into_response(),
Expand Down
10 changes: 9 additions & 1 deletion agent_api_rest/src/holder/holder/offers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,15 @@ use serde_json::json;
#[axum_macros::debug_handler]
pub(crate) async fn offers(State(state): State<HolderState>) -> Response {
match query_handler("all_received_offers", &state.query.all_received_offers).await {
Ok(Some(all_offers_view)) => (StatusCode::OK, Json(all_offers_view)).into_response(),
Ok(Some(all_received_offers_view)) => {
let all_received_offers = all_received_offers_view
.received_offers
.into_iter()
.map(|(_, credential_view)| credential_view)
.collect::<Vec<_>>();

(StatusCode::OK, Json(all_received_offers)).into_response()
}
Ok(None) => (StatusCode::OK, Json(json!({}))).into_response(),
_ => StatusCode::INTERNAL_SERVER_ERROR.into_response(),
}
Expand Down
9 changes: 6 additions & 3 deletions agent_api_rest/src/holder/holder/offers/reject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@ use axum::{
use hyper::StatusCode;

#[axum_macros::debug_handler]
pub(crate) async fn reject(State(state): State<HolderState>, Path(offer_id): Path<String>) -> Response {
pub(crate) async fn reject(State(state): State<HolderState>, Path(received_offer_id): Path<String>) -> Response {
let command = OfferCommand::RejectCredentialOffer {
offer_id: offer_id.clone(),
received_offer_id: received_offer_id.clone(),
};

// Remove the Credential Offer from the state.
if command_handler(&offer_id, &state.command.offer, command).await.is_err() {
if command_handler(&received_offer_id, &state.command.offer, command)
.await
.is_err()
{
// TODO: add better Error responses. This needs to be done properly in all endpoints once
// https://github.com/impierce/openid4vc/issues/78 is fixed.
return StatusCode::INTERNAL_SERVER_ERROR.into_response();
Expand Down
10 changes: 9 additions & 1 deletion agent_api_rest/src/holder/holder/presentations/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,15 @@ use tracing::info;
#[axum_macros::debug_handler]
pub(crate) async fn get_presentations(State(state): State<HolderState>) -> Response {
match query_handler("all_presentations", &state.query.all_presentations).await {
Ok(Some(all_presentations_view)) => (StatusCode::OK, Json(all_presentations_view)).into_response(),
Ok(Some(all_presentations_view)) => {
let all_presentations = all_presentations_view
.presentations
.into_iter()
.map(|(_, credential_view)| credential_view)
.collect::<Vec<_>>();

(StatusCode::OK, Json(all_presentations)).into_response()
}
Ok(None) => (StatusCode::OK, Json(json!({}))).into_response(),
_ => StatusCode::INTERNAL_SERVER_ERROR.into_response(),
}
Expand Down
6 changes: 3 additions & 3 deletions agent_api_rest/src/holder/openid4vci/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ pub(crate) async fn offers(State(state): State<HolderState>, Json(payload): Json
return (StatusCode::BAD_REQUEST, "invalid payload").into_response();
};

let offer_id = uuid::Uuid::new_v4().to_string();
let received_offer_id = uuid::Uuid::new_v4().to_string();

let command = OfferCommand::ReceiveCredentialOffer {
offer_id: offer_id.clone(),
received_offer_id: received_offer_id.clone(),
credential_offer,
};

// Add the Credential Offer to the state.
match command_handler(&offer_id, &state.command.offer, command).await {
match command_handler(&received_offer_id, &state.command.offer, command).await {
Ok(_) => StatusCode::OK.into_response(),
// TODO: add better Error responses. This needs to be done properly in all endpoints once
// https://github.com/impierce/openid4vc/issues/78 is fixed.
Expand Down
Loading

0 comments on commit eae028b

Please sign in to comment.