Perform a QUICK transfer

Read more about QUICK in Cryptshare Web App or in the Cryptshare for Outlook (Classic) User guides.

In this article, you’ll learn how to perform a Cryptshare transfer that is secured by QUICK Technology using the Cryptshare .NET API. Alternatively, you may skip to the Summary section and view the complete source code.

Implementation

In this section, we’ll go through a step-by-step instruction in order to build a program that is capable of performing a QUICK transfer.

Preparing the program

We prepare a simple console application and define important bits of information that we’ll need along the way. In order to use the Cryptshare.* namespace, please make sure that you have successfully added the Cryptshare.API.dll to the project references.

using Cryptshare.API;
using System;
using System.Collections.Generic;
using System.Linq;

namespace QuickTransfer
{
   class Program
   {
       private static readonly string SenderEmailAddress = "john.doe@example.com";
       private static readonly string SenderName = "John Doe";
       private static readonly string SenderPhoneNumber = "+49 (0) 1234 56789";
       private static readonly string ServerUrl = "`https://cryptshare.example.com[`https://cryptshare.example.com`]`";
       // New "client.store" file will be created if it doesn't already exist.
       private static readonly string ClientStoreLocation = @"C:\temp";
       private static readonly string RecipientEmailAddress = "jane.doe@example.com";
       private static readonly string FilePath = @"C:\temp\pdf-sample.pdf";

       static void Main(string[] args)
       {
           try
           {
               // All following code snippets are to be inserted here.
           }
           catch (Exception e)
           {
               Console.Error.WriteLine("An error has occurred: " + e);
           }
           finally
           {
               Console.WriteLine("Press any key to terminate the program.");
               Console.ReadKey();
           }
       }
   }
}

Creating the client instance

Similar to performing regular transfers, it’s important to create a client instance representing the sender. The following information is needed:

  • Email address of the sender

  • URL of the Cryptshare Server

  • Path to access the verification store

Client client = new Client(
   SenderEmailAddress,
   new CryptshareConnection(new WebServiceUri(ServerUrl)),
   ClientStoreLocation
);

Creating and preparing the transfer instance

Populating the transfer instance with information is just as important as creating a client instance and an integral part of every Cryptshare transfer.

Transfer transfer = new Transfer();

A successful transfer requires the following minimum amount of information:

  • The sender’s full name

transfer.SenderName = SenderName;
  • The sender’s phone number

transfer.SenderPhone = SenderPhoneNumber;
  • At least one recipient (the second parameter defines whether QUICK should be enabled for this recipient)

// Activate QUICK for the given recipient.
transfer.Recipients.Add(new Recipient(RecipientEmailAddress, true));
  • The password mode to be used

transfer.PasswordMode = PasswordMode.Manual;
  • Optional: A file to be sent

    • Specify a file.

transfer.Files = new List<string>() { FilePath };
  • Optional: Specifying whether the Cryptshare server should handle the email notification part for both the sender and recipient.

transfer.SendEmails = true;
transfer.NotifySender = true;
transfer.NotifyRecipients = true;
transfer.InformAboutDownload = true;
  • Expiration date of the transfer. Hint: Because we’re relying on a policy query in order to set the expiration date, we’re required to have a valid verification. Thus, the maximum storage duration should only be queried if a valid verification is ensured beforehand. Please note the order of calls in the Summary section.

// Query the maximum possible storage duration for the given sender-recipient policy.
Policy policy = client.RequestPolicy(transfer.Recipients.ConvertAll(recipient => recipient.EmailAddress));
transfer.ExpirationDate = DateTime.Now.AddDays(policy.StorageDuration);

Further requirements for a successful transfer

Our client and transfer instances now fulfill all necessary requirements for a transfer. However, additional requirements imposed by the Cryptshare Server need to be considered and handled. More specifically, it is required that:

  • the sender email address is verified.

    • If no, the program should ensure a valid sender verification as seen in the example below.

