Skip to content

Commit

Permalink
Add base url optional parameter (#265)
Browse files Browse the repository at this point in the history
* Add optional parameter tails_base_url when writing revocation registry

Signed-off-by: Miroslav Kovar <miroslavkovar@protonmail.com>
  • Loading branch information
mirgee authored Apr 27, 2021
1 parent 3117815 commit d79d41c
Show file tree
Hide file tree
Showing 9 changed files with 86 additions and 28 deletions.
3 changes: 2 additions & 1 deletion agents/node/vcxagent-core/src/services/service-prover.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ module.exports.createServiceProver = function createServiceProver ({ logger, loa
}

async function buildDisclosedProof (disclosedProofId, proofRequest) {
const disclosedProof = await DisclosedProof.create({ sourceId: 'proof', request: JSON.stringify(proofRequest) })
const request = typeof proofRequest === 'string' ? proofRequest : JSON.stringify(proofRequest)
const disclosedProof = await DisclosedProof.create({ sourceId: 'proof', request })
await saveDisclosedProof(disclosedProofId, disclosedProof)
}

Expand Down
12 changes: 10 additions & 2 deletions agents/node/vcxagent-core/src/services/service-verifier.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ module.exports.createServiceVerifier = function createServiceVerifier ({ logger,
}

async function sendProofRequest (connectionId, proofId) {
logger.debug(`Verifier sending proof request proofId=${proofId}, connectionId=${connectionId}`)
const connection = await loadConnection(connectionId)
const proof = await loadProof(proofId)
await proof.requestProof(connection)
const state = await proof.getState()
await saveProof(proofId, proof)
const proofRequestMessage = proof.getProofRequestMessage()
const proofRequestMessage = await proof.getProofRequestMessage()
return { state, proofRequestMessage }
}

Expand All @@ -35,6 +36,12 @@ module.exports.createServiceVerifier = function createServiceVerifier ({ logger,
return await proof.getState()
}

async function getProofState (proofId) {
const proof = await loadProof(proofId)
const { proofState } = await proof.getProof()
return proofState
}

async function listIds () {
return listProofIds()
}
Expand All @@ -59,6 +66,7 @@ module.exports.createServiceVerifier = function createServiceVerifier ({ logger,

listIds,
printInfo,
getState
getState,
getProofState
}
}
10 changes: 9 additions & 1 deletion libvcx/src/api/credential_def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,16 @@ use crate::utils::threadpool::spawn;
/// TODO: Currently supports ISSUANCE BY DEFAULT, support for ISSUANCE ON DEMAND will be added as part of ticket: IS-1074
/// support_revocation: true|false - Optional, by default its false
/// tails_file: path to tails file - Optional if support_revocation is false
/// tails_url: URL where the holder can download the tails file - Optional if support_revocation is false
/// tails_base_url: incomplete URL where the holder can download the tails file - Optional if support_revocation is false
/// max_creds: size of tails file - Optional if support_revocation is false
/// # Examples config -> "{}" | "{"support_revocation":false}" | "{"support_revocation":true, "tails_file": "/tmp/tailsfile.txt", "max_creds": 1}"
/// If tails_location is specified, the exact value is written to the ledger and obtainable via vcx_credential_get_tails_location.
/// If tails_base_location in specified, the value written to the ledger and obtainable via vcx_credential_get_tails_location is "{tails_base_location}/{tails_hash}".
/// It is not allowed to specify both tails_location and tails_base_location.
/// # Examples config -> "{}"
/// | "{"support_revocation":false}"
/// | "{"support_revocation":true, "tails_file": "/tmp/tailsfile.txt", "max_creds": 1, "tails_url": "https://dummy.faber.org/DvVhi9j4a3RYdZoQxBerhUUHnyBf8k4j8a5Zp2vgLHpW"}"
/// | "{"support_revocation":true, "tails_file": "/tmp/tailsfile.txt", "max_creds": 1, "tails_base_url": "https://dummy.faber.org"}"
/// cb: Callback that provides CredentialDef handle and error status of request.
///
/// payment_handle: future use (currently uses any address in wallet)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use crate::error::prelude::*;
use crate::aries::messages::a2a::{A2AMessage, MessageId};
use crate::aries::messages::attachment::{AttachmentId, Attachments};
use crate::aries::messages::connection::service::Service;
use crate::libindy::proofs::proof_request::ProofRequestData;

#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Default)]
Expand Down Expand Up @@ -30,6 +29,7 @@ impl PresentationRequest {
}

pub fn set_request_presentations_attach(mut self, request_presentations: &PresentationRequestData) -> VcxResult<PresentationRequest> {
trace!("set_request_presentations_attach >> {:?}", request_presentations);
self.request_presentations_attach.add_base64_encoded_json_attachment(AttachmentId::PresentationRequest, json!(request_presentations))?;
Ok(self)
}
Expand Down
66 changes: 52 additions & 14 deletions libvcx/src/credential_def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,12 @@ pub struct CredentialDef {
state: PublicEntityStateType,
}

#[derive(Deserialize, Debug, Serialize)]
#[derive(Clone, Deserialize, Debug, Serialize)]
pub struct RevocationDetails {
pub support_revocation: Option<bool>,
pub tails_file: Option<String>,
pub tails_url: Option<String>,
pub tails_base_url: Option<String>,
pub max_creds: Option<u32>,
}

Expand All @@ -68,12 +69,20 @@ pub struct RevocationRegistryDefinition {
pub ver: String,
}

fn _replace_tails_location(new_rev_reg_def: &str, tails_url: &str) -> VcxResult<String> {
trace!("_replace_tails_location >>> new_rev_reg_def: {}, tails_url: {}", new_rev_reg_def, tails_url);
fn _replace_tails_location(new_rev_reg_def: &str, revocation_details: &RevocationDetails) -> VcxResult<String> {
trace!("_replace_tails_location >>> new_rev_reg_def: {}, revocation_details: {:?}", new_rev_reg_def, revocation_details);
let mut new_rev_reg_def: RevocationRegistryDefinition = serde_json::from_str(new_rev_reg_def)
.map_err(|err| VcxError::from_msg(VcxErrorKind::SerializationError, format!("Failed to deserialize new rev_reg_def: {:?}, error: {:?}", new_rev_reg_def, err)))?;

new_rev_reg_def.value.tails_location = String::from(tails_url);
let tails_location = match &revocation_details.tails_url {
Some(tails_url) => tails_url.to_string(),
None => match &revocation_details.tails_base_url {
Some(tails_base_url) => vec![tails_base_url.to_string(), new_rev_reg_def.value.tails_hash.to_owned()].join("/"),
None => return Err(VcxError::from_msg(VcxErrorKind::InvalidRevocationDetails, "Both tails_url and tails_base_location not found in revocation details"))
}
};

new_rev_reg_def.value.tails_location = String::from(tails_location);

serde_json::to_string(&new_rev_reg_def)
.map_err(|err| VcxError::from_msg(VcxErrorKind::SerializationError, format!("Failed to serialize new rev_reg_def: {:?}, error: {:?}", new_rev_reg_def, err)))
Expand Down Expand Up @@ -170,21 +179,21 @@ impl CredentialDef {
fn get_state(&self) -> u32 { self.state as u32 }

fn rotate_rev_reg(&mut self, revocation_details: &str) -> VcxResult<RevocationRegistry> {
debug!("rotate_rev_reg >>>");
debug!("rotate_rev_reg >>> revocation_details: {}", revocation_details);
let revocation_details = _parse_revocation_details(revocation_details)?;
let (tails_url, tails_file, max_creds, issuer_did) = (
revocation_details.tails_url.ok_or(VcxError::from_msg(VcxErrorKind::InvalidRevocationDetails, "tails_url not found in revocation details"))?,
revocation_details.tails_file.or(self.get_tails_file()),
let (tails_file, max_creds, issuer_did) = (
revocation_details.clone().tails_file.or(self.get_tails_file()),
revocation_details.max_creds.or(self.get_max_creds()),
self.issuer_did.as_ref());
self.issuer_did.as_ref()
);
match (&mut self.rev_reg, &tails_file, &max_creds, &issuer_did) {
(Some(rev_reg), Some(tails_file), Some(max_creds), Some(issuer_did)) => {
let tag = format!("tag{}", rev_reg.tag + 1);
let (rev_reg_id, rev_reg_def, rev_reg_entry) =
anoncreds::generate_rev_reg(&issuer_did, &self.id, &tails_file, *max_creds, tag.as_str())
.map_err(|err| err.map(VcxErrorKind::CreateRevRegDef, "Cannot create revocation registry defintion"))?;

let new_rev_reg_def = _replace_tails_location(&rev_reg_def, &tails_url)?;
let new_rev_reg_def = _replace_tails_location(&rev_reg_def, &revocation_details)?;

let rev_reg_def_payment_txn = anoncreds::publish_rev_reg_def(&issuer_did, &new_rev_reg_def)
.map_err(|err| err.map(VcxErrorKind::CreateCredDef, "Cannot publish revocation registry defintion"))?;
Expand Down Expand Up @@ -213,16 +222,23 @@ impl CredentialDef {
}

fn _parse_revocation_details(revocation_details: &str) -> VcxResult<RevocationDetails> {
serde_json::from_str::<RevocationDetails>(&revocation_details)
.to_vcx(VcxErrorKind::InvalidRevocationDetails, "Cannot deserialize RevocationDetails")
let revoc_details = serde_json::from_str::<RevocationDetails>(&revocation_details)
.to_vcx(VcxErrorKind::InvalidRevocationDetails, "Cannot deserialize RevocationDetails")?;

match revoc_details.tails_url.is_some() && revoc_details.tails_base_url.is_some() {
true => Err(VcxError::from_msg(VcxErrorKind::InvalidOption, "It is allowed to specify either tails_location or tails_base_location, but not both")),
false => Ok(revoc_details)
}
}

fn _maybe_set_url(rev_reg_def_json: &str, revocation_details: &RevocationDetails) -> VcxResult<String> {
let mut rev_reg_def: serde_json::Value = serde_json::from_str(&rev_reg_def_json)
let mut rev_reg_def: RevocationRegistryDefinition = serde_json::from_str(&rev_reg_def_json)
.map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Invalid RevocationRegistryDefinition: {:?}, err: {:?}", rev_reg_def_json, err)))?;

if let Some(tails_url) = &revocation_details.tails_url {
rev_reg_def["value"]["tailsLocation"] = serde_json::Value::String(tails_url.to_string());
rev_reg_def.value.tails_location = tails_url.to_string();
} else if let Some(tails_base_url) = &revocation_details.tails_base_url {
rev_reg_def.value.tails_location = vec![tails_base_url.to_string(), rev_reg_def.value.tails_hash.to_owned()].join("/")
}

serde_json::to_string(&rev_reg_def)
Expand Down Expand Up @@ -670,6 +686,28 @@ pub mod tests {
assert_eq!(rev_reg_def["value"]["tailsLocation"], utils::constants::TEST_TAILS_URL.to_string());
}

#[cfg(feature = "pool_tests")]
#[test]
fn test_tails_base_url_written_to_ledger() {
let _setup = SetupLibraryWalletPoolZeroFees::init();
let tails_url = utils::constants::TEST_TAILS_URL.to_string();

let (schema_id, _) = libindy::utils::anoncreds::tests::create_and_write_test_schema(utils::constants::DEFAULT_SCHEMA_ATTRS);
let did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).unwrap();

let revocation_details = json!({"support_revocation": true, "tails_file": get_temp_dir_path("tails.txt").to_str().unwrap(), "max_creds": 2, "tails_base_url": tails_url}).to_string();
let handle = create_and_publish_credentialdef("1".to_string(),
"test_tails_url_written_to_ledger".to_string(),
did,
schema_id,
"tag1".to_string(),
revocation_details).unwrap();
let rev_reg_def = get_rev_reg_def(handle).unwrap().unwrap();
let rev_reg_def: serde_json::Value = serde_json::from_str(&rev_reg_def).unwrap();
let tails_hash = get_tails_hash(handle).unwrap();
assert_eq!(rev_reg_def["value"]["tailsLocation"], vec![tails_url, tails_hash].join("/"));
}

#[cfg(feature = "pool_tests")]
#[test]
fn test_create_revocable_cred_def_with_payments() {
Expand Down
4 changes: 2 additions & 2 deletions libvcx/src/disclosed_proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ pub fn create_proof(source_id: &str, proof_req: &str) -> VcxResult<u32> {

let presentation_request: PresentationRequest = serde_json::from_str(proof_req)
.map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson,
format!("Strict `aries` protocol is enabled. Can not parse `aries` formatted Presentation Request: {}", err)))?;
format!("Strict `aries` protocol is enabled. Can not parse `aries` formatted Presentation Request: {}\nError: {}", proof_req, err)))?;

let proof = Prover::create(source_id, presentation_request)?;
HANDLE_MAP.add(proof)
Expand All @@ -55,7 +55,7 @@ pub fn create_proof_with_msgid(source_id: &str, connection_handle: u32, msg_id:

let presentation_request: PresentationRequest = serde_json::from_str(&proof_request)
.map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson,
format!("Strict `aries` protocol is enabled. Can not parse `aries` formatted Presentation Request: {}", err)))?;
format!("Strict `aries` protocol is enabled. Can not parse `aries` formatted Presentation Request: {}\nError: {}", proof_request, err)))?;

let proof = Prover::create(source_id, presentation_request)?;

Expand Down
10 changes: 5 additions & 5 deletions libvcx/src/libindy/utils/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ struct WalletConfig {
wallet_key_derivation: String,
wallet_type: Option<String>,
storage_config: Option<String>,
storage_credentials: Option<String>,
storage_credentials: Option<serde_json::Value>,
rekey: Option<String>,
rekey_derivation_method: Option<String>
}
Expand All @@ -25,7 +25,7 @@ struct WalletCredentials {
#[serde(skip_serializing_if = "Option::is_none")]
rekey: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
storage_credentials: Option<String>,
storage_credentials: Option<serde_json::Value>,
key_derivation_method: String,
#[serde(skip_serializing_if = "Option::is_none")]
rekey_derivation_method: Option<String>
Expand Down Expand Up @@ -83,7 +83,7 @@ pub fn create_wallet_from_config(config: &str) -> VcxResult<()> {
&config.wallet_key_derivation,
config.wallet_type.as_ref().map(String::as_str),
config.storage_config.as_ref().map(String::as_str),
config.storage_credentials.as_ref().map(String::as_str),
config.storage_credentials.as_ref().map(|s| s.to_string()).as_deref(),
)?;
trace!("Wallet with handle {:?} and config {:?} created", wh, config);

Expand Down Expand Up @@ -121,7 +121,7 @@ pub fn build_wallet_credentials(key: &str, storage_credentials: Option<&str>, ke
serde_json::to_string(&WalletCredentials {
key: String::from(key),
rekey: rekey.map(|s| s.into()),
storage_credentials: storage_credentials.map(|s| s.into()),
storage_credentials: storage_credentials.map(|s| serde_json::from_str(s).unwrap()),
key_derivation_method: String::from(key_derivation_method),
rekey_derivation_method: rekey_derivation_method.map(|s| s.into())
}).map_err(|err| VcxError::from_msg(VcxErrorKind::SerializationError, format!("Failed to serialize WalletCredentials, err: {:?}", err)))
Expand Down Expand Up @@ -165,7 +165,7 @@ pub fn create_and_open_as_main_wallet(wallet_name: &str, wallet_key: &str, key_d
pub fn open_wallet_directly(wallet_config: &str) -> VcxResult<WalletHandle> {
let config: WalletConfig = serde_json::from_str(wallet_config)
.map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot deserialize WalletConfig {:?}, err: {:?}", wallet_config, err)))?;
open_as_main_wallet(&config.wallet_name, &config.wallet_key, &config.wallet_key_derivation, config.wallet_type.as_deref(), config.storage_config.as_deref(), config.storage_credentials.as_deref(), config.rekey.as_deref(), config.rekey_derivation_method.as_deref())
open_as_main_wallet(&config.wallet_name, &config.wallet_key, &config.wallet_key_derivation, config.wallet_type.as_deref(), config.storage_config.as_deref(), config.storage_credentials.as_ref().map(|s| s.to_string()).as_deref(), config.rekey.as_deref(), config.rekey_derivation_method.as_deref())
}

pub fn close_main_wallet() -> VcxResult<()> {
Expand Down
5 changes: 4 additions & 1 deletion wrappers/node/src/api/credential-def.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ export interface IRevocationDetails {
supportRevocation?: boolean;
tailsFile?: string;
tailsUrl?: string;
tailsBaseUrl?: string;
}

export enum CredentialDefState {
Expand Down Expand Up @@ -120,8 +121,8 @@ export class CredentialDef extends VCXBase<ICredentialDefData> {
support_revocation: revocationDetails.supportRevocation,
tails_file: revocationDetails.tailsFile,
tails_url: revocationDetails.tailsUrl,
tails_base_url: revocationDetails.tailsBaseUrl,
};

try {
await credentialDef._create((cb) =>
rustAPI().vcx_credentialdef_create(
Expand Down Expand Up @@ -176,6 +177,7 @@ export class CredentialDef extends VCXBase<ICredentialDefData> {
support_revocation: revocationDetails.supportRevocation,
tails_file: revocationDetails.tailsFile,
tails_url: revocationDetails.tailsUrl,
tails_base_url: revocationDetails.tailsBaseUrl,
};
const credDefForEndorser = await createFFICallbackPromise<{
credDefTxn: string;
Expand Down Expand Up @@ -472,6 +474,7 @@ export class CredentialDef extends VCXBase<ICredentialDefData> {
max_creds: revocationDetails.maxCreds,
tails_file: revocationDetails.tailsFile,
tails_url: revocationDetails.tailsUrl,
tails_base_url: revocationDetails.tailsBaseUrl,
};
try {
const dataStr = await createFFICallbackPromise<string>(
Expand Down
2 changes: 1 addition & 1 deletion wrappers/node/src/api/proof.ts
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ export class Proof extends VCXBaseWithState<IProofData> {
commandHandle,
proof.sourceId,
JSON.stringify(createDataRest.attrs),
JSON.stringify(createDataRest.preds),
JSON.stringify(createDataRest.preds || []),
JSON.stringify(createDataRest.revocationInterval),
createDataRest.name,
cb,
Expand Down

0 comments on commit d79d41c

Please sign in to comment.