/// <summary>
    /// Projects a single geometry to the specified spatial reference.
    /// </summary>
    private static void ProjectAsync(Geometry geometry, SpatialReference spatialReference, EventHandler<GeometryEventArgs> callback)
    {
      CallbackHelper helper = new CallbackHelper(callback);

      ESRI.ArcGIS.Client.Tasks.GeometryService geometryService = new ESRI.ArcGIS.Client.Tasks.GeometryService(Url);

      geometryService.ProjectCompleted += helper.geometryService_ProjectCompleted;
      geometryService.ProjectAsync(new List<Graphic>(new Graphic[] { new Graphic() { Geometry = geometry } }), spatialReference);
    }
示例#2
0
        /// <summary>
        /// Opens the BLOB storage writer async.
        /// </summary>
        /// <returns>The BLOB storage writer async.</returns>
        /// <param name="type">Type.</param>
        /// <param name="configJson">Config json.</param>
        public static Task <BlobStorageWriter> OpenWriterAsync(string type, string configJson)
        {
            ParamGuard.NotNullOrWhiteSpace(type, "type");
            ParamGuard.NotNullOrWhiteSpace(configJson, "configJson");

            var taskCompletionSource = new TaskCompletionSource <BlobStorageWriter>();
            var commandHandle        = PendingCommands.Add(taskCompletionSource);

            var result = NativeMethods.indy_open_blob_storage_writer(
                commandHandle,
                type,
                configJson,
                OpenWriterCallback
                );

            CallbackHelper.CheckResult(result);

            return(taskCompletionSource.Task);
        }
示例#3
0
        /// <summary>
        /// Gets the user defined metadata stored against a key-pair in the specified wallet.
        /// </summary>
        /// <remarks>
        /// If no metadata is stored against the specified key-pair null will be returned.</remarks>
        /// <param name="wallet">The wallet containing the key-pair.</param>
        /// <param name="verKey">The verification key of the key-pair.</param>
        /// <returns>An asynchronous <see cref="Task{T}"/> that resolves to a string containing the metadata associated with the key-pair.</returns>
        /// <exception cref="WalletValueNotFoundException">Thrown if the wallet does not contain a key-pair matching the provided <paramref name="verKey"/> or they key-pair has no metadata.</exception>
        public static Task <string> GetKeyMetadataAsync(Wallet wallet, string verKey)
        {
            ParamGuard.NotNull(wallet, "wallet");
            ParamGuard.NotNullOrWhiteSpace(verKey, "verKey");

            var taskCompletionSource = new TaskCompletionSource <string>();
            var commandHandle        = PendingCommands.Add(taskCompletionSource);

            var commandResult = NativeMethods.indy_get_key_metadata(
                commandHandle,
                wallet.Handle,
                verKey,
                GetKeyMetadataCompletedCallback
                );

            CallbackHelper.CheckResult(commandResult);

            return(taskCompletionSource.Task);
        }
示例#4
0
        /// <summary>
        /// Opens a Wallet.
        /// </summary>
        /// <remarks>
        /// <para>Opens a wallet by name using the name of a wallet created earlier using the
        /// <see cref="CreateWalletAsync(string, string, string, string, string)"/> method.
        /// </para>
        /// <note type="note">Attempting to open the same wallet more than once will result in an error.</note>
        /// <para>
        /// The <paramref name="runtimeConfig"/> parameter allows the default configuration of the wallet
        /// to be overridden while opening the wallet; this does not replace the configuration registered
        /// when the wallet was created but instead overrides it for the duration of this opening only.
        /// See the <see cref="CreateWalletAsync(string, string, string, string, string)"/> method for
        /// details on the configuration string supported by the default wallet type; custom wallet
        /// types will can support their own format.
        /// </para>
        /// <para>The <paramref name="credentials"/> parameter is unused in the default wallet at present,
        /// however the value can be used by custom wallet implementations; it is up to the custom wallet
        /// type implementer to interpret the value.
        /// </para>
        /// </remarks>
        /// <param name="name">The name of the Wallet to open.</param>
        /// <param name="runtimeConfig">The runtime configuration to override the configuration the wallet was created with.</param>
        /// <param name="credentials">The wallet credentials.</param>
        /// <returns>An asynchronous <see cref="Task{T}"/> that resolves to a <see cref="Wallet"/> instance when the operation completes.</returns>
        public static Task <Wallet> OpenWalletAsync(string name, string runtimeConfig, string credentials)
        {
            ParamGuard.NotNullOrWhiteSpace(name, "name");

            var taskCompletionSource = new TaskCompletionSource <Wallet>();
            var commandHandle        = PendingCommands.Add(taskCompletionSource);

            var result = IndyNativeMethods.indy_open_wallet(
                commandHandle,
                name,
                runtimeConfig,
                credentials,
                _openWalletCallback
                );

            CallbackHelper.CheckResult(result);

            return(taskCompletionSource.Task);
        }
        /// <summary>
        /// Deletes a wallet.
        /// </summary>
        /// <remarks>
        /// <para>Deletes a wallet created earlier using the <see cref="CreateWalletAsync(string, string)"/>
        /// by name.
        /// </para>
        /// <para>The <paramref name="credentials"/> parameter is unused in the default wallet at present,
        /// however the value can be used by custom wallet implementations; it is up to the custom wallet
        /// type implementer to interpret the value.
        /// </para>
        /// </remarks>
        /// <param name="config">The name of the wallet to delete.</param>
        /// <param name="credentials">The wallet credentials.</param>
        /// <returns>An asynchronous <see cref="Task"/> with no return value that completes when the operation completes.</returns>
        public static Task DeleteWalletAsync(string config, string credentials)
        {
            ParamGuard.NotNullOrWhiteSpace(config, "config");
            ParamGuard.NotNullOrWhiteSpace(credentials, "credentials");

            var taskCompletionSource = new TaskCompletionSource <bool>();
            var commandHandle        = PendingCommands.Add(taskCompletionSource);

            var result = NativeMethods.indy_delete_wallet(
                commandHandle,
                config,
                credentials,
                CallbackHelper.TaskCompletingNoValueCallback
                );

            CallbackHelper.CheckResult(result);

            return(taskCompletionSource.Task);
        }
示例#6
0
        /// <summary>
        /// Get info about My DID in format: DID, verkey, metadata
        /// </summary>
        /// <returns>The my did with meta async.</returns>
        /// <param name="wallet">IWallet.</param>
        /// <param name="myDid">My did.</param>
        public static Task <string> GetMyDidWithMetaAsync(IWallet wallet, string myDid)
        {
            ParamGuard.NotNull(wallet, "wallet");
            ParamGuard.NotNullOrWhiteSpace(myDid, "myDid");

            var taskCompletionSource = new TaskCompletionSource <string>();
            var commandHandle        = PendingCommands.Add(taskCompletionSource);

            var commandResult = NativeMethods.indy_get_my_did_with_meta(
                commandHandle,
                wallet.Handle,
                myDid,
                GetMyDidWithMetaCompletedCallback
                );

            CallbackHelper.CheckResult(commandResult);

            return(taskCompletionSource.Task);
        }
示例#7
0
        /// <summary>
        /// Builds a GET_REVOC_REG request. Request to get the accumulated state of the Revocation Registry
        /// by ID. The state is defined by the given timestamp.
        /// </summary>
        /// <returns>Request result as json..</returns>
        /// <param name="submitterDid">DID of the read request sender.</param>
        /// <param name="revocRegDefId">ID of the corresponding Revocation Registry Definition in ledger.</param>
        /// <param name="timestamp">Requested time represented as a total number of seconds from Unix Epoch</param>
        public static Task <string> BuildGetRevocRegRequestAsync(string submitterDid, string revocRegDefId, long timestamp)
        {
            ParamGuard.NotNullOrWhiteSpace(submitterDid, "submitterDid");
            ParamGuard.NotNullOrWhiteSpace(revocRegDefId, "revocRegDefId");

            var taskCompletionSource = new TaskCompletionSource <string>();
            var commandHandle        = PendingCommands.Add(taskCompletionSource);

            var result = NativeMethods.indy_build_get_revoc_reg_request(
                commandHandle,
                submitterDid,
                revocRegDefId,
                timestamp,
                BuildRequestCallback);

            CallbackHelper.CheckResult(result);

            return(taskCompletionSource.Task);
        }
示例#8
0
        /// <summary>
        /// Builds a SCHEMA ledger request to store a schema.
        /// </summary>
        /// <remarks>
        /// <para>
        /// Builds a request message that is suitable for storing a schema on a
        /// ledger.  Schema specify the data types and formats which are used to make up claims.
        /// </para>
        /// <para>
        /// The <paramref name="data"/> parameter must contain a JSON string with the members "name",
        /// "version" and "attr_names" that define the schema.  For example the following JSON describes
        /// a schema with the name "access" that is version 1.0 of the schema and specifies the attributes
        /// "ip", "port", and "keys":
        /// <code>
        /// {
        ///     "name":"access",
        ///     "version":"1.0",
        ///     "attr_names":["ip","port","keys"]
        /// }
        /// </code>
        /// </para>
        /// </remarks>
        /// <param name="submitterDid">The DID of the submitter.</param>
        /// <param name="data">The JSON schema.</param>
        /// <returns>An asynchronous <see cref="Task{T}"/> that resolves to a <see cref="string"/>
        /// containing the request JSON. </returns>
        public static Task <string> BuildSchemaRequestAsync(string submitterDid, string data)
        {
            ParamGuard.NotNullOrWhiteSpace(submitterDid, "submitterDid");
            ParamGuard.NotNullOrWhiteSpace(data, "data");

            var taskCompletionSource = new TaskCompletionSource <string>();
            var commandHandle        = PendingCommands.Add(taskCompletionSource);

            var result = NativeMethods.indy_build_schema_request(
                commandHandle,
                submitterDid,
                data,
                BuildRequestCallback
                );

            CallbackHelper.CheckResult(result);

            return(taskCompletionSource.Task);
        }
示例#9
0
        /// <summary>
        /// Builds Indy request for information to verify the payment receipt
        /// </summary>
        /// <returns>Indy request for verification receipt.</returns>
        /// <param name="wallet">Wallet.</param>
        /// <param name="submitterDid">DID of request sender</param>
        /// <param name="receipt">Payment receipt to verify.</param>
        public static Task <PaymentResult> BuildVerifyPaymentRequestAsync(Wallet wallet, string submitterDid, string receipt)
        {
            ParamGuard.NotNull(wallet, "wallet");
            ParamGuard.NotNullOrWhiteSpace(receipt, "receipt");

            var taskCompletionSource = new TaskCompletionSource <PaymentResult>();
            var commandHandle        = PendingCommands.Add(taskCompletionSource);

            var result = NativeMethods.indy_build_verify_payment_req(
                commandHandle,
                wallet.Handle,
                submitterDid,
                receipt,
                BuildVerifyPaymentRequestCallback);

            CallbackHelper.CheckResult(result);

            return(taskCompletionSource.Task);
        }
示例#10
0
        /// <summary>
        /// Builds Indy get request for getting fees for transactions in the ledger
        ///
        /// Note this endpoint is EXPERIMENTAL. Function signature and behaviour may change
        /// in the future releases.
        /// </summary>
        /// <returns>Indy request for getting fees for transactions in the ledger.</returns>
        /// <param name="wallet">Wallet.</param>
        /// <param name="submitterDid">DID of request sender</param>
        /// <param name="paymentMethod">Payment method.</param>
        public static Task <string> BuildGetTxnFeesRequestAsync(Wallet wallet, string submitterDid, string paymentMethod)
        {
            ParamGuard.NotNull(wallet, "wallet");
            ParamGuard.NotNullOrWhiteSpace(paymentMethod, "paymentMethod");

            var taskCompletionSource = new TaskCompletionSource <string>();
            var commandHandle        = PendingCommands.Add(taskCompletionSource);

            var result = NativeMethods.indy_build_get_txn_fees_req(
                commandHandle,
                wallet.Handle,
                submitterDid,
                paymentMethod,
                BuildGetTxnFeesReqCallback);

            CallbackHelper.CheckResult(result);

            return(taskCompletionSource.Task);
        }
示例#11
0
        /// <summary>
        /// Create the payment address for this payment method.
        ///
        /// This method generates private part of payment address
        /// and stores it in a secure place. Ideally it should be
        /// secret in libindy wallet (see crypto module).
        ///
        /// Note that payment method should be able to resolve this
        /// secret by fully resolvable payment address format.
        /// </summary>
        /// <returns>Public identifier of payment address in fully resolvable payment address format</returns>
        /// <param name="wallet">Wallet.</param>
        /// <param name="paymentMethod">Payment method to use (for example, 'sov')</param>
        /// <param name="config">
        /// <code>payment address config as json:
        ///   {
        ///     seed: &lt;str&gt;, // allows deterministic creation of payment address
        ///   }
        /// </code>
        /// </param>
        public static Task <string> CreatePaymentAddressAsync(Wallet wallet, string paymentMethod, string config)
        {
            ParamGuard.NotNull(wallet, "wallet");
            ParamGuard.NotNullOrWhiteSpace(paymentMethod, "paymentMethod");

            var taskCompletionSource = new TaskCompletionSource <string>();
            var commandHandle        = PendingCommands.Add(taskCompletionSource);

            var result = NativeMethods.indy_create_payment_address(
                commandHandle,
                wallet.Handle,
                paymentMethod,
                config,
                CreatePaymentAddressCallback);

            CallbackHelper.CheckResult(result);

            return(taskCompletionSource.Task);
        }
示例#12
0
        /// <summary>
        /// Builds Indy request for getting UTXO list for payment address
        /// according to this payment method.
        ///
        /// Note this endpoint is EXPERIMENTAL. Function signature and behaviour may change
        /// in the future releases.
        /// </summary>
        /// <returns>get_utxo_txn_json - Indy request for getting UTXO list for payment address
        /// payment_method</returns>
        /// <param name="wallet">Wallet.</param>
        /// <param name="submittedDid">DID of request sender</param>
        /// <param name="paymentAddress">target payment address</param>
        public static Task <PaymentResult> BuildGetPaymentSourcesAsync(Wallet wallet, string submittedDid, string paymentAddress)
        {
            ParamGuard.NotNullOrWhiteSpace(submittedDid, "submittedDid");
            ParamGuard.NotNullOrWhiteSpace(paymentAddress, "paymentAddress");

            var taskCompletionSource = new TaskCompletionSource <PaymentResult>();
            var commandHandle        = PendingCommands.Add(taskCompletionSource);

            var result = NativeMethods.indy_build_get_payment_sources_request(
                commandHandle,
                wallet.Handle,
                submittedDid,
                paymentAddress,
                BuildGetUtxoRequestCallback);

            CallbackHelper.CheckResult(result);

            return(taskCompletionSource.Task);
        }
示例#13
0
        /// <summary>
        /// Verifies whether or not a proof is valid.
        /// </summary>
        /// <remarks>
        /// <para>
        /// This method verifies a proof that can be made up of multiple claims.
        /// All required schema, public keys and revocation registries must be provided.
        /// </para>
        /// <para>
        /// The <paramref name="proofRequestJson"/> parameter expects the initial proof request sent
        /// by the verifier.
        /// <code>
        /// {
        ///     "nonce": string,
        ///     "requested_attr1_uuid": &lt;attr_info&gt;,
        ///     "requested_attr2_uuid": &lt;attr_info&gt;,
        ///     "requested_attr3_uuid": &lt;attr_info&gt;,
        ///     "requested_predicate_1_uuid": &lt;predicate_info&gt;,
        ///     "requested_predicate_2_uuid": &lt;predicate_info&gt;,
        /// }
        /// </code>
        /// </para>
        /// <para>
        /// The <paramref name="proofJson"/> parameter expects a JSON string containing,
        /// for each requested attribute,  either a proof (with optionally revealed attribute value) or
        /// self-attested attribute value.  Each proof is associated with a claim and corresponding
        /// schema_seq_no, issuer_did and revoc_reg_seq_no. There is also aggregated proof part
        /// common for all claim proofs.
        /// <code>
        /// {
        ///     "requested": {
        ///         "requested_attr1_id": [claim_proof1_uuid, revealed_attr1, revealed_attr1_as_int],
        ///         "requested_attr2_id": [self_attested_attribute],
        ///         "requested_attr3_id": [claim_proof2_uuid]
        ///         "requested_attr4_id": [claim_proof2_uuid, revealed_attr4, revealed_attr4_as_int],
        ///         "requested_predicate_1_uuid": [claim_proof2_uuid],
        ///         "requested_predicate_2_uuid": [claim_proof3_uuid],
        ///     },
        ///     "claim_proofs": {
        ///         "claim_proof1_uuid": [&lt;claim_proof&gt;, issuer_did, schema_seq_no, revoc_reg_seq_no],
        ///         "claim_proof2_uuid": [&lt;claim_proof&gt;, issuer_did, schema_seq_no, revoc_reg_seq_no],
        ///         "claim_proof3_uuid": [&lt;claim_proof&gt;, issuer_did, schema_seq_no, revoc_reg_seq_no]
        ///     },
        ///     "aggregated_proof": &lt;aggregated_proof&gt;
        /// }
        /// </code>
        /// </para>
        /// <para>
        /// The <paramref name="schemasJson"/> parameter expects a JSON string containing all schema
        /// participating in the proof.
        /// <code>
        /// {
        ///     "claim_proof1_uuid": &lt;schema&gt;,
        ///     "claim_proof2_uuid": &lt;schema&gt;,
        ///     "claim_proof3_uuid": &lt;schema&gt;
        /// }
        /// </code>
        /// </para>
        /// <para>
        /// The <paramref name="claimDefsJson"/> parameter expects a JSON string containing all claim
        /// definitions participating in the proof.
        /// <code>
        /// {
        ///     "claim_proof1_uuid": &lt;claim_def&gt;,
        ///     "claim_proof2_uuid": &lt;claim_def&gt;,
        ///     "claim_proof3_uuid": &lt;claim_def&gt;
        /// }
        /// </code>
        /// </para>
        /// <para>
        /// The <paramref name="revocRegsJson"/> parameter expects a JSON string containing all revocation
        /// registries participating in the proof.
        /// <code>
        /// {
        ///     "claim_proof1_uuid": &lt;revoc_reg&gt;,
        ///     "claim_proof2_uuid": &lt;revoc_reg&gt;,
        ///     "claim_proof3_uuid": &lt;revoc_reg&gt;
        /// }
        /// </code>
        /// </para>
        /// </remarks>
        /// <param name="proofRequestJson">The proof request JSON.</param>
        /// <param name="proofJson">The proof JSON.</param>
        /// <param name="schemasJson">The schemas JSON.</param>
        /// <param name="claimDefsJson">The claim definitions JSON.</param>
        /// <param name="revocRegsJson">The revocation registries JSON.</param>
        /// <returns>An asynchronous <see cref="Task{T}"/> that, when the operation completes, resolves
        /// to true if the proof is valid, otherwise false.</returns>
        public static Task <bool> VerifierVerifyProofAsync(string proofRequestJson, string proofJson, string schemasJson, string claimDefsJson, string revocRegsJson)
        {
            var taskCompletionSource = new TaskCompletionSource <bool>();
            var commandHandle        = PendingCommands.Add(taskCompletionSource);

            var commandResult = IndyNativeMethods.indy_verifier_verify_proof(
                commandHandle,
                proofRequestJson,
                proofJson,
                schemasJson,
                claimDefsJson,
                revocRegsJson,
                _verifierVerifyProofCallback
                );

            CallbackHelper.CheckResult(commandResult);

            return(taskCompletionSource.Task);
        }
示例#14
0
        /// <summary>
        /// Creates a claim request for the specified claim offer and stores it in the provided wallet.
        /// </summary>
        /// <remarks>
        /// <para>
        /// The JSON of a claim definition that is associated with the issuer_did and schema_seq_no in the
        /// claim_offer must be provided in the <paramref name="claimDefJson"/> parameter.  Claim
        /// definitions can be retrieved from the ledger using the
        /// <see cref="Ledger.BuildGetClaimDefTxnAsync(string, int, string, string)"/>method.
        /// </para>
        /// <para>
        /// The JSON in the <paramref name="claimOfferJson"/> parameter contains information about the
        /// issuer of the claim offer:
        /// <code>
        /// {
        ///     "issuer_did": string,
        ///     "schema_seq_no": string
        /// }
        /// </code>
        /// This method gets the public key and schema the <c>issuer_did</c> from the ledger for and
        /// stores them in the provided wallet. Once this is complete a blinded master secret is for the
        /// master secret specified by the <paramref name="masterSecretName"/> parameter.
        /// <note type="note">
        /// The master secret identified by the name must be already stored in the secure wallet using the
        /// <see cref="ProverCreateMasterSecretAsync(Wallet, string)"/> method.
        /// </note>
        /// The blinded master secret becomes a part of the claim request.
        /// </para>
        /// </remarks>
        /// <param name="wallet">The target wallet.</param>
        /// <param name="proverDid">The DID of the prover.</param>
        /// <param name="claimOfferJson">The claim offer JSON to generate a claim request for.</param>
        /// <param name="claimDefJson">The claim definition JSON.</param>
        /// <param name="masterSecretName">The name of the master secret in the wallet to use for generating the blinded secret.</param>
        /// <returns>An asynchronous <see cref="Task{T}"/> that, when the operation completes, resolves
        /// to a JSON string containing the claim request.</returns>
        public static Task <string> ProverCreateAndStoreClaimReqAsync(Wallet wallet, string proverDid, string claimOfferJson, string claimDefJson, string masterSecretName)
        {
            var taskCompletionSource = new TaskCompletionSource <string>();
            var commandHandle        = PendingCommands.Add(taskCompletionSource);

            var commandResult = IndyNativeMethods.indy_prover_create_and_store_claim_req(
                commandHandle,
                wallet.Handle,
                proverDid,
                claimOfferJson,
                claimDefJson,
                masterSecretName,
                _proverCreateAndStoreClaimReqCallback
                );

            CallbackHelper.CheckResult(commandResult);

            return(taskCompletionSource.Task);
        }
示例#15
0
        /// <summary>
        /// Builds a ledger request to store a NYM.
        /// </summary>
        /// <remarks>
        /// <para>
        /// Builds a request message that is suitable for storing a NYM for the <paramref name="targetDid"/>
        /// on the ledger.
        /// </para>
        /// <para>
        /// Only the <paramref name="submitterDid"/> and <paramref name="targetDid"/> parameters
        /// are required, however the other parameters provide greater control over the process.  Normally
        /// the <paramref name="targetDid"/> and <paramref name="verKey"/> parameters would be from values
        /// generated by a prior call to <see cref="Signus.CreateAndStoreMyDidAsync(Wallet, string)"/>.
        /// </para>
        /// <para>
        /// The <paramref name="role"/> parameter dictates what permissions the NYM will have - valid values
        /// are 'STEWARD' and 'TRUSTEE' and 'TRUST_ANCHOR'.
        /// </para>
        /// </remarks>
        /// <param name="submitterDid">The DID of the party who will submit the request to the ledger.</param>
        /// <param name="targetDid">The DID the NYM belongs to.</param>
        /// <param name="verKey">The verification key for the NYM.</param>
        /// <param name="alias">The alias for the NYM.</param>
        /// <param name="role">The role of the NYM.</param>
        /// <returns>An asynchronous <see cref="Task{T}"/> that resolves to a <see cref="string"/>
        /// containing the request JSON. </returns>
        public static Task <string> BuildNymRequestAsync(string submitterDid, string targetDid, string verKey, string alias, string role)
        {
            var taskCompletionSource = new TaskCompletionSource <string>();
            var commandHandle        = PendingCommands.Add(taskCompletionSource);

            var result = IndyNativeMethods.indy_build_nym_request(
                commandHandle,
                submitterDid,
                targetDid,
                verKey,
                alias,
                role,
                _buildRequestCallback
                );

            CallbackHelper.CheckResult(result);

            return(taskCompletionSource.Task);
        }
示例#16
0
        /// <summary>
        /// Creates keys for the given schema and signature type.
        /// </summary>
        /// <remarks>
        /// <para>This method creates both primary and revocation keys for the given
        /// signature type and schema and stores them in the provided <see cref="Wallet"/>.
        /// The generated claim definition is returned as a JSON string containing information about the
        /// signature type, schema, the issuer's public key and the unique identifier of the public key
        /// in the wallet.
        /// </para>
        /// <note type="note">Currently the only signature type that is supported is 'CL'.</note>
        /// </remarks>
        /// <param name="wallet">The wallet into which the claim definition will be stored.</param>
        /// <param name="issuerDid">The DID of the issuer of the claim definition.</param>
        /// <param name="schemaJson">The JSON schema of the claim definition.</param>
        /// <param name="signatureType">The type of signature to use.</param>
        /// <param name="createNonRevoc">Whether to request non-revocation claim.</param>
        /// <returns>
        /// An asynchronous <see cref="Task{T}"/> that, when the operation completes, resolves to a
        /// JSON string containing the claim definition.</returns>
        public static Task <string> IssuerCreateAndStoreClaimDefAsync(Wallet wallet, string issuerDid, string schemaJson, string signatureType, bool createNonRevoc)
        {
            var taskCompletionSource = new TaskCompletionSource <string>();
            var commandHandle        = PendingCommands.Add(taskCompletionSource);

            var commandResult = IndyNativeMethods.indy_issuer_create_and_store_claim_def(
                commandHandle,
                wallet.Handle,
                issuerDid,
                schemaJson,
                signatureType,
                createNonRevoc,
                _issuerCreateAndStoreClaimDefCallback
                );

            CallbackHelper.CheckResult(commandResult);

            return(taskCompletionSource.Task);
        }
示例#17
0
        /// <summary>
        /// Gets all claim offers in the provided wallet matching the specified filter.
        /// </summary>
        /// <remarks>
        /// <para>
        /// Claim offers stored with the <see cref="ProverStoreClaimOfferAsync(Wallet, string)"/> can be
        /// retrieved from the <paramref name="wallet"/> by searching on the DID of the issuer and/or the schema
        /// sequence number.  To filter the claim offers a <paramref name="filterJson"/> parameter must be provided with
        /// a JSON string which can include the following members:
        /// <code>
        /// {
        ///     "issuer_did": string,
        ///     "schema_seq_no": string
        /// }
        /// </code>
        /// </para>
        /// <para>
        /// The return value from this method is a JSON string that contains the list of matching claim
        /// offers in the following format:
        /// <code>
        /// {
        ///     [
        ///         {
        ///             "issuer_did": string,
        ///             "schema_seq_no": string
        ///         },
        ///         ...
        ///     ]
        /// }
        /// </code>
        /// </para>
        /// </remarks>
        /// <param name="wallet">The wallet containing the claims to get.</param>
        /// <param name="filterJson">The filter JSON.</param>
        /// <returns>An asynchronous <see cref="Task{T}"/> that, when the operation completes, resolves
        /// to a JSON string with a list of claim offers matching the filter.</returns>
        public static Task <string> ProverGetClaimOffersAsync(Wallet wallet, string filterJson)
        {
            ParamGuard.NotNull(wallet, "wallet");
            ParamGuard.NotNullOrWhiteSpace(filterJson, "filterJson");

            var taskCompletionSource = new TaskCompletionSource <string>();
            var commandHandle        = PendingCommands.Add(taskCompletionSource);

            var commandResult = NativeMethods.indy_prover_get_claim_offers(
                commandHandle,
                wallet.Handle,
                filterJson,
                _proverGetClaimOffersCallback
                );

            CallbackHelper.CheckResult(commandResult);

            return(taskCompletionSource.Task);
        }
示例#18
0
        /// <summary>
        /// Builds a GET_CRED_DEF request.Request to get a credential definition (in particular, public key),
        /// that Issuer creates for a particular Credential Schema.
        /// </summary>
        /// <returns>The get cred def request async.</returns>
        /// <param name="submitterDid">Submitter did.</param>
        /// <param name="id">Identifier.</param>
        public static Task <string> BuildGetCredDefRequestAsync(string submitterDid, string id)
        {
            ParamGuard.NotNullOrWhiteSpace(submitterDid, "submitterDid");
            ParamGuard.NotNullOrWhiteSpace(id, "id");

            var taskCompletionSource = new TaskCompletionSource <string>();
            var commandHandle        = PendingCommands.Add(taskCompletionSource);

            var result = NativeMethods.indy_build_get_cred_def_request(
                commandHandle,
                submitterDid,
                id,
                BuildRequestCallback
                );

            CallbackHelper.CheckResult(result);

            return(taskCompletionSource.Task);
        }
示例#19
0
        /// <summary>
        /// Creates a master secret with the specified name and stores it in the provided wallet.
        /// </summary>
        /// <remarks>
        /// The name of the master secret must be unique within the wallet.
        /// </remarks>
        /// <param name="wallet">The target wallet.</param>
        /// <param name="masterSecretName">The name of the master secret.</param>
        /// <returns>An asynchronous <see cref="Task"/> that completes when the operation has completed.</returns>
        public static Task ProverCreateMasterSecretAsync(Wallet wallet, string masterSecretName)
        {
            ParamGuard.NotNull(wallet, "wallet");
            ParamGuard.NotNullOrWhiteSpace(masterSecretName, "masterSecretName");

            var taskCompletionSource = new TaskCompletionSource <bool>();
            var commandHandle        = PendingCommands.Add(taskCompletionSource);

            var commandResult = NativeMethods.indy_prover_create_master_secret(
                commandHandle,
                wallet.Handle,
                masterSecretName,
                CallbackHelper.TaskCompletingNoValueCallback
                );

            CallbackHelper.CheckResult(commandResult);

            return(taskCompletionSource.Task);
        }
示例#20
0
        /// <summary>
        /// Gets the verification key for the specified DID.
        /// </summary>
        /// <remarks>
        /// This method will obtain the verification key associated with the specified <paramref name="did"/>from the provided <paramref name="wallet"/> but will
        /// not attempt to retrieve the key from the ledger if not present in the wallet, nor will it perform any freshness check against the ledger to determine
        /// if the key is up-to-date.  To ensure that the key is fresh use the <see cref="KeyForDidAsync(IPool, IWallet, string)"/> method instead.
        /// <note type="note">
        /// The <see cref="CreateAndStoreMyDidAsync(IWallet, string)"/> and <see cref="Crypto.CreateKeyAsync(IWallet, string)"/> methods both create
        /// similar wallet records so the returned verification key in all generic crypto and messaging functions.
        /// </note>
        /// </remarks>
        /// <param name="wallet">The wallet to resolve the DID from.</param>
        /// <param name="did">The DID to get the verification key for.</param>
        /// <returns>An asynchronous <see cref="Task{T}"/> that resolves to a string containing the verification key associated with the DID.</returns>
        /// <exception cref="WalletItemNotFoundException">Thrown if the DID could not be resolved from the <paramref name="wallet"/>.</exception>
        public static Task <string> KeyForLocalDidAsync(IWallet wallet, string did)
        {
            ParamGuard.NotNull(wallet, "wallet");
            ParamGuard.NotNullOrWhiteSpace(did, "did");

            var taskCompletionSource = new TaskCompletionSource <string>();
            var commandHandle        = PendingCommands.Add(taskCompletionSource);

            var commandResult = NativeMethods.indy_key_for_local_did(
                commandHandle,
                wallet.Handle,
                did,
                KeyForLocalDidCompletedCallback
                );

            CallbackHelper.CheckResult(commandResult);

            return(taskCompletionSource.Task);
        }
示例#21
0
        /// <summary>
        /// Updates and stores the provided claim in the specified wallet.
        /// </summary>
        /// <remarks>
        /// <para>
        /// This method updates the claim provided in the <paramref name="claimsJson"/> parameter
        /// with a blinded master secret and stores it in the wallet specified in the
        /// <paramref name="wallet"/> parameter.
        /// </para>
        /// <para>
        /// The claim JSON is typically structured as follows:
        /// <code>
        /// {
        ///     "claim": {attr1:[value, value_as_int]}
        ///     "signature": &lt;signature&gt;,
        ///     "schema_seq_no": string,
        ///     "revoc_reg_seq_no", string
        ///     "issuer_did", string
        /// }
        /// </code>
        /// It contains the information about the <c>schema_seq_no</c>, <c>issuer_did</c>
        /// and <c>revoc_reg_seq_no</c> - see the <see cref="IssuerCreateClaimAsync(Wallet, string, string, int)"/>
        /// method for details.
        /// </para>
        /// Seq_no is a sequence number of the corresponding transaction in the ledger.
        /// </remarks>
        /// <param name="wallet">The target wallet.</param>
        /// <param name="claimsJson">The claims JSON.</param>
        /// <returns>An asynchronous <see cref="Task"/> that completes when the operation has completed.</returns>
        public static Task ProverStoreClaimAsync(Wallet wallet, string claimsJson)
        {
            ParamGuard.NotNull(wallet, "wallet");
            ParamGuard.NotNullOrWhiteSpace(claimsJson, "claimsJson");

            var taskCompletionSource = new TaskCompletionSource <bool>();
            var commandHandle        = PendingCommands.Add(taskCompletionSource);

            var commandResult = NativeMethods.indy_prover_store_claim(
                commandHandle,
                wallet.Handle,
                claimsJson,
                CallbackHelper.TaskCompletingNoValueCallback
                );

            CallbackHelper.CheckResult(commandResult);

            return(taskCompletionSource.Task);
        }
示例#22
0
        /// <summary>
        /// Retrieves abbreviated verkey if it is possible otherwise return full verkey.
        /// </summary>
        /// <returns>The verkey async.</returns>
        /// <param name="did">Did.</param>
        /// <param name="fullVerkey">Full verkey.</param>
        public static Task <string> AbbreviateVerkeyAsync(string did, string fullVerkey)
        {
            ParamGuard.NotNullOrWhiteSpace(did, "did");
            ParamGuard.NotNullOrWhiteSpace(fullVerkey, "fullVerkey");

            var taskCompletionSource = new TaskCompletionSource <string>();
            var commandHandle        = PendingCommands.Add(taskCompletionSource);

            var commandResult = NativeMethods.indy_abbreviate_verkey(
                commandHandle,
                did,
                fullVerkey,
                AbbreviateVerkeyCompletedCallback
                );

            CallbackHelper.CheckResult(commandResult);

            return(taskCompletionSource.Task);
        }
示例#23
0
        /// <summary>
        /// Gets claims matching the provided proof request from the specified wallet.
        /// </summary>
        /// <remarks>
        /// The proof request provided in the <paramref name="proofRequestJson"/> parameter must conform
        /// to the format:
        /// <code>
        /// {
        ///     "name": string,
        ///     "version": string,
        ///     "nonce": string,
        ///     "requested_attr1_referent": &lt;attr_info&gt;,
        ///     "requested_attr2_referent": &lt;attr_info&gt;,
        ///     "requested_attr3_referent": &lt;attr_info&gt;,
        ///     "requested_predicate_1_referent": &lt;predicate_info&gt;,
        ///     "requested_predicate_2_referent": &lt;predicate_info&gt;,
        /// }
        /// </code>
        /// The method will return a JSON string with claims matching the given proof request in the following format:
        /// <code>
        /// {
        ///     "requested_attr1_referent": [claim1, claim2],
        ///     "requested_attr2_referent": [],
        ///     "requested_attr3_referent": [claim3],
        ///     "requested_predicate_1_referent": [claim1, claim3],
        ///     "requested_predicate_2_referent": [claim2],
        /// }
        /// </code>
        /// Each claim in the result consists of a uuid (<c>referent</c>), human-readable attributes as
        /// a key-value map (<c>attrs</c>), a schema sequence number (<c>schema_seq_no</c>) an issuer DID
        /// (<c>issuer_did</c>) and a revocation registry sequence number (<c>revoc_reg_seq_no</c>):
        /// <code>
        /// {
        ///     "referent": string,
        ///     "attrs": [{"attr_name" : "attr_value"}],
        ///     "schema_seq_no": string,
        ///     "issuer_did": string,
        ///     "revoc_reg_seq_no": string,
        /// }
        /// </code>
        /// </remarks>
        /// <param name="wallet">The target wallet.</param>
        /// <param name="proofRequestJson">The proof request JSON.</param>
        /// <returns>An asynchronous <see cref="Task{T}"/> that, when the operation completes, resolves
        /// to a JSON string containing the claims for the proof request.</returns>
        public static Task <string> ProverGetClaimsForProofReqAsync(Wallet wallet, string proofRequestJson)
        {
            ParamGuard.NotNull(wallet, "wallet");
            ParamGuard.NotNullOrWhiteSpace(proofRequestJson, "proofRequestJson");

            var taskCompletionSource = new TaskCompletionSource <string>();
            var commandHandle        = PendingCommands.Add(taskCompletionSource);

            var commandResult = NativeMethods.indy_prover_get_claims_for_proof_req(
                commandHandle,
                wallet.Handle,
                proofRequestJson,
                _proverGetClaimsForProofCallback
                );

            CallbackHelper.CheckResult(commandResult);

            return(taskCompletionSource.Task);
        }
示例#24
0
        /// <summary>
        /// Prepares an anonymous message so that it can be securely sent to a recipient.
        /// </summary>
        /// <param name="recipientKey">The verification key of the intended recipient of the message.</param>
        /// <param name="message">The message content to prepare.</param>
        /// <returns>An asynchronous <see cref="Task{T}"/> that resolves to an array of bytes containing the prepared message.</returns>
        /// <exception cref="InvalidStructureException">Thrown if the value passed to the <paramref name="recipientKey"/> is malformed or the content of the <paramref name="message"/> parameter is invalid.</exception>
        public static Task <byte[]> PrepAnonymousMsgAsync(string recipientKey, byte[] message)
        {
            ParamGuard.NotNullOrWhiteSpace(recipientKey, "recipientKey");
            ParamGuard.NotNull(message, "message");

            var taskCompletionSource = new TaskCompletionSource <byte[]>();
            var commandHandle        = PendingCommands.Add(taskCompletionSource);

            var result = NativeMethods.indy_prep_anonymous_msg(
                commandHandle,
                recipientKey,
                message,
                message.Length,
                _agentMessagePreparedCallback);

            CallbackHelper.CheckResult(result);

            return(taskCompletionSource.Task);
        }