CheckVerificationResult checkVerificationResult = client.CheckVerification();
if (!checkVerificationResult.UserVerified)
{
 switch (checkVerificationResult.VerificationMode)
 {
 case VerificationMode.Sender:
 Console.WriteLine($"Requesting a verification code for {client.UserEmailAddress}...");
 client.RequestSenderVerification();
 Console.WriteLine($"Please enter the code below and confirm with [Enter]:");
 string code = Console.ReadLine().Trim();
 client.ConfirmSenderVerification(code);
 break;
 case VerificationMode.Client:
 if (checkVerificationResult.ClientVerificationAllowed)
 {
 client.RequestClientVerification();
 }
 else
 {
 throw new UnauthorizedAccessException(
 $"Your client ID is not whitelisted. Please whitelist the following client ID before proceeding: {client.ClientId}"
 );
 }
 break;
 default:
 break;
 }
  • no QUICK activation is required - for example, a QUICK activation may be required if the given sender email address already has QUICK access credentials on the server, which may be the case if QUICK has been used previously on another device.

    • If yes, the sender’s own QUICK access will be reset.

    • Hint: Make sure you’re aware of the consequences of resetting the QUICK connection. In general, QUICK access can be activated programmatically as is described in the article Activate QUICK access.

if (checkVerificationResult.ActivationRequired)
{
 // WARNING: Only reset the QUICK state if you are aware of the consequences. When in doubt, please

` // consult the Wiki article about QUICK Technology: `http://cryptshare.click/webapp-quick-activation-en

 client.ResetQuickState();
}
  • the existing verification is enabled for the usage of QUICK.

if (!checkVerificationResult.QuickEnabled)
{
 client.EnableVerificationForQuick();
}
  • a password is set if no QUICK connection has been established to at least one recipient.

    • For the recipient to whom there is no established QUICK connection, this transfer also acts as an invitation to establish a QUICK connection with the sender.

{
   // ...
 HashSet<string> recipients = new HashSet<string>(transfer.Recipients.Select(r => r.EmailAddress));
 IDictionary<string, QuickConnectionState> quickConnectionStates = client.RequestQuickConnectionStates(recipients);
 if (!IsPureQuickTransfer(quickConnectionStates))
 {
 // Not a pure QUICK transfer, password needs to be set.
 Console.Write("Not a pure QUICK transfer; generating a one-time-password... ");
 PasswordPolicy passwordPolicy = client.RequestPasswordPolicy();
 transfer.Password = client.RequestGeneratedPassword(passwordPolicy.MinimumLength);
 Console.WriteLine(transfer.Password);
 }
   // ...
}

private static bool IsPureQuickTransfer(IDictionary<string, QuickConnectionState> quickConnectionStates)
{
   return quickConnectionStates
       .Select(entry => entry.Value)
       .All(recipient => recipient == QuickConnectionState.Established);
}

If these prerequisites are considered, the transfer can be performed successfully.

{
 // ...
 client.PerformTransfer(transfer, null, HandleUploadComplete, null, null);
 // ...
}

private static void HandleUploadComplete(IDictionary<string, string> urlMappings, IDictionary<string, string> smtpMappings, string serverGenPassword, TransferError transferError, string trackingID)
{
   Console.WriteLine("URL mappings:");
   foreach (var mapping in urlMappings)
   {
       Console.WriteLine($"{mapping.Key}: {mapping.Value}");
   }
   Console.WriteLine("SMTP mappings:");
   foreach (var mapping in smtpMappings)
   {
       Console.WriteLine($"{mapping.Key}: {mapping.Value}");
   }
   Console.WriteLine($"Tracking ID: {trackingID}");

Summary

If you have followed the article step-by-step, you should end up with a program that looks as follows:

Expand to view the source code…​ Expand source
using Cryptshare.API;
using System;
using System.Collections.Generic;
using System.Linq;

namespace QuickTransfer
{
   class Program
   {
       private static readonly string SenderEmailAddress = "john.doe@example.com";
       private static readonly string SenderName = "John Doe";
       private static readonly string SenderPhoneNumber = "+49 (0) 1234 56789";
       private static readonly string ServerUrl = "`https://cryptshare.example.com[`https://cryptshare.example.com`]`";
 // New "client.store" file will be created if it doesn't already exist.
       private static readonly string ClientStoreLocation = @"C:\temp";
       private static readonly string RecipientEmailAddress = "jane.doe@example.com";
       private static readonly string FilePath = @"C:\temp\pdf-sample.pdf";

       static void Main(string[] args)
       {
           try
           {
               Client client = new Client(
                   SenderEmailAddress,
                   new CryptshareConnection(new WebServiceUri(ServerUrl)),
                   ClientStoreLocation
               );
               Transfer transfer = new Transfer();
               transfer.SenderName = SenderName;
               transfer.SenderPhone = SenderPhoneNumber;
               // Activate QUICK for the given recipient.
               transfer.Recipients.Add(new Recipient(RecipientEmailAddress, true));
               transfer.PasswordMode = PasswordMode.Manual;
               transfer.Files = new List<string>() { FilePath };
               // Optional: Let the Cryptshare Server handle the email sending process.
               transfer.SendEmails = true;
               transfer.NotifySender = true;
               transfer.NotifyRecipients = true;
               transfer.InformAboutDownload = true;

               CheckVerificationResult checkVerificationResult = client.CheckVerification();
               if (!checkVerificationResult.UserVerified)
               {
                   switch (checkVerificationResult.VerificationMode)
                   {
                       case VerificationMode.Sender:
                           Console.WriteLine($"Requesting a verification code for {client.UserEmailAddress}...");
                           client.RequestSenderVerification();
                           Console.WriteLine($"Please enter the code below and confirm with [Enter]:");
                           string code = Console.ReadLine().Trim();
                           client.ConfirmSenderVerification(code);
                           break;
                       case VerificationMode.Client:
                           if (checkVerificationResult.ClientVerificationAllowed)
                           {
                               client.RequestClientVerification();
                           }
                           else
                           {
                               throw new UnauthorizedAccessException(
                                   $"Your client ID is not whitelisted. Please whitelist the following client ID before proceeding: {client.ClientId}"
                               );
                           }
                           break;
                       default:
                           break;
                   }
               }

               // Query the maximum possible storage duration for the given sender-recipient policy.
               Policy policy = client.RequestPolicy(transfer.Recipients.ConvertAll(recipient => recipient.EmailAddress));
               transfer.ExpirationDate = DateTime.Now.AddDays(policy.StorageDuration);

               // If the user already has a personal key on this server, reset the QUICK state. We could activate the
               // QUICK access using the API, but choose to reset the QUICK state for the sake of brevity.
               if (checkVerificationResult.ActivationRequired)
               {
                   // WARNING: Only reset the QUICK state if you are aware of the consequences. When in doubt, please

` // consult the Wiki article about QUICK Technology: `http://cryptshare.click/webapp-quick-activation-en

                   client.ResetQuickState();
               }

               // A regular verification needs to be enabled for QUICK, if not already done.
               if (!checkVerificationResult.QuickEnabled)
               {
                   client.EnableVerificationForQuick();
               }

               // We must define a password if there is at least one recipient who has not yet accepted the QUICK invitation.
               HashSet<string> recipients = new HashSet<string>(transfer.Recipients.Select(r => r.EmailAddress));
               IDictionary<string, QuickConnectionState> quickConnectionStates = client.RequestQuickConnectionStates(recipients);
               if (!IsPureQuickTransfer(quickConnectionStates))
               {
                   // Not a pure QUICK transfer, password needs to be set.
                   Console.Write("Not a pure QUICK transfer; generating a one-time-password... ");
                   PasswordPolicy passwordPolicy = client.RequestPasswordPolicy();
                   transfer.Password = client.RequestGeneratedPassword(passwordPolicy.MinimumLength);
                   Console.WriteLine(transfer.Password);
               }

               client.PerformTransfer(transfer, null, HandleUploadComplete, null, null);
           }
           catch (Exception e)
           {
               Console.Error.WriteLine("An error has occurred: " + e);
           }
           finally
           {
               Console.WriteLine("Press any key to terminate the program.");
               Console.ReadKey();
           }
       }

       private static bool IsPureQuickTransfer(IDictionary<string, QuickConnectionState> quickConnectionStates)
       {
           return quickConnectionStates
               .Select(entry => entry.Value)
               .All(recipient => recipient == QuickConnectionState.Established);
       }

       private static void HandleUploadComplete(IDictionary<string, string> urlMappings, IDictionary<string, string> smtpMappings, string serverGenPassword, TransferError transferError, string trackingID)
       {
           Console.WriteLine("URL mappings:");
           foreach (var mapping in urlMappings)
           {
               Console.WriteLine($"{mapping.Key}: {mapping.Value}");
           }
           Console.WriteLine("SMTP mappings:");
           foreach (var mapping in smtpMappings)
           {
               Console.WriteLine($"{mapping.Key}: {mapping.Value}");
           }
           Console.WriteLine($"Tracking ID: {trackingID}");
       }
   }
}