a file. The application will need to point the user to a URL to
authorize the application, and from there we can easily access
the user’s documents. We will use the generic integration model,
which effectively makes SmartVault a basic file storage system
similar to a hard drive.
Here’s What You’ll Need
To perform autonomous authentication, we will first need to generate a RSA key pair. Visit Generating a Key Pair to view the steps on how to create them.
If you have not yet created a developer account or client ID, visit Creating a Developer Account to view the steps on how to create them.
Setting Up
You will also need to install the Java API wrapper library, begin communicating with SmartVault, and create a method to handle autonomous authentication. The following tutorial will guide you through this process:
Autonomous Authentication
Browsing the Folder Structure
A very common task in SmartVault is browsing the folder structure. For generic integrations, this is done using the /nodes/pth structure. The root of this structure contains the user’s accounts. Accounts contain vaults, and vaults contain folders. Folders are where files are typically stored.
Let’s create a method called browsePath to implement browsing this structure in a simplified way. This method will take in a path to browse and output the response. The variable children controls how deep in the structure we want to traverse on each call. Setting this to 1 will make the response contain the immediate contents of the path retrieved.
public NodeProto.NodeResponse browsePath(String path) throws Exception { int children = 1; // Immediate contents only return _delegation.navigate(path, children); }
Downloading Files
Before we can download our file again, we’re going to need the full path to the file in SmartVault. Let’s call a new method called getRemoteFile to retrieve this. We can figure this out using the original path to the file on the local system, and the remote folder path that we determined earlier.
public static void main(String[] args) {mvc try { SmartVault smartVault = new SmartVault(); authenticate(smartVault); String localFile = getLocalFile(); String remoteFolder = getRemoteFolder(smartVault); System.out.println(String.format("\nUploading '%s' to '%s'", localFile, remoteFolder)); smartVault.uploadFile(localFile, remoteFolder); System.out.println("\nUpload complete"); String remoteFile = getRemoteFile(remoteFolder, localFile); ... } catch (Exception e) { e.printStackTrace(); } }
Now let’s implement getRemoteFile. All we need to do here is append the filename to end of the remote folder path.
private static String getRemoteFile(String remoteFolder, String localFile) { return String.format("%s/%s", remoteFolder, Paths.get(localFile).getFileName().toString()); }
We also need to know where to save the file. Let’s call a new method called getLocalFolder to obtain that information from the user.
public static void main(String[] args) { try { SmartVault smartVault = new SmartVault(); authenticate(smartVault); String localFile = getLocalFile(); String remoteFolder = getRemoteFolder(smartVault); System.out.println(String.format("\nUploading '%s' to '%s'", localFile, remoteFolder)); smartVault.uploadFile(localFile, remoteFolder); System.out.println("\nUpload complete"); String remoteFile = getRemoteFile(remoteFolder, localFile); String localFolder = getLocalFolder(); ... } catch (Exception e) { e.printStackTrace(); } }
Now let’s implement getLocalFolder. This method will simply have the user input a folder path using the console.
private static String getLocalFolder() { System.out.print("\nEnter a folder for download. " + "(Hint: drag a folder to the console window): "); String localFolder = keyboard.nextLine(); return localFolder.replace("\"", ""); // Remove quotes, if supplied }
Finally, we can download our file using the downloadFile method we created earlier.
public static void main(String[] args) { try { SmartVault smartVault = new SmartVault(); authenticate(smartVault); String localFile = getLocalFile(); String remoteFolder = getRemoteFolder(smartVault); System.out.println(String.format("\nUploading '%s' to '%s'", localFile, remoteFolder)); smartVault.uploadFile(localFile, remoteFolder); System.out.println("\nUpload complete"); String remoteFile = getRemoteFile(remoteFolder, localFile); String localFolder = getLocalFolder(); System.out.println(String.format("\nDownloading '%s' to '%s'", remoteFile, localFolder)); smartVault.downloadFile(remoteFile, localFolder); System.out.println("\nDownload complete"); } catch (Exception e) { e.printStackTrace(); } }
Trying It Out
Setting Up
Now that we’ve got a nice wrapper class to handle some basic operations, let’s try it out! We’re going to make a simple console program that uploads a file to SmartVault and downloads it again.
Let’s start with a simple main method.
public static void main(String[] args) { ... }
Authenticating
Include the authenticate method you created using the Autonomous authentication tutorial.
public static void main(String[] args) { try { SmartVault smartVault = new SmartVault(); authenticate(smartVault); } catch (Exception e) { e.printStackTrace(); } }
Downloading a File
Let’s create a method called downloadFile to download a file from SmartVault to the local computer. We’re going to need the path to the file in SmartVault and a folder to store it in on the local machine.
public void downloadFile(String remoteFile, String localFolder) throws Exception { ... }
The /nodes/pth structure only contains file metadata. Actually downloading a file uses a different URI using the file’s document ID, which can be obtained by browsing to the metadata. We can use the browsePath method that we created earlier to do this.
public void downloadFile(String remoteFile, String localFolder) throws Exception { NodeProto.NodeResponse fileNode = browsePath(remoteFile); String remoteDownload = fileNode.getMessage().getDownloadUri(); ... }
Next, we’ll need to create a stream in order to write the file locally. This will require the path to the file including the filename. For the purposes of this tutorial, we will assume that we will save the file with the same name that it has in SmartVault.
public void downloadFile(String remoteFile, String localFolder) throws Exception { NodeProto.NodeResponse fileNode = browsePath(remoteFile); String remoteDownload = fileNode.getMessage().getDownloadUri(); String localFile = String.format("%s/%s", localFolder, Paths.get(remoteFile).getFileName().toString()); FileOutputStream localFileStream = new FileOutputStream(localFile); ... }
The SmartVault library allows us to get a stream pointing to the remote file.
public void downloadFile(String remoteFile, String localFolder) throws Exception { NodeProto.NodeResponse fileNode = browsePath(remoteFile); String remoteDownload = fileNode.getMessage().getDownloadUri(); String localFile = String.format("%s/%s", localFolder, Paths.get(remoteFile).getFileName().toString()); FileOutputStream localFileStream = new FileOutputStream(localFile); InputStream remoteFileStream = _delegation.readFile(remoteDownload).getStream(); ... }
To save the file we can simply copy the remote stream to the local stream. This will automatically copy the data to the local computer.
public void downloadFile(String remoteFile, String localFolder) throws Exception { NodeProto.NodeResponse fileNode = browsePath(remoteFile); String remoteDownload = fileNode.getMessage().getDownloadUri(); String localFile = String.format("%s/%s", localFolder, Paths.get(remoteFile).getFileName().toString()); FileOutputStream localFileStream = new FileOutputStream(localFile); InputStream remoteFileStream = _delegation.readFile(remoteDownload).getStream(); IOUtils.copy(remoteFileStream, localFileStream); ... }
Finally, we’re going to want to close both of these streams.
public void downloadFile(String remoteFile, String localFolder) throws Exception { NodeProto.NodeResponse fileNode = browsePath(remoteFile); String remoteDownload = fileNode.getMessage().getDownloadUri(); String localFile = String.format("%s/%s", localFolder, Paths.get(remoteFile).getFileName().toString()); FileOutputStream localFileStream = new FileOutputStream(localFile); InputStream remoteFileStream = _delegation.readFile(remoteDownload).getStream(); IOUtils.copy(remoteFileStream, localFileStream); remoteFileStream.close(); localFileStream.close(); }
Finishing It Up
Let’s go ahead and add a prompt to have the user press the enter key to exit to prevent the console application from quitting so we can see the of end of the program’s output.
public static void main(String[] args) { try { SmartVault smartVault = new SmartVault(); authenticate(smartVault); String remoteFile = getRemoteFile(remoteFolder, localFile); String localFolder = getLocalFolder(); System.out.println(String.format("\nDownloading '%s' to '%s'", remoteFile, localFolder)); smartVault.downloadFile(remoteFile, localFolder); System.out.println("\nDownload complete"); } catch (Exception e) { e.printStackTrace(); } System.out.println("\nPress 'Enter' key to exit"); keyboard.nextLine(); }
Putting It Together
SmartVault.java
import com.smartvault.proto.*; import com.smartvault.rest.*; import org.apache.commons.io.IOUtils; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.openssl.PEMReader; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.StringReader; import java.nio.file.Paths; import java.security.KeyPair; import java.security.Security; public class SmartVault { private ClientProtocol _protocol; private DelegatedProtocol _delegation; public SmartVault() throws Exception { String clientId = "JavaTutorial"; // Change this to your client ID String privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" + "MIIEpAIBAAKCAQEAxmh2LZYY5SzT+BMmSNoGsjyI7O6fzmozR+mviyOiAIk0bBXa\n" + "U/kLGnaTYe4WE8DyQHweBQq1C5ovUA3L5rqKshoxmhrOtJ04YvMXmEaPBxxfxpLH\n" + "ogqg+7kkjDMs+Mb+EpYwguHKGXhFF80AWMZmfVVquTCuhG6bXUHFmdcVSg4imiE2\n" + "Ah75matYfD/X9aQecLC32gdgUAx7+6JflmQp+xAhr4s+LUORwCLT6v6znzpA89Qy\n" + "/8cc8FS3RrOZtxpjPcY9xK60uY94huPXjuW9Yj9nBgYnqE1hNPZGZCKcwxSInEtC\n" + "GjsAx+bvRiNYdNwtOZz6z6oAN/QX4mEQkE2wlQIDAQABAoIBAHkpD4n1EAzbXDIw\n" + "139DjTVI3ED706EEn345yVZJk0OKhfW/Po1rFwm5AXWbI+Y6PHV+lgJ0MGz+Yggb\n" + "9LlYjxwF/OZjmnkXTXi3hGAcLnmkLSShO8HLhdVSkWwAUGU3d644AzXZ1kXJeT/4\n" + "k06jEbFV+Q9QGDKNLNk9MgMpIjoO5Na5doiGd6UpIVGkZhNL1MVRa1x2ktCz211a\n" + "b9MvsufNB1d7Ady8lY8z794r035ixclCToimMtd4Q5GPjQIVXhSHGjxtMElRv43k\n" + "Xp9EIzdLgOkM7L2tOxMIrBU/5aaErCIfqRER/yIBHc3zlPqh2dp5pK92qx6aml9U\n" + "S3uUL90CgYEA+ztEVRNu4dMiJUBQjJxfx8OWZhfsEsVR6G4+aictXrXFQIppiXZE\n" + "aZrUiGSZm1lnK7/XdbgPowFvBafObe3MtVDEx5xYE9ZYSI5wm4xyqkybLlr2wmQK\n" + "mFdn8l26SpWxnhfBp2nuFk8FyJhuq1kLuTG6zq7xfHZTmH1pSR+jO9sCgYEAyiyG\n" + "lHRGe7TMqzlJ0KTUwVBK75b31pAG/yLWIzyeoU/Y7cTNakj/SGloX6kx0Kk2v2/L\n" + "lsKFab0wMf1XQgX+C+sxvQ+bM8oiVcvQmlfaRLuFYBzdJRd4xhz69Ir4vRaOAY9K\n" + "pbSV9tmEs58oRtm+k/Ks6bRT0KRqTjEebCD8KE8CgYEA7Tpdn+glv9/aUkqUxPG0\n" + "D7HEhsr4BBGG8m+HSD2OPexuQi9w0Hh4yS+GmPRFh8e4ADu6fFI9kbJ8315BMtRl\n" + "hKCr78DV+oVf/8Ng2cCZVe3YasFCWPSWfJusb9PJYTxQ5/OOzULdqvsbfvtRJUOE\n" + "Km+m8huHs/sXnNpvXLkfLhkCgYBg4wuvszVf7Vo0KCUuvv9SkRcIULH++lDQDjLO\n" + "+isPJUPRVoIWkFr+qb0iMuQzmhQpk/reCeSDsu2Y107szhBcR98zOnpnTFQ+B4m1\n" + "nap1S+R0FgEI2IHBd3vwm3TusRNmvfPJC4zemolUx042/fytzBt/eDK+hzyGslVg\n" + "/kG5UwKBgQCG4U6kaT3BjF8Rr+S65JfPKEdZfO6pngva8ySMwB5xdzuX37nMqVZr\n" + "TGc654yj1FCa80UMwUo2ptUE0oCKh3VdZElinG9+wNpO/3nIS/b404A5EdF8QJ6w\n" + "1lHO1FsptGDOpb69WIjqoUzTiMfMEeOCNKlvFI2ZamzDdR6l39J8Cw==\n" + "-----END RSA PRIVATE KEY-----\n"; Security.addProvider(new BouncyCastleProvider()); StringReader reader = new StringReader(privateKey); KeyPair keyPair = (KeyPair) new PEMReader(reader).readObject(); ServerCfg cfg = new ServerCfg("https://rest.smartvault.com", clientId, keyPair.getPrivate()); Authentication auth = new Authentication(cfg); _protocol = auth.createClientProtocol(); } public String requestAuthorization(String email) throws Exception { BasicUserInfoProto.BasicUserInfoResponse response = _protocol.statUser(email); return response.getMessage().getAuthorizationUri(); } public void authenticate(String email) throws Exception { _delegation = _protocol.createDelegatedProtocol(email); } public NodeProto.NodeResponse browsePath(String path) throws Exception { int children = 1; // Immediate contents only return _delegation.navigate(path, children); } public void downloadFile(String remoteFile, String localFolder) throws Exception { NodeProto.NodeResponse fileNode = browsePath(remoteFile); String remoteDownload = fileNode.getMessage().getDownloadUri(); String localFile = String.format("%s/%s", localFolder, Paths.get(remoteFile).getFileName().toString()); FileOutputStream localFileStream = new FileOutputStream(localFile); InputStream remoteFileStream = _delegation.readFile(remoteDownload).getStream(); IOUtils.copy(remoteFileStream, localFileStream); remoteFileStream.close(); localFileStream.close(); } }
Program.java
import com.smartvault.proto.NodeProto; import java.awt.*; import java.net.URI; import java.nio.file.Paths; import java.util.Scanner; public class Program { private static Scanner keyboard = new Scanner(System.in); public static void main(String[] args) { try { SmartVault smartVault = new SmartVault(); authenticate(smartVault); String localFile = getLocalFile(); String remoteFolder = getRemoteFolder(smartVault); String remoteFile = getRemoteFile(remoteFolder, localFile); String localFolder = getLocalFolder(); System.out.println(String.format("\nDownloading '%s' to '%s'", remoteFile, localFolder)); smartVault.downloadFile(remoteFile, localFolder); System.out.println("\nDownload complete"); } catch (Exception e) { e.printStackTrace(); } System.out.println("\nPress 'Enter' key to exit"); keyboard.nextLine(); } private static void authenticate(SmartVault smartVault) throws Exception { // Autonomous authentication System.out.print("Enter your email address: "); String email = keyboard.nextLine(); System.out.print("Have you authorized this application? [y/n]: "); String response = keyboard.nextLine(); if (!response.toLowerCase().startsWith("y")) { String url = smartVault.requestAuthorization(email); Desktop.getDesktop().browse(URI.create(url)); System.out.println("\nPress 'Enter' once you have allowed this application."); keyboard.nextLine(); } smartVault.authenticate(email); } private static String getRemoteFile(String remoteFolder, String localFile) { return String.format("%s/%s", remoteFolder, Paths.get(localFile).getFileName().toString()); } private static String getLocalFolder() { System.out.print("\nEnter a folder for download. " + "(Hint: drag a folder to the console window): "); String localFolder = keyboard.nextLine(); return localFolder.replace("\"", ""); // Remove quotes, if supplied } private static String getLocalFile() { System.out.print("\nEnter the path to a file to upload. " + "(Hint: drag a file to the console window): "); String localFile = keyboard.nextLine(); return localFile.replace("\"", ""); // Remove quotes, if supplied } private static String getRemoteFolder(SmartVault smartVault) throws Exception { NodeProto.NodeResponse rootNode = smartVault.browsePath("nodes/pth"); String account = rootNode.getMessage().getChildrenList().get(0).getName(); return String.format("/nodes/pth/%s/My First Vault/My First folder", account); } }
Here’s What You’ll Need
To perform autonomous authentication, we will first need to generate a RSA key pair. Visit Generating a Key Pair to view the steps on how to create them.
If you have not yet created a developer account or client ID, visit Creating a Developer Account to view the steps on how to create them.
Setting Up
You will also need to install the C# API wrapper library, begin communicating with SmartVault, and create a method to handle pin-based authentication. The following tutorial will guide you through this process:
Pin-Based Authentication
Browsing the Folder Structure
A very common task in SmartVault is browsing the folder structure. For generic integrations, this is done using the /nodes/pth structure. The root of this structure contains the user’s accounts. Accounts contain vaults, and vaults contain folders. Folders are where files are typically stored.
Let’s create a method called BrowsePath to implement browsing this structure in a simplified way. This method will take in a path to browse and output the response. The variable children controls how deep in the structure we want to traverse on each call. Setting this to 1 will make the response contain the immediate contents of the path retrieved.
public NodeResponse BrowsePath(string path) { int children = 1; // Immediate contents only return _delegation.Navigate(new AbsolutePath(path), children); }
Downloading Files
Let’s create a method called DownloadFile to download a file from SmartVault to the local computer. We’re going to need the path to the file in SmartVault and a folder to store it in on the local machine.
public void DownloadFile(string remoteFile, string localFolder) { ... }
The /nodes/pth structure only contains file metadata. Actually downloading a file uses a different URI using the file’s document ID, which can be obtained by browsing to the metadata. We can use the BrowsePath method that we created earlier to do this.
public void DownloadFile(string remoteFile, string localFolder) { NodeResponse fileNode = BrowsePath(remoteFile); string remoteDownload = fileNode.Message.DownloadUri; ... }
Next, we’ll need to create a stream in order to write the file locally. This will require the path to the file including the filename. For the purposes of this tutorial, we will assume that we will save the file with the same name that it has in SmartVault.
public void DownloadFile(string remoteFile, string localFolder) { NodeResponse fileNode = BrowsePath(remoteFile); string remoteDownload = fileNode.Message.DownloadUri; string localFile = String.Format("{0}\\{1}", localFolder, Path.GetFileName(remoteFile)); FileStream localFileStream = File.Create(localFile); ... }
The SmartVault library allows us to get a stream pointing to the remote file.
public void DownloadFile(string remoteFile, string localFolder) { NodeResponse fileNode = BrowsePath(remoteFile); string remoteDownload = fileNode.Message.DownloadUri; string localFile = String.Format("{0}\\{1}", localFolder, Path.GetFileName(remoteFile)); FileStream localFileStream = File.Create(localFile); Stream remoteFileStream = _delegation.ReadFile(new AbsolutePath(remoteDownload)).Stream; ... }
To save the file, we can simply copy the remote stream to the local stream. This will automatically copy the data to the local computer.
public void DownloadFile(string remoteFile, string localFolder) { NodeResponse fileNode = BrowsePath(remoteFile); string remoteDownload = fileNode.Message.DownloadUri; string localFile = String.Format("{0}\\{1}", localFolder, Path.GetFileName(remoteFile)); FileStream localFileStream = File.Create(localFile); Stream remoteFileStream = _delegation.ReadFile(new AbsolutePath(remoteDownload)).Stream; remoteFileStream.CopyTo(localFileStream); ... }
Finally, we’re going to want to close both of these streams.
public void DownloadFile(string remoteFile, string localFolder) { NodeResponse fileNode = BrowsePath(remoteFile); string remoteDownload = fileNode.Message.DownloadUri; string localFile = String.Format("{0}\\{1}", localFolder, Path.GetFileName(remoteFile)); FileStream localFileStream = File.Create(localFile); Stream remoteFileStream = _delegation.ReadFile(new AbsolutePath(remoteDownload)).Stream; remoteFileStream.CopyTo(localFileStream); remoteFileStream.Close(); localFileStream.Close(); }
Trying It Out
Setting Up
Now that we’ve got a nice wrapper class to handle some basic operations, let’s try it out! We’re going to make a simple console program that uploads a file to SmartVault and downloads it again.
Let’s start with a simple Main method.
class Program { static void Main(string[] args) { ... } }
Authenticating
Include the authenticate method you created using the Pin-Based Authentication tutorial.
static void Main(string[] args) { try { SmartVault smartVault = new SmartVault(); Authenticate(smartVault); ... } catch (Exception e) { Console.WriteLine(e.Message); } }
Downloading a File
Before we can download our file again, we’re going to need the full path to the file in SmartVault. Let’s call a new method called GetRemoteFile to retrieve this. We can figure this out using the original path to the file on the local system, and the remote folder path that we determined earlier.
static void Main(string[] args) { try { SmartVault smartVault = new SmartVault(); Authenticate(smartVault); string remoteFile = GetRemoteFile(remoteFolder, localFile); ... } catch (Exception e) { Console.WriteLine(e.Message); } }
Now let’s implement GetRemoteFile. All we need to do here is append the filename to end of the remote folder path.
private static string GetRemoteFile(string remoteFolder, string localFile) { return String.Format("{0}/{1}", remoteFolder, Path.GetFileName(localFile)); }
We also need to know where to save the file. Let’s call a new method called GetLocalFolder to obtain that information from the user.
static void Main(string[] args) { try { SmartVault smartVault = new SmartVault(); Authenticate(smartVault); string localFile = GetLocalFile(); string remoteFolder = GetRemoteFolder(smartVault); Console.WriteLine("\nUploading '{0}' to '{1}'", localFile, remoteFolder); smartVault.UploadFile(localFile, remoteFolder); Console.WriteLine("\nUpload complete"); string remoteFile = GetRemoteFile(remoteFolder, localFile); string localFolder = GetLocalFolder(); ... } catch (Exception e) { Console.WriteLine(e.Message); } }
Now let’s implement GetLocalFolder. This method will simply have the user input a folder path using the console.
private static string GetLocalFolder() { Console.Write("\nEnter a folder for download. " + "(Hint: drag a folder to the console window): "); string localFolder = Console.ReadLine(); return localFolder.Replace("\"", ""); // Remove quotes, if supplied }
Finally, we can download our file using the DownloadFile method we created earlier.
static void Main(string[] args) { try { SmartVault smartVault = new SmartVault(); Authenticate(smartVault); string localFile = GetLocalFile(); string remoteFolder = GetRemoteFolder(smartVault); string remoteFile = GetRemoteFile(remoteFolder, localFile); string localFolder = GetLocalFolder(); Console.WriteLine("\nDownloading '{0}' to '{1}'", remoteFile, localFolder); smartVault.DownloadFile(remoteFile, localFolder); Console.WriteLine("\nDownload complete"); } catch (Exception e) { Console.WriteLine(e.Message); } }
Finishing It Up
Let’s go ahead and add a prompt to have the user press the enter key to exit to prevent the console application from quitting so we can see the of end of the program’s output.
static void Main(string[] args) { try { SmartVault smartVault = new SmartVault(); Authenticate(smartVault); string remoteFile = GetRemoteFile(remoteFolder, localFile); string localFolder = GetLocalFolder(); Console.WriteLine("\nDownloading '{0}' to '{1}'", remoteFile, localFolder); smartVault.DownloadFile(remoteFile, localFolder); Console.WriteLine("\nDownload complete"); } catch (Exception e) { Console.WriteLine(e.Message); } Console.WriteLine("\nPress any key to exit"); Console.ReadKey(); }
Putting It Together
Smartvault.cs
using System; using SmartVault.Core; using SmartVault.Proto; using SmartVault.Rest; using System.IO; namespace HelloWorldSVRest { class SmartVault { private PublicClientProtocol _protocol; private DelegatedProtocol _delegation; public SmartVault() { string clientId = "CSharpTutorial"; // Change this to your client ID PublicClientCfg cfg = new PublicClientCfg(new Uri("https://rest.smartvault.com"), clientId); _protocol = new PublicClientProtocol(cfg); } public string RequestPin(string email) { return _protocol.GetPinRequestEndpoint(email); } public void Authenticate(string email, string pin) { _delegation = _protocol.CreateDelegatedProtocol(email, pin); } public NodeResponse BrowsePath(string path) { int children = 1; // Immediate contents only return _delegation.Navigate(new AbsolutePath(path), children); } public void UploadFile(string localFile, string remoteFolder) { FileStream stream = new FileStream(localFile, FileMode.Open); UploadFileRequest.Builder builder = UploadFileRequest.CreateBuilder(); builder.Name = Path.GetFileName(localFile); _delegation.PostFile(new AbsolutePath(remoteFolder), builder.Build(), stream); stream.Close(); } public void DownloadFile(string remoteFile, string localFolder) { NodeResponse fileNode = BrowsePath(remoteFile); string remoteDownload = fileNode.Message.DownloadUri; string localFile = String.Format("{0}\\{1}", localFolder, Path.GetFileName(remoteFile)); FileStream localFileStream = File.Create(localFile); Stream remoteFileStream = _delegation.ReadFile(new AbsolutePath(remoteDownload)).Stream; remoteFileStream.CopyTo(localFileStream); remoteFileStream.Close(); localFileStream.Close(); } } }
Program.cs
using System; using System.Diagnostics; using System.IO; namespace HelloWorldSVRest { class Program { static void Main(string[] args) { try { SmartVault smartVault = new SmartVault(); Authenticate(smartVault); string localFile = GetLocalFile(); string remoteFolder = GetRemoteFolder(smartVault); Console.WriteLine("\nUploading '{0}' to '{1}'", localFile, remoteFolder); smartVault.UploadFile(localFile, remoteFolder); Console.WriteLine("\nUpload complete"); string remoteFile = GetRemoteFile(remoteFolder, localFile); string localFolder = GetLocalFolder(); Console.WriteLine("\nDownloading '{0}' to '{1}'", remoteFile, localFolder); smartVault.DownloadFile(remoteFile, localFolder); Console.WriteLine("\nDownload complete"); } catch (Exception e) { Console.WriteLine(e.Message); } Console.WriteLine("\nPress any key to exit"); Console.ReadKey(); } private static void Authenticate(SmartVault smartVault) { // Pin-based authentication with manual pin entry Console.Write("Enter your email address: "); string email = Console.ReadLine(); Console.Write("Do you have a pin? [y/n]: "); string response = Console.ReadLine(); if (!response.ToLower().StartsWith("y")) { string url = smartVault.RequestPin(email); Process.Start(url); } Console.Write("Enter your pin: "); string pin = Console.ReadLine(); smartVault.Authenticate(email, pin); } private static string GetLocalFile() { Console.Write("\nEnter the path to a file to upload. " + "(Hint: drag a file to the console window): "); string localFile = Console.ReadLine(); return localFile.Replace("\"", ""); // Remove quotes, if supplied } private static string GetRemoteFolder(SmartVault smartVault) { var rootNode = smartVault.BrowsePath("/nodes/pth"); string account = rootNode.Message.ChildrenList[0].Name; return String.Format("/nodes/pth/{0}/My First Vault/My First folder", account); } private static string GetRemoteFile(string remoteFolder, string localFile) { return String.Format("{0}/{1}", remoteFolder, Path.GetFileName(localFile)); } private static string GetLocalFolder() { Console.Write("\nEnter a folder for download. " + "(Hint: drag a folder to the console window): "); string localFolder = Console.ReadLine(); return localFolder.Replace("\"", ""); // Remove quotes, if supplied } } }
Web Application with ASP.NET MVC4 Using C#
Here’s What You’ll Need
If you have not yet created a developer account or client ID, visit Creating a Developer Account.(For OAuth Support, select User PIN since this is how we will be authenticating.)
Installing the Library
We could form individual REST API calls and communicate with SmartVault that way, but why do this when this work has already been done for you? Our C# API wrapper library allows you to perform actions with SmartVault without writing individual REST API requests. This is available as a NuGet package called SmartVault.Rest and can be obtained from the standard nuget.org repository:
Now that we have the library installed, we can start writing some code.
Setting Up
Let’s create a new class called SmartVault in the Models folder to handle communication with the SmartVault API. We will need to include the SmartVault library:
using SmartVault.Core; using SmartVault.Proto; using SmartVault.Rest; class SmartVault { . . . }
Opening the Connection
Let’s add three instance variables to our class to handle communication with SmartVault:
private PublicClientCfg _clientCfg; private PublicClientProtocol _protocol; private DelegatedProtocol _delegation;
The _clientCfg object created here will be used to store the connection information with SmartVault. The _protocol object will handle tasks on behalf of the client. In our case, this will be used to get the authorization URL. The _delegation object will allow us to perform actions on behalf of the user. We can use this to browse and manage files, as well as perform uploads and downloads.
Let’s create a constructor to set up an initial connection with SmartVault. This will initialize the _clientCfg and _protocol objects:
public SmartVault() { string clientId = "CSharpTutorial"; // Change this to your client ID _clientCfg = new PublicClientCfg(new Uri("https://rest.smartvault.com"), clientId); _protocol = new PublicClientProtocol(_clientCfg); }
NOTE: You will need to change the Client ID to the one you registered earlier using the SmartVault Portal.
Authentication
For this tutorial, we’re going to be using pin-based authentication with a callback. The way that this works is that the user will need to be directed to the SmartVault Portal to authorize our application. Once the user does this, he or she will be redirected back to our application. This callback includes the delegation token that we will use to authenticate all the user’s actions.
Requesting a Pin
The SmartVault API has a call to get a URL from the server for the user to visit in order to authorize an application. We will need the user’s email address in order to do this.
Let’s start by creating a method called RequestPin which will take in the user’s email address and output the URL as a string. There’s just one simple library call that we’ll need to do in order to get the URL. Here’s the implementation for RequestPin:
public string RequestPin(string email) { return _protocol.GetPinRequestEndpoint(email); }
Authenticating with SmartVault
Once we have the delegation token, we can use it along with their email address to actually authenticate. Let’s create a method called AuthenticateWithToken to take care of this.
public void AuthenticateWithToken(string email, string token) { _delegation = _protocol.CreateDelegatedProtocol(email, pin); }
Using the email address and token, we will need to build a DelegationTokenResponse object that contains this information.
public void AuthenticateWithToken(string email, string token) { DelegationTokenResponse.Types.Message.Builder messageBuilder = new DelegationTokenResponse.Types.Message.Builder(); messageBuilder.SetToken(token); messageBuilder.SetUserEmail(email); DelegationTokenResponse.Builder responseBuilder = new DelegationTokenResponse.Builder(); responseBuilder.SetMessage(messageBuilder.Build()); . . . }
From there, we can create a UserCfg object containing all information to connect with SmartVault and authenticate as our user. We can now initialize the _delegation object to perform all the actions as this user.
public void AuthenticateWithToken(string email, string token) { DelegationTokenResponse.Types.Message.Builder messageBuilder = new DelegationTokenResponse.Types.Message.Builder(); messageBuilder.SetToken(token); messageBuilder.SetUserEmail(email); DelegationTokenResponse.Builder responseBuilder = new DelegationTokenResponse.Builder(); responseBuilder.SetMessage(messageBuilder.Build()); UserCfg cfg = new UserCfg(email, responseBuilder.Build(), _clientCfg); _delegation = new DelegatedProtocol(cfg); }
Browsing the Folder Structure
A very common task in SmartVault is browsing the folder structure. For generic integrations, this is done using the /nodes/pth structure. The root of this structure contains the user’s accounts. Accounts contain vaults, and vaults contain folders. Folders are where files are typically stored.
Let’s create a method called BrowsePath to implement browsing this structure in a simplified way. This method will take in a path to browse and output the response. The variable children controls how deep in the structure we want to traverse on each call. Setting this to 1 will make the response contain the immediate contents of the path retrieved.
public NodeResponse BrowsePath(string path) { int children = 1; // Immediate contents only return _delegation.Navigate(new AbsolutePath(path), children); }
Uploading Files
Let’s create a method called UploadFile to handle uploading files from the local computer to SmartVault. We will need three pieces of information to be able to upoad a file: a stream containing the file’s data, the path to a remote folder to put it in, and the filename as which we want to store it.
public void UploadFile(Stream fileData, string remoteFolder, string fileName) { . . . }
The first step with loading a file is building an UploadFileRequest. This contains the file’s metadata, including the filename in SmartVault.
public void UploadFile(Stream fileData, string remoteFolder, string fileName) { UploadFileRequest.Builder builder = UploadFileRequest.CreateBuilder(); builder.Name = fileName; . . . }
Next, we need to actually upload the file, using a library call that takes in the request, the folder path to store it in, and the stream pointing to the file data.
public void UploadFile(Stream fileData, string remoteFolder, string fileName) { UploadFileRequest.Builder builder = UploadFileRequest.CreateBuilder(); builder.Name = fileName; _delegation.PostFile(new AbsolutePath(remoteFolder), builder.Build(), fileData); . . . }
Finally, we’re going to want to close that stream.
public void UploadFile(Stream fileData, string remoteFolder, string fileName) { UploadFileRequest.Builder builder = UploadFileRequest.CreateBuilder(); builder.Name = fileName; _delegation.PostFile(new AbsolutePath(remoteFolder), builder.Build(), fileData); fileData.Close(); }
Downloading Files
Since this is a web application, there is little reason to actually download files to the server. Instead, we will return the download link to a file so that the user can download it to their machine. Let’s create a method called GetDownloadLink to handle this, which will take in the path to a remote file and return the URL to download the file. We will use the BrowsePath method we created earlier to obtain this information from the file’s metadata.
public string GetDownloadLink(string remoteFile) { NodeResponse fileNode = BrowsePath(remoteFile); return fileNode.Message.DownloadLinkUri; }
Trying It Out
Authorization
Now that we’ve got a nice wrapper class to handle some basic operations, let’s try it out! We’re going to make a very basic website that performs authentication.
Let’s create a Home view to get the user’s email address so they can authorize our application. This will contain a webpage called Index.cshtml.
Our webpage will have a field for the user to enter their email address, which will be passed to the controller as a string.
@model stringWelcome Welcome!
@using (Html.BeginForm()) { @Html.ValidationSummary(true) Enter your email address: @Html.EditorForModel(Model, "email") }
Now we’ll need a controller to actually make this do something. Let’s create one called HomeController.
public class HomeController : Controller { . . . }
We’ll need a method called Index, which will simply display our page.
public ActionResult Index() { return View(); }
Next we’ll need another method to handle the POST request from our page. This will take in the string containing the user’s email address.
[HttpPost] public ActionResult Index(string email) { . . . }
Now let’s use create an instance of the SmartVault model. We’re going to store the model in the session data so that we can reference it from other pages.
[HttpPost] public ActionResult Index(string email) { Models.SmartVault smartVault = new Models.SmartVault(); Session["smartVault"] = smartVault; . . . }
Next, we can use the SmartVault model to get the URL to authorize our application.
[HttpPost] public ActionResult Index(string email) { Models.SmartVault smartVault = new Models.SmartVault(); Session["smartVault"] = smartVault; string url = smartVault.RequestPin(email); . . . }
We’ll need to register our callback. This is done by tacking on a new parameter to the URL called redirect_uri. Once the user has authorized our application, SmartVault will redirect the user to this URL with a GET request. The request will contain parameters containing the user’s delegation token.
Let’s have SmartVault redirect the user to the URL in our application called Auth to handle the authentication.
[HttpPost] public ActionResult Index(string email) { Models.SmartVault smartVault = new Models.SmartVault(); Session["smartVault"] = smartVault; string url = smartVault.RequestPin(email); url += String.Format("&redirect_uri={0}/Auth", Request.Url.GetLeftPart(UriPartial.Authority)); . . . }
Finally, we can redirect the user to SmartVault to do the authorization.
[HttpPost] public ActionResult Index(string email) { Models.SmartVault smartVault = new Models.SmartVault(); Session["smartVault"] = smartVault; string url = smartVault.RequestPin(email); url += String.Format("&redirect_uri={0}/Auth", Request.Url.GetLeftPart(UriPartial.Authority)); return new RedirectResult(url); }
Authentication
Because of the callback we set up, SmartVault will redirect the user to the path /Auth in our application. Let’s create a controller called AuthController to handle this request and authenticate our user.
public class AuthController : Controller { . . . }
Let’s create an Index method that takes in the two parameters that SmartVault will return to us: access_token and email.
public ActionResult Index(string access_token, string email) { . . . }
Let’s get our SmartVault object we created earlier from the session data, and use the AuthenticateWithToken method that we created to authenticate.
public ActionResult Index(string access_token, string email) { Models.SmartVault smartVault = (Models.SmartVault)Session["smartVault"]; smartVault.AuthenticateWithToken(email, access_token); . . . }
Finally, let’s redirect the user to a new page at the path /UploadFile fromwhich they will be able to upload a file.
public ActionResult Index(string access_token, string email) { Models.SmartVault smartVault = (Models.SmartVault)Session["smartVault"]; smartVault.AuthenticateWithToken(email, access_token); return Redirect("/UploadFile"); }
Uploading a File
Let’s create an UploadFile view to allow the user to upload a file. This will contain a webpage called Index.cshtml.
Index.cshtml will simply contain a form to allow the user to upload a file.
Upload File Upload File
@FileUpload.GetHtml( initialNumberOfFiles:1, allowMoreFilesToBeAdded:false, includeFormTag:true, uploadText:"Upload")
Now we need to create a controller class called UploadFileController to make this do something.
public class UploadFileController : Controller { ... }
Let’s add a method called Index to display our page.
public ActionResult Index() { return View(); }
Now we need to add a method to handle the POST request from our page.
[HttpPost] public ActionResult Index(int? id) { ... }
Let’s retrieve our SmartVault object from the session data and get the file out of the request that the user sent us.
[HttpPost] public ActionResult Index(int? id) { Models.SmartVault smartVault = (Models.SmartVault)Session["smartVault"]; HttpPostedFileBase uploadedFile = Request.Files[0]; . . . }
If the request is not null, Let’s use the SmartVault object to upload the file to SmartVault. Notice UploadFile uses a method called GetRemoteFolder that retrieves the path to a folder in which to store our file in SmartVault.
[HttpPost] public ActionResult Index(int? id { Models.SmartVault smartVault = (Models.SmartVault)Session["smartVault"]; HttpPostedFileBase uploadedFile = Request.Files[0]; if (uploadedFile != null) { smartVault.UploadFile(uploadedFile.InputStream, GetRemoteFolder(smartVault), uploadedFile.FileName); . . . } }
Let’s implement GetRemoteFolder. SmartVault automatically creates an account for the user on signup containing a vault called My First Vault and a folder called My First folder. For this tutorial, let’s assume that we’re going to upload the file to My First folder. If you have changed the name of this vault or folder in your account, you’ll probably want to update them here to match.
This still doesn’t give us the account name, which is randomly generated on signup. But we can use our BrowsePath method to retrieve it.
public string GetRemoteFolder(Models.SmartVault smartVault)
{
var rootNode = smartVault.BrowsePath(“/nodes/pth”);
string account = rootNode.Message.ChildrenList[0].Name;
return String.Format(“/nodes/pth/{0}/My First Vault/My First folder”, account);
}
Now let’s store the entire path to the file in SmartVault in the session data.
[HttpPost] public ActionResult Index(int? id) { Models.SmartVault smartVault = (Models.SmartVault)Session["smartVault"]; HttpPostedFileBase uploadedFile = Request.Files[0]; if (uploadedFile != null) { smartVault.UploadFile(uploadedFile.InputStream, GetRemoteFolder(smartVault), uploadedFile.FileName); Session["remoteFile"] = GetRemoteFolder(smartVault) + "/" + uploadedFile.FileName; . . . } }
Finally, let’s redirect the user to a new page from which they can download their file. Also remember to set the message as null in the case that the request was empty.
[HttpPost] public ActionResult Index(int? id) { Models.SmartVault smartVault = (Models.SmartVault)Session["smartVault"]; HttpPostedFileBase uploadedFile = Request.Files[0]; if (uploadedFile != null) { smartVault.UploadFile(uploadedFile.InputStream, GetRemoteFolder(smartVault), uploadedFile.FileName); Session["remoteFile"] = GetRemoteFolder(smartVault) + "/" + uploadedFile.FileName; TempData["message"] = "File uploaded successfully."; return RedirectToAction("index"); } TempData["message"] = null; return RedirectToAction("index"); }
Downloading a File
Let’s create a page on which the user can click a link to download their file. To do this, let’s create a DownloadFile view. This will contain a webpage called Index.cshtml.
This Index.cshtml file will simply contain a link the user can click to download their file, the URL to which will be passed in as a string.
@model stringDownload File Download File
Click here to download your file
Now let’s create a controller called DownloadFileController so that this page will actually work.
public class DownloadFileController : Controller { . . . }
We’ll need a method called Index, which will be called when the user attempts to load our page.
public ActionResult Index() { . . . }
Let’s retrieve our SmartVault object and the path to the remote file that we stored earlier in the session data.
public ActionResult Index() { Models.SmartVault smartVault = (Models.SmartVault)Session["smartVault"]; string remoteFile = (string)Session["remoteFile"]; ... }
We can use the SmartVault object to get the download link for our file.
public ActionResult Index() { Models.SmartVault smartVault = (Models.SmartVault)Session["smartVault"]; string remoteFile = (string)Session["remoteFile"]; string url = smartVault.GetDownloadLink(remoteFile); ... }
Finally, let’s return our webpage, passing in the URL so the link on the page can point to our file.
public ActionResult Index() { Models.SmartVault smartVault = (Models.SmartVault)Session["smartVault"]; string remoteFile = (string)Session["remoteFile"]; string url = smartVault.GetDownloadLink(remoteFile); return View(model:url); }
Putting It Together
SmartVault.cs
using System; using SmartVault.Core; using SmartVault.Proto; using SmartVault.Rest; using System.IO; namespace ASPNET_MVC_HelloWorldSVRest.Models { public class SmartVault { private readonly PublicClientProtocol _protocol; private DelegatedProtocol _delegation; private readonly PublicClientCfg _clientCfg; public SmartVault() { const string clientId = "CSharpTutorial"; // Change this to your client ID _clientCfg = new PublicClientCfg(new Uri("https://rest.smartvault.com"), clientId); _protocol = new PublicClientProtocol(_clientCfg); } public string RequestPin(string email) { return _protocol.GetPinRequestEndpoint(email); } public void AuthenticateWithToken(string email, string token) { DelegationTokenResponse.Types.Message.Builder messageBuilder = new DelegationTokenResponse.Types.Message.Builder(); messageBuilder.SetToken(token); messageBuilder.SetUserEmail(email); DelegationTokenResponse.Builder responseBuilder = new DelegationTokenResponse.Builder(); responseBuilder.SetMessage(messageBuilder.Build()); UserCfg cfg = new UserCfg(email, responseBuilder.Build(), _clientCfg); _delegation = new DelegatedProtocol(cfg); } public NodeResponse BrowsePath(string path) { const int children = 1; // Immediate contents only return _delegation.Navigate(new AbsolutePath(path), children); } public void UploadFile(Stream localFile, string remoteFolder, string fileName) { UploadFileRequest.Builder builder = UploadFileRequest.CreateBuilder(); builder.Name = fileName; _delegation.PostFile(new AbsolutePath(remoteFolder), builder.Build(), localFile); localFile.Close(); } public string GetDownloadLink(string remoteFile) { NodeResponse fileNode = BrowsePath(remoteFile); return fileNode.Message.DownloadLinkUri; } } }
AuthController.cs
using System.Web.Mvc; namespace ASPNET_MVC_HelloWorldSVRest.Controllers { public class AuthController : Controller { // // GET: /Auth/ public ActionResult Index(string access_token, string email) { Models.SmartVault smartVault = (Models.SmartVault)Session["smartVault"]; smartVault.AuthenticateWithToken(email, access_token); return Redirect("/UploadFile"); } } }
HomeController.cs
using System; using System.Web.Mvc; namespace ASPNET_MVC_HelloWorldSVRest.Controllers { public class HomeController : Controller { // // GET: /Home/ public ActionResult Index() { return View(); } [HttpPost] public ActionResult Index(string email) { Models.SmartVault smartVault = new Models.SmartVault(); string url = smartVault.RequestPin(email); if (Request.Url != null) { url += String.Format("&redirect_uri={0}/Auth", Request.Url.GetLeftPart(UriPartial.Authority)); } Session["smartVault"] = smartVault; return new RedirectResult(url); } } }
Home – index.cshtml
@model stringWelcome Welcome!
@using (Html.BeginForm()) { @Html.ValidationSummary(true) Enter your email address: @Html.EditorForModel(Model, "email") }
UploadFileController.cs
using System; using System.Web; using System.Web.Mvc; namespace ASPNET_MVC_HelloWorldSVRest.Controllers { public class UploadFileController : Controller { // // GET: /UploadFile/ public ActionResult Index() { return View(); } [HttpPost] public ActionResult Index(int? id) { Models.SmartVault smartVault = (Models.SmartVault)Session["smartVault"]; HttpPostedFileBase uploadedFile = Request.Files[0]; if (uploadedFile != null) { smartVault.UploadFile(uploadedFile.InputStream, GetRemoteFolder(smartVault), uploadedFile.FileName); Session["remoteFile"] = GetRemoteFolder(smartVault) + "/" + uploadedFile.FileName; } return new RedirectResult("/DownloadFile"); } public string GetRemoteFolder(Models.SmartVault smartVault) { var rootNode = smartVault.BrowsePath("/nodes/pth"); string account = rootNode.Message.ChildrenList[0].Name; return String.Format("/nodes/pth/{0}/My First Vault/My First folder", account); } } }
UploadFile – index.cshtml
Upload File Upload File
@FileUpload.GetHtml( initialNumberOfFiles:1, allowMoreFilesToBeAdded:false, includeFormTag:true, uploadText:"Upload")
DownloadFileController.cs
using System.Web.Mvc; namespace ASPNET_MVC_HelloWorldSVRest.Controllers { public class DownloadFileController : Controller { // // GET: /DownloadFile/ public ActionResult Index() { Models.SmartVault smartVault = (Models.SmartVault)Session["smartVault"]; string url = smartVault.GetDownloadLink((string)Session["remoteFile"]); return View(model:url); } } }
DownloadFile – index.cshtml
@model stringDownload File Download File
Click here to download your file
Leave A Comment?