示例#25
0
        /// <summary>
        /// Sets the metadata on the existing pairwise record for the specified DID in the provided wallet.
        /// </summary>
        /// <remarks>
        /// If the pairwise record already contains any existing metadata it will be replaced with the value provided
        /// in the <paramref name="metadata"/> parameter.  To remove all metadata for a record provide <c>null</c> in the
        /// <paramref name="metadata"/> parameter.
        /// </remarks>
        /// <param name="wallet">The wallet containing the pairwise record.</param>
        /// <param name="theirDid">The DID belonging to another party the pairwise record exists for.</param>
        /// <param name="metadata">The metadata to set on the pairwise record.</param>
        /// <returns>An asynchronous <see cref="Task"/> completes once the operation completes.</returns>
        public static Task SetMetadataAsync(Wallet wallet, string theirDid, string metadata)
        {
            ParamGuard.NotNull(wallet, "wallet");
            ParamGuard.NotNullOrWhiteSpace(theirDid, "theirDid");

            var taskCompletionSource = new TaskCompletionSource <bool>();
            var commandHandle        = PendingCommands.Add(taskCompletionSource);

            int result = NativeMethods.indy_set_pairwise_metadata(
                commandHandle,
                wallet.Handle,
                theirDid,
                metadata,
                CallbackHelper.TaskCompletingNoValueCallback);

            CallbackHelper.CheckResult(result);

            return(taskCompletionSource.Task);
        }
示例#26
0
        /// <summary>
        /// Creates a key in the provided wallet.
        /// </summary>
        /// <remarks>
        /// The <paramref name="keyJson"/> parameter must contain a JSON object although all properties of the object are optional.  The schema
        /// the object must conform to are as follows:
        /// <code>
        /// {
        ///     "seed": string, // Optional (if not set random one will be used); Seed information that allows deterministic key creation.
        ///     "crypto_type": string, // Optional (if not set then ed25519 curve is used); Currently only 'ed25519' value is supported for this field.
        /// }
        /// </code>
        /// The <c>seed</c> member is optional and is used to specify the seed to use for key creation - if this parameter is not set then a random seed will be used.
        /// The <c>crypto_type</c> member is also optional and will default to ed25519 curve if not set.
        /// <note type="note">At present the crypto_type member only supports the value 'ed22519'.</note>
        /// </remarks>
        /// <param name="wallet">The wallet to create the key in.</param>
        /// <param name="keyJson">The JSON string describing the key.</param>
        /// <returns>An asynchronous <see cref="Task{T}"/> that resolves to a string containing the verification key of the generated key-pair.</returns>
        /// <exception cref="InvalidStructureException">Thrown if the value passed to the <paramref name="keyJson"/> parameter is malformed or contains invalid data.</exception>
        public static Task <string> CreateKeyAsync(Wallet wallet, string keyJson)
        {
            ParamGuard.NotNull(wallet, "wallet");
            ParamGuard.NotNullOrWhiteSpace(keyJson, "keyJson");

            var taskCompletionSource = new TaskCompletionSource <string>();
            var commandHandle        = PendingCommands.Add(taskCompletionSource);

            var commandResult = NativeMethods.indy_create_key(
                commandHandle,
                wallet.Handle,
                keyJson,
                CreateKeyCompletedCallback
                );

            CallbackHelper.CheckResult(commandResult);

            return(taskCompletionSource.Task);
        }
示例#27
0
        /// <summary>
        /// Unpacks a message packed using indy_pack_message which follows the wire message format (Experimental)
        /// </summary>
        /// <param name="wallet">The wallet.</param>
        /// <param name="message">The JWE message to be unpacked</param>
        /// <returns>
        /// if authcrypt was used to pack the message returns this json structure:
        /// <code>
        /// {
        ///     message: &lt;decrypted message>,
        ///     sender_verkey: &lt;sender_verkey>,
        ///     recipient_verkey: &lt;recipient_verkey>
        /// }
        /// </code>
        /// OR
        /// <code>
        /// if anoncrypt was used to pack the message returns this json structure:
        /// {
        ///     message: &lt;decrypted message>,
        ///     recipient_verkey: &lt;recipient_verkey>
        /// }
        /// </code>
        /// </returns>
        public static Task <byte[]> UnpackMessageAsync(Wallet wallet, byte[] message)
        {
            ParamGuard.NotNull(wallet, "wallet");
            ParamGuard.NotNull(message, "message");

            var taskCompletionSource = new TaskCompletionSource <byte[]>();
            var commandHandle        = PendingCommands.Add(taskCompletionSource);

            var commandResult = NativeMethods.indy_unpack_message(
                commandHandle,
                wallet.Handle,
                message,
                message.Length,
                UnpackMessageCompletedCallback);

            CallbackHelper.CheckResult(commandResult);

            return(taskCompletionSource.Task);
        }
示例#28
0
        /// <summary>
        /// Closes the pool.
        /// </summary>
        /// <remarks>
        /// <note type="note">Once a Pool instance is closed it cannot be opened again.  Instead call the
        /// <see cref="OpenPoolLedgerAsync(string, string)"/> method to open a new Pool instance.</note>
        /// </remarks>
        /// <returns>An asynchronous <see cref="Task"/> that completes when the operation completes.</returns>
        public Task CloseAsync()
        {
            _requiresClose = false;

            var taskCompletionSource = new TaskCompletionSource <bool>();
            var commandHandle        = PendingCommands.Add(taskCompletionSource);

            var result = NativeMethods.indy_close_pool_ledger(
                commandHandle,
                Handle,
                CallbackHelper.TaskCompletingNoValueCallback
                );

            CallbackHelper.CheckResult(result);

            GC.SuppressFinalize(this);

            return(taskCompletionSource.Task);
        }
示例#29
0
        /// <summary>
        /// Builds a ledger request for storing an ATTRIB.
        /// </summary>
        /// <remarks>
        /// <para>
        /// Builds a request message that is suitable for setting an attribute on the ledger.
        /// </para>
        /// <para>
        /// The <paramref name="submitterDid"/>, <paramref name="targetDid"/> are mandatory and
        /// any one of the <paramref name="hash"/>, <paramref name="raw"/> or <paramref name="enc"/>
        /// parameters must also be provided, depending on what type of data should be stored.
        /// </para>
        /// </remarks>
        /// <param name="submitterDid">The DID of the party that will submit the request to the ledger.</param>
        /// <param name="targetDid">The DID the ATTRIB will belong to.</param>
        /// <param name="hash">The hash of the ATTRIB data.</param>
        /// <param name="raw">The raw JSON attribute data.</param>
        /// <param name="enc">The encrypted attribute data.</param>
        /// <returns>An asynchronous <see cref="Task{T}"/> that resolves to a <see cref="string"/>
        /// containing the request JSON. </returns>
        public static Task <string> BuildAttribRequestAsync(string submitterDid, string targetDid, string hash, string raw, string enc)
        {
            var taskCompletionSource = new TaskCompletionSource <string>();
            var commandHandle        = PendingCommands.Add(taskCompletionSource);

            var result = IndyNativeMethods.indy_build_attrib_request(
                commandHandle,
                submitterDid,
                targetDid,
                hash,
                raw,
                enc,
                _buildRequestCallback
                );

            CallbackHelper.CheckResult(result);

            return(taskCompletionSource.Task);
        }
示例#30
0
        /// <summary>
        /// Encrypts the provided message with the public key of the specified DID.
        /// </summary>
        /// <remarks>
        /// <para>If the wallet specified in the <paramref name="wallet"/> parameter contains the public key
        /// associated with the DID specified in the <paramref name="did"/> parameter and the value has
        /// not expired then this key will be used for encryption.
        /// </para>
        /// <para>On the other hand, if the public key is not present in the wallet or has expired the public
        /// key will be read from the ledger in the node pool specified in the <paramref name="pool"/>
        /// parameter and the wallet will be updated with the new public key if required.
        /// </para>
        /// <para>For further information on registering a public key for a DID see the
        /// <see cref="StoreTheirDidAsync(Wallet, string)"/>method and for information on the expiry of
        /// values in a wallet see the <see cref="Wallet.CreateWalletAsync(string, string, string, string, string)"/>
        /// and <see cref="Wallet.OpenWalletAsync(string, string, string)"/> methods.
        /// </para>
        /// </remarks>
        /// <param name="wallet">The wallet containing the DID to use for encryption.</param>
        /// <param name="pool">The node pool to read the public key from if required.</param>
        /// <param name="myDid">The DID used to encrypt the message.</param>
        /// <param name="did">The DID the message is to be encrypted for.</param>
        /// <param name="msg">The message to encrypt.</param>
        /// <returns>An asynchronous <see cref="Task{T}"/> that resolves to an <see cref="EncryptResult"/> once encryption is complete.</returns>
        public static Task <EncryptResult> EncryptAsync(Wallet wallet, Pool pool, string myDid, string did, byte[] msg)
        {
            var taskCompletionSource = new TaskCompletionSource <EncryptResult>();
            var commandHandle        = PendingCommands.Add(taskCompletionSource);

            var commandResult = IndyNativeMethods.indy_encrypt(
                commandHandle,
                wallet.Handle,
                pool.Handle,
                myDid,
                did,
                msg,
                msg.Length,
                _encryptCallback);

            CallbackHelper.CheckResult(commandResult);

            return(taskCompletionSource.Task);
        }
示例#31
0
        /// <summary>
        /// Generates new signing and encryption keys in the specified wallet for an existing DID owned by the caller
        /// </summary>
        /// <remarks>
        /// The developer has some control over the generation of the new keys through the value passed to
        /// the <paramref name="identityJson"/> parameter.  This parameter expects a valid JSON string
        /// with the following optional members:
        /// <code>
        /// {
        ///     "seed": string, (optional) Seed that allows deterministic key creation (if not set random one will be created).
        ///                                Can be UTF-8, base64 or hex string.
        ///     "crypto_type": string, (optional) if not set then ed25519 curve is used;
        ///               currently only 'ed25519' value is supported for this field)
        /// }
        /// </code>
        /// <para>The <c>seed</c> member controls the seed that will be used to generate they keys.
        /// If not provided a random one will be created.</para>
        /// <para>The <c>crypto_type</c> member specifies the type of cryptographic algorithm will be
        /// used to generate they keys.  If not provided then ed22519 curve will be used.
        /// <note type="note">The only value currently supported for this member is 'ed25519'.</note>
        /// </para>
        /// </remarks>
        /// <param name="wallet">The wallet the DID is stored in.</param>
        /// <param name="did">The did to replace the keys for.</param>
        /// <param name="identityJson">The identity information as JSON.</param>
        /// <returns>An asynchronous <see cref="Task{T}"/> that resolves to a string containing the new verification key when the operation completes.</returns>
        public static Task <string> ReplaceKeysStartAsync(Wallet wallet, string did, string identityJson)
        {
            ParamGuard.NotNull(wallet, "wallet");
            ParamGuard.NotNullOrWhiteSpace(did, "did");
            ParamGuard.NotNullOrWhiteSpace(identityJson, "identityJson");

            var taskCompletionSource = new TaskCompletionSource <string>();
            var commandHandle        = PendingCommands.Add(taskCompletionSource);

            var commandResult = NativeMethods.indy_replace_keys_start(
                commandHandle,
                wallet.Handle,
                did,
                identityJson,
                ReplaceKeysCallback);

            CallbackHelper.CheckResult(commandResult);

            return(taskCompletionSource.Task);
        }
 public void Can_dispatch_using_coroutine_dispatcher() {
     var helper = new CallbackHelper();
     var queue = new UpdateDelayQueue(TimeSpan.FromSeconds(1), new UpdateRecordDispatcher(helper.Invoke));
     var queued = new XDoc("deki-event")
         .Attr("wikiid", "abc")
         .Elem("channel", "event://abc/deki/pages/update")
         .Elem("pageid", "1")
         .Elem("path", "bar");
     queue.Enqueue(queued);
     Assert.AreEqual(0, helper.Callbacks.Count);
     if(!helper.ResetEvent.WaitOne(2000, true)) {
         Assert.Fail("callback didn't happen");
     }
     Assert.AreEqual(1, helper.Callbacks.Count);
     Assert.AreEqual(1, helper.Callbacks[0].Id);
     Assert.AreEqual("abc", helper.Callbacks[0].WikiId);
     Assert.AreEqual("bar", helper.Callbacks[0].Path);
     Assert.AreEqual(RecordType.Page, helper.Callbacks[0].Type);
 }