Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save cburnette/bce6236076a15aeb7c03 to your computer and use it in GitHub Desktop.
Save cburnette/bce6236076a15aeb7c03 to your computer and use it in GitHub Desktop.
Upload file from local disk to a specific Box folder with auto-refreshing tokens using encrypted tokens in C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Box.V2;
using Box.V2.Auth;
using Box.V2.Config;
using Box.V2.Exceptions;
using Box.V2.Models;
using Nito.AsyncEx;
using System.IO;
using System.Security.Cryptography; //make sure you add a reference to system.security
namespace MoveFileFromDiskToBox
{
//Make sure you install the NuGet package 'Box Windows SDK V2'
class Program
{
const string CLIENT_ID = "YOUR_CLIENT_ID";
const string CLIENT_SECRET = "YOUR_CLIENT_SECRET";
const string TOKEN_FILENAME = "Data.dat";
const string TOKEN_FILE_LENGTH_FILENAME = "Data_length.dat";
const char TOKEN_SPLIT_CHAR = '|';
const string BOX_FOLDER_PATH = "/Personal Backups/Test"; //for this example code, make sure this folder structure exists in Box
//set these to point to whatever file you want to upload; make sure it exists!
const string PATH_TO_FILE = "C:\\";
const string FILENAME = "example.pdf";
static string access_token;
static string refresh_token;
static BoxClient client;
static void Main(string[] args)
{
if (args.Length == 1)
{
//If tokens are passed in as args assume they are valid; this is the way to bootstrap the refresh cycle.
//You only need to do this the first time you run the program and then the tokens will automatically refresh across runs.
//Use the tool at this URL to generate your first set of tokens: https://box-token-generator.herokuapp.com/
//There should be one command line arg that looks like: ACCESS_TOKEN|REFRESH_TOKEN
var tokens = args[0].Split(TOKEN_SPLIT_CHAR);
access_token = tokens[0];
refresh_token = tokens[1];
}
else
{
//After you have bootstrapped the tokens you should not send anything in as command line args.
//The program will read the encrypted token file, decrypt the tokens, refresh the tokens, and then create a new session to Box.
//read in the length of the data to decrypt
int bytesToRead = int.Parse(File.ReadAllText(TOKEN_FILE_LENGTH_FILENAME, UnicodeEncoding.ASCII));
//we need to read the tokens from the encrypted token file
using (FileStream fStream = new FileStream(TOKEN_FILENAME, FileMode.Open))
{
byte[] decryptedData = DecryptDataFromStream(null, DataProtectionScope.CurrentUser, fStream, bytesToRead);
string decryptedString = UnicodeEncoding.ASCII.GetString(decryptedData);
var tokens = decryptedString.Split(TOKEN_SPLIT_CHAR);
access_token = tokens[0];
refresh_token = tokens[1];
}
}
//http://blog.stephencleary.com/2012/02/async-console-programs.html
try
{
var config = new BoxConfig(CLIENT_ID, CLIENT_SECRET, new Uri("http://localhost"));
var session = new OAuthSession(access_token, refresh_token, 3600, "bearer");
client = new BoxClient(config, session);
AsyncContext.Run(() => MainAsync());
}
catch (Exception ex)
{
Console.Error.WriteLine(ex);
}
Console.WriteLine();
Console.Write("Press return to exit...");
Console.ReadLine();
}
static async Task MainAsync()
{
//first we need to refresh the tokens and persist them in a file
var newSession = await client.Auth.RefreshAccessTokenAsync(access_token);
//store the tokens on disk with encryption. You don't want your tokens exposed to other users
WriteTokensEncrypted(newSession.AccessToken, newSession.RefreshToken);
//look up the folder id based on the path
var boxFolderId = await FindBoxFolderId(BOX_FOLDER_PATH);
using (FileStream fs = File.Open(PATH_TO_FILE + FILENAME, FileMode.Open, FileAccess.Read))
{
Console.WriteLine("Uploading file...");
// Create request object with name and parent folder the file should be uploaded to
BoxFileRequest request = new BoxFileRequest()
{
Name = DateTime.Now.ToFileTime() + "-" + FILENAME, //for this demo, don't collide with any other files
Parent = new BoxRequestEntity() { Id = boxFolderId }
};
BoxFile f = await client.FilesManager.UploadAsync(request, fs);
}
}
static async Task<String> FindBoxFolderId(string path)
{
var folderNames = path.Split('/');
folderNames = folderNames.Where((f) => !String.IsNullOrEmpty(f)).ToArray(); //get rid of leading empty entry in case of leading slash
var currFolderId = "0"; //the root folder is always "0"
foreach (var folderName in folderNames)
{
var folderInfo = await client.FoldersManager.GetInformationAsync(currFolderId);
var foundFolder = folderInfo.ItemCollection.Entries.OfType<BoxFolder>().First((f) => f.Name == folderName);
currFolderId = foundFolder.Id;
}
return currFolderId;
}
private static void WriteTokensEncrypted(string access_token, string refresh_token)
{
//store the tokens in an encrypted file for later retrieval;
//http://msdn.microsoft.com/en-US/library/ms229741(v=vs.110).aspx
byte[] toEncrypt = UnicodeEncoding.ASCII.GetBytes(access_token + TOKEN_SPLIT_CHAR + refresh_token);
File.Delete(TOKEN_FILENAME); //blow away any old file
FileStream fStream = new FileStream(TOKEN_FILENAME, FileMode.OpenOrCreate);
int bytesWritten = EncryptDataToStream(toEncrypt, null, DataProtectionScope.CurrentUser, fStream);
fStream.Close();
//write the length of bytes that were encrypted; we need this when decrypting
File.WriteAllText(TOKEN_FILE_LENGTH_FILENAME, bytesWritten.ToString(), UnicodeEncoding.ASCII);
}
public static int EncryptDataToStream(byte[] Buffer, byte[] Entropy, DataProtectionScope Scope, Stream S)
{
int length = 0;
// Encrypt the data in memory.
byte[] encryptedData = ProtectedData.Protect(Buffer, Entropy, Scope);
// Write the encrypted data to a stream.
if (S.CanWrite && encryptedData != null)
{
S.Write(encryptedData, 0, encryptedData.Length);
length = encryptedData.Length;
}
// Return the length that was written to the stream.
return length;
}
public static byte[] DecryptDataFromStream(byte[] Entropy, DataProtectionScope Scope, Stream S, int Length)
{
byte[] inBuffer = new byte[Length];
byte[] outBuffer;
// Read the encrypted data from a stream.
if (S.CanRead)
{
S.Read(inBuffer, 0, Length);
outBuffer = ProtectedData.Unprotect(inBuffer, Entropy, Scope);
}
else
{
throw new IOException("Could not read the stream.");
}
// Return the length that was written to the stream.
return outBuffer;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment