From 71a2030a05f74088f5feb9463d5156c179602a92 Mon Sep 17 00:00:00 2001 From: Yaakov Date: Sun, 26 Sep 2021 14:00:51 +1000 Subject: [PATCH] Add command to generate SAS token for private containers --- src/console/Commands/Cdn/StorageSasCommand.cs | 68 +++++++++++++++++++ src/console/Program.cs | 3 +- src/console/shamir.csproj | 1 + 3 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 src/console/Commands/Cdn/StorageSasCommand.cs diff --git a/src/console/Commands/Cdn/StorageSasCommand.cs b/src/console/Commands/Cdn/StorageSasCommand.cs new file mode 100644 index 0000000..30558c9 --- /dev/null +++ b/src/console/Commands/Cdn/StorageSasCommand.cs @@ -0,0 +1,68 @@ +using System; +using System.Diagnostics; +using System.Threading.Tasks; +using Azure.Storage; +using Azure.Storage.Blobs; +using Azure.Storage.Sas; +using CommandLine; +using Microsoft.Azure.Storage; + +namespace Shamir.Console +{ + public class StorageSasOptions + { + [Option("connection-string", Required = false, HelpText = "Azure Storage connection string for the Storage Account backing the CDN.")] + public string? ConnectionString { get; set; } + + [Option('h', "host", Required = false, HelpText = "Hostname to generate the SAS token for.")] + public string? HostName { get; set; } + + [Option('d', "days", Default = 7, HelpText = "Number of days that the SAS token should remain valid for.")] + public int ValidityPeriodDays { get; set; } + + [Value(0, MetaName = "path", Required = true, HelpText = "Path to enumerate, starting with the Azure Storage container name.")] + public string? Path { get; set; } + } + + public sealed class StorageSasCommand : ParsedArgumentsCommand + { + public override string Name => "sas"; + + public override string Description => "Generate a SAS token for a file in Storage."; + + public override ValueTask ExecuteAsync(IServiceProvider serviceProvider, StorageSasOptions options) + { + var connectionString = options.ConnectionString ?? Environment.GetEnvironmentVariable("AZURE_CONNECTION_STRING"); + var account = CloudStorageAccount.Parse(connectionString); + + Debug.Assert(options.Path != null, "Path should be set."); + + var delimiterIndex = options.Path.IndexOf('/'); + var (containerName, path) = delimiterIndex > 0 + ? (options.Path[..delimiterIndex], options.Path[(delimiterIndex + 1)..]) + : (options.Path, string.Empty); + + var client = new BlobServiceClient(connectionString); + + var builder = new BlobSasBuilder(BlobSasPermissions.Read, DateTimeOffset.UtcNow.AddDays(options.ValidityPeriodDays)); + builder.BlobContainerName = containerName; + builder.BlobName = path; + builder.Protocol = SasProtocol.Https; + builder.Resource = "b"; + + var key = new StorageSharedKeyCredential(account.Credentials.AccountName, account.Credentials.ExportBase64EncodedKey()); + var parameters = builder.ToSasQueryParameters(key); + var uri = new UriBuilder + { + Scheme = "https", + Host = options.HostName ?? account.BlobStorageUri.PrimaryUri.Host, + Path = options.Path, + Query = parameters.ToString(), + }; + + System.Console.WriteLine(uri.Uri.AbsoluteUri); + + return ValueTask.FromResult(0); + } + } +} \ No newline at end of file diff --git a/src/console/Program.cs b/src/console/Program.cs index 2f5ea58..871caaf 100644 --- a/src/console/Program.cs +++ b/src/console/Program.cs @@ -29,7 +29,8 @@ namespace Shamir.Console ImmutableArray.Empty, ImmutableArray.Create( new StorageLsCommand(), - new StorageCopyCommand() + new StorageCopyCommand(), + new StorageSasCommand() )) ), ImmutableArray.Empty diff --git a/src/console/shamir.csproj b/src/console/shamir.csproj index 4a2c32c..08af8e0 100644 --- a/src/console/shamir.csproj +++ b/src/console/shamir.csproj @@ -11,6 +11,7 @@ +