Skip to content

Instantly share code, notes, and snippets.

@CurtHagenlocher
Created August 13, 2019 14:20
Show Gist options
  • Save CurtHagenlocher/23a692099186da26d322181b3742ba39 to your computer and use it in GitHub Desktop.
Save CurtHagenlocher/23a692099186da26d322181b3742ba39 to your computer and use it in GitHub Desktop.
Work-in-progress Azure Table Storage
section AzStorage;
[DataSource.Kind="TableStorage"]
shared TableStorage.Contents = (url) =>
Text.FromBinary(Web.Contents(url, [Headers=SignRequest(url)]));
[DataSource.Kind="TableStorage"]
shared FileStorage.Contents = (url) =>
Text.FromBinary(Web.Contents(url, [Headers=SignRequestBlob(url)]));
[DataSource.Kind="TableStorage"]
shared TableStorage.Action = (verb, url, body) =>
WebAction.Request(verb, url, [Headers=SignRequest(url) & [#"Content-Type"="application/json"], Content=Json.FromValue(body)]);
[DataSource.Kind="TableStorage"]
shared TableStorage.Table = (url, table) => Table.View(null, []
);
// Text.FromBinary(Web.Contents(url, [Headers=SignRequest(url)]));
TableStorage = [
Authentication = [Key=null],
Label = "TableStorage",
Type = "Custom",
MakeResourcePath = MakeResourcePath,
ParseResourcePath = (resourcePath) => { resourcePath },
TestConnection = (resource) => { "TableStorage.Contents", resource }
];
DataSourceError = "DataSource.Error";
ExpressionError = "Expression.Error";
MakeResourcePath = (url as text) as text =>
let
parts = Uri.Parts(url),
portText = if parts[Port]? = null or
(parts[Port]? = 80 and Text.Lower(parts[Scheme]) = "http") or
(parts[Port]? = 443 and Text.Lower(parts[Scheme]) = "https")
then ""
else ":" & Number.ToText(parts[Port]),
resourcePath = Text.Lower(parts[Scheme] & "://" & parts[Host] & portText)
in
resourcePath;
SignRequest = (url) =>
let
parts = Uri.Parts(url),
account = Text.Split(parts[Host], "."){0},
resource = "/" & account & Text.Split(parts[Path], "?"){0},
date = DateTimeZone.ToText(DateTimeZone.UtcNow(), "r"),
stringToSign = date & "#(lf)" & resource,
payload = Text.ToBinary(stringToSign, TextEncoding.Utf8),
password = Extension.CurrentCredential()[Password]?,
key = if password = null then "" else password,
secret = try Binary.FromText(key, BinaryEncoding.Base64) otherwise #binary({0}),
signature = Binary.ToText(Crypto.CreateHmac(CryptoAlgorithm.SHA256, secret, payload), BinaryEncoding.Base64)
in
[
Authorization = "SharedKeyLite " & account & ":" & signature,
Accept = "application/json;odata=nometadata",
#"x-ms-version" = "2018-03-28",
#"x-ms-date" = DateTimeZone.ToText(DateTimeZone.UtcNow(), "r")
];
SignRequestBlob = (url) =>
let
parts = Uri.Parts(url),
account = Text.Split(parts[Host], "."){0},
resource = "/" & account & Text.Split(parts[Path], "?"){0},
date = DateTimeZone.ToText(DateTimeZone.UtcNow(), "r"),
stringToSign = "GET#(lf)#(lf)#(lf)#(lf)x-ms-date:" & date & "#(lf)x-ms-version:2018-03-28#(lf)" & resource,
payload = Text.ToBinary(stringToSign, TextEncoding.Utf8),
password = Extension.CurrentCredential()[Password]?,
key = if password = null then "" else password,
secret = try Binary.FromText(key, BinaryEncoding.Base64) otherwise #binary({0}),
signature = Binary.ToText(Crypto.CreateHmac(CryptoAlgorithm.SHA256, secret, payload), BinaryEncoding.Base64)
in
[
Authorization = "SharedKeyLite " & account & ":" & signature,
Accept = "application/json;odata=nometadata",
#"x-ms-version" = "2018-03-28",
#"x-ms-date" = DateTimeZone.ToText(DateTimeZone.UtcNow(), "r")
];
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment