I've been receiving an error from Amazon web service - InvalidParameterValue
Either Action or Operation query parameter must be present.
I believe it is most likely due to the signature being incorrect as the XML document and Header matches that of a test I did in their scratchpad.
Does anything stand out as being incorrect?
Thanks,
Clare
private static string ConstructCanonicalQueryString(SortedDictionary<string, string> sortedParameters)
{
var builder = new StringBuilder();
if (sortedParameters.Count == 0)
{
builder.Append(string.Empty);
return builder.ToString();
}
foreach (var kvp in sortedParameters)
{
builder.Append(PercentEncodeRfc3986(kvp.Key));
builder.Append("=");
builder.Append(PercentEncodeRfc3986(kvp.Value));
builder.Append("&");
}
var canonicalString = builder.ToString();
return canonicalString.Substring(0, canonicalString.Length - 1);
}
private static string PercentEncodeRfc3986(string value)
{
value = HttpUtility.UrlEncode(string.IsNullOrEmpty(value) ? string.Empty : value, Encoding.UTF8);
if (string.IsNullOrEmpty(value))
{
return string.Empty;
}
value = value.Replace("'", "%27")
.Replace("(", "%28")
.Replace(")", "%29")
.Replace("*", "%2A")
.Replace("!", "%21")
.Replace("%7e", "~")
.Replace("+", "%20")
.Replace(":", "%3A");
var sbuilder = new StringBuilder(value);
for (var i = 0; i < sbuilder.Length; i++)
{
if (sbuilder[i] != '%')
{
continue;
}
if (!char.IsLetter(sbuilder[i + 1]) && !char.IsLetter(sbuilder[i + 2]))
{
continue;
}
sbuilder[i + 1] = char.ToUpper(sbuilder[i + 1]);
sbuilder[i + 2] = char.ToUpper(sbuilder[i + 2]);
}
return sbuilder.ToString();
}
public string SignRequest(Dictionary<string, string> parametersUrl, Dictionary<string, string>
parametersSignture)
{
var secret = Encoding.UTF8.GetBytes(parametersSignture["Secret"]);
var signer = new HMACSHA256(secret);
var pc = new ParamComparer();
var sortedParameters = new SortedDictionary<string, string>(parametersUrl, pc);
var orderedParameters = ConstructCanonicalQueryString(sortedParameters);
var builder = new StringBuilder();
builder.Append(parametersSignture["RequestMethod"])
.Append(" \n")
.Append(parametersSignture["EndPoint"])
.Append("\n")
.Append("/\n")
.Append(orderedParameters);
var stringToSign = builder.ToString();
var toSign = Encoding.UTF8.GetBytes(stringToSign);
var sigBytes = signer.ComputeHash(toSign);
var signature = Convert.ToBase64String(sigBytes);
return signature.Replace("=", "%3D").Replace("/", "%2F").Replace("+", "%2B");
}
public class ParamComparer : IComparer<string>
{
public int Compare(string p1, string p2)
{
return string.CompareOrdinal(p1, p2);
}
}
The issue was that the Action wasn't included correctly into the Request
Related
I am using Amazon's Textract service for extracting tables, Forms from pdf documnets.
The example provided at Github here is working for single page document only. But as per demo provided by AWS they are able to extract multi page pdf docs as well.
As per documentation we have to call same service for multi pages as well. But it is not working for me.
All the examples provided by them are either in python or java.
I am doing it in dotnet core.
Any help?
Here is my code.
public IActionResult FileExtract(string filename)
{
try
{
string lineText = "";
string wordText = "";
string fieldsText = "";
string fieldsText2 = "";
string tableText = "";
// Extracting file in below code.
var textractAnalysisClient = BuildTextractClient();
var document = PrepareDocument(textractAnalysisClient, "FORMS", filename);
document.Pages.ForEach(page =>
{
page.Lines.ForEach(line =>
{
lineText += "<button class='rawlabel'>" + line.Text + "</button>";
line.Words.ForEach(word =>
{
wordText += word.Text;
});
});
page.Form.Fields.ForEach(f =>
{
fieldsText += "<div><h5>" + f.Key + "</h5><p style='background-color:lightgray;width: 200px;padding: 6px;'>"
+ f.Value + "</p></div>";
});
var key = "Phone Number:";
var field = page.Form.GetFieldByKey(key);
if (field != null)
{
fieldsText2 += "Key: " + field.Key + " | Value: " + field.Value;
}
});
tableText = "<table id='customers'>";
document = PrepareDocument(textractAnalysisClient, "TABLES", filename);
document.Pages.ForEach(page =>
{
page.Tables.ForEach(table =>
{
var r = 0;
table.Rows.ForEach(row =>
{
r++;
tableText += "<tr>";
var c = 0;
row.Cells.ForEach(cell =>
{
c++;
tableText += "<td>";
tableText += cell.Text + "</td>";
});
tableText += "</tr>";
});
});
});
tableText += "</table>";
objJsonResponse.fieldsText = fieldsText;
objJsonResponse.fieldsText2 = fieldsText2;
objJsonResponse.lineText = lineText;
objJsonResponse.tableText = tableText;
objJsonResponse.wordText = wordText;
objJsonResponse.responsecode = 1;
return Json(objJsonResponse);
}
catch (Exception ex)
{
this.objJsonResponse.responsecode = -1;
this.objJsonResponse.error = "failed";
return Json(this.objJsonResponse);
}
}
static TextractTextAnalysisService BuildTextractClient()
{
var builder = new ConfigurationBuilder()
.SetBasePath(Environment.CurrentDirectory)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddEnvironmentVariables()
.Build();
var awsOptions = builder.GetAWSOptions();
return new TextractTextAnalysisService(awsOptions.CreateServiceClient<IAmazonTextract>());
}
static TextractDocument PrepareDocument(TextractTextAnalysisService textractAnalysisClient, string type, string FormFile)
{
var task = textractAnalysisClient.StartDocumentAnalysis(BucketName, FormFile, type);
var jobId = task.Result;
textractAnalysisClient.WaitForJobCompletion(jobId);
var results = textractAnalysisClient.GetJobResults(jobId);
return new TextractDocument(results);
}
We are trying to call AWS API Gateway from C# Windows Service, for a background job. Which was supposed to trigger API Gateway periodically initialize request?
We used RestSharp to invoke API Endpoint, the class called AwsAuthenticator , which is inherited from RestSharp.Authenticators.IAuthenticator.
But when we invoke API Gateway we received with error as
"The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details."
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
namespace ConsoleApp3
{
public class AwsAuthenticator : RestSharp.Authenticators.IAuthenticator
{
public string AccessKeyId { get; }
public string AccessKeySecret { get; }
public string Region { get; }
public AwsAuthenticator(string accessKeyId, string accessKeySecret, string region)
{
AccessKeyId = accessKeyId;
AccessKeySecret = accessKeySecret;
Region = region;
}
private static HashSet<string> ignoredHeaders = new HashSet<string>() {
"authorization",
"content-length",
"content-type",
"user-agent"
};
public void Authenticate(RestSharp.IRestClient client, RestSharp.IRestRequest request)
{
DateTime signingDate = DateTime.UtcNow;
SetContentMd5(request);
SetContentSha256(request);
SetHostHeader(request, client);
SetDateHeader(request, signingDate);
SortedDictionary<string, string> headersToSign = GetHeadersToSign(request);
string signedHeaders = GetSignedHeaders(headersToSign);
string canonicalRequest = GetCanonicalRequest(client, request, headersToSign);
byte[] canonicalRequestBytes = System.Text.Encoding.UTF8.GetBytes(canonicalRequest);
string canonicalRequestHash = BytesToHex(ComputeSha256(canonicalRequestBytes));
string stringToSign = GetStringToSign(Region, signingDate, canonicalRequestHash);
byte[] signingKey = GenerateSigningKey(Region, signingDate);
byte[] stringToSignBytes = System.Text.Encoding.UTF8.GetBytes(stringToSign);
byte[] signatureBytes = SignHmac(signingKey, stringToSignBytes);
string signature = BytesToHex(signatureBytes);
string authorization = GetAuthorizationHeader(signedHeaders, signature, signingDate, Region);
request.AddHeader("Authorization", authorization);
}
public string GetCredentialString(DateTime signingDate, string region)
{
return AccessKeyId + "/" + GetScope(region, signingDate);
}
private string GetAuthorizationHeader(string signedHeaders, string signature, DateTime signingDate, string region)
{
return "AWS4-HMAC-SHA256 Credential=" + this.AccessKeyId + "/" + GetScope(region, signingDate) +
", SignedHeaders=" + signedHeaders + ", Signature=" + signature;
}
private string GetSignedHeaders(SortedDictionary<string, string> headersToSign)
{
return string.Join(";", headersToSign.Keys);
}
private byte[] GenerateSigningKey(string region, DateTime signingDate)
{
byte[] formattedDateBytes = System.Text.Encoding.UTF8.GetBytes(signingDate.ToString("yyyMMdd"));
byte[] formattedKeyBytes = System.Text.Encoding.UTF8.GetBytes("AWS4" + this.AccessKeySecret);
byte[] dateKey = SignHmac(formattedKeyBytes, formattedDateBytes);
byte[] regionBytes = System.Text.Encoding.UTF8.GetBytes(region);
byte[] dateRegionKey = SignHmac(dateKey, regionBytes);
byte[] serviceBytes = System.Text.Encoding.UTF8.GetBytes("execute-api");
byte[] dateRegionServiceKey = SignHmac(dateRegionKey, serviceBytes);
byte[] requestBytes = System.Text.Encoding.UTF8.GetBytes("aws4_request");
return SignHmac(dateRegionServiceKey, requestBytes);
}
private byte[] SignHmac(byte[] key, byte[] content)
{
HMACSHA256 hmac = new HMACSHA256(key);
hmac.Initialize();
return hmac.ComputeHash(content);
}
private string GetStringToSign(string region, DateTime signingDate, string canonicalRequestHash)
{
return "AWS4-HMAC-SHA256\n" +
signingDate.ToString("yyyyMMddTHHmmssZ") + "\n" +
GetScope(region, signingDate) + "\n" +
canonicalRequestHash;
}
private string GetScope(string region, DateTime signingDate)
{
string formattedDate = signingDate.ToString("yyyyMMdd");
return formattedDate + "/" + region + "/execute-api/aws4_request";
}
private byte[] ComputeSha256(byte[] body)
{
SHA256 sha256 = SHA256.Create();
return sha256.ComputeHash(body);
}
private string BytesToHex(byte[] checkSum)
{
return BitConverter.ToString(checkSum).Replace("-", string.Empty).ToLower();
}
public string PresignPostSignature(string region, DateTime signingDate, string policyBase64)
{
byte[] signingKey = this.GenerateSigningKey(region, signingDate);
byte[] stringToSignBytes = System.Text.Encoding.UTF8.GetBytes(policyBase64);
byte[] signatureBytes = SignHmac(signingKey, stringToSignBytes);
string signature = BytesToHex(signatureBytes);
return signature;
}
public string PresignURL(RestSharp.IRestClient client, RestSharp.IRestRequest request, int expires)
{
DateTime signingDate = DateTime.UtcNow;
string requestQuery = "";
string path = request.Resource;
requestQuery = "X-Amz-Algorithm=AWS4-HMAC-SHA256&";
requestQuery += "X-Amz-Credential="
+ this.AccessKeyId
+ Uri.EscapeDataString("/" + GetScope(Region, signingDate))
+ "&";
requestQuery += "X-Amz-Date="
+ signingDate.ToString("yyyyMMddTHHmmssZ")
+ "&";
requestQuery += "X-Amz-Expires="
+ expires
+ "&";
requestQuery += "X-Amz-SignedHeaders=host";
string canonicalRequest = GetPresignCanonicalRequest(client, request, requestQuery);
byte[] canonicalRequestBytes = System.Text.Encoding.UTF8.GetBytes(canonicalRequest);
string canonicalRequestHash = BytesToHex(ComputeSha256(canonicalRequestBytes));
string stringToSign = GetStringToSign(Region, signingDate, canonicalRequestHash);
byte[] signingKey = GenerateSigningKey(Region, signingDate);
byte[] stringToSignBytes = System.Text.Encoding.UTF8.GetBytes(stringToSign);
byte[] signatureBytes = SignHmac(signingKey, stringToSignBytes);
string signature = BytesToHex(signatureBytes);
// Return presigned url.
return client.BaseUrl + path + "?" + requestQuery + "&X-Amz-Signature=" + signature;
}
private string GetPresignCanonicalRequest(RestSharp.IRestClient client, RestSharp.IRestRequest request, string requestQuery)
{
LinkedList<string> canonicalStringList = new LinkedList<string>();
canonicalStringList.AddLast(request.Method.ToString());
string path = request.Resource;
if (!path.StartsWith("/"))
{
path = "/" + path;
}
canonicalStringList.AddLast(path);
canonicalStringList.AddLast(requestQuery);
canonicalStringList.AddLast("host:" + client.BaseUrl.Host);
canonicalStringList.AddLast("");
canonicalStringList.AddLast("host");
canonicalStringList.AddLast("UNSIGNED-PAYLOAD");
return string.Join("\n", canonicalStringList);
}
private string GetCanonicalRequest(RestSharp.IRestClient client, RestSharp.IRestRequest request,
SortedDictionary<string, string> headersToSign)
{
LinkedList<string> canonicalStringList = new LinkedList<string>();
canonicalStringList.AddLast(request.Method.ToString());
string[] path = request.Resource.Split(new char[] { '?' }, 2);
if (!path[0].StartsWith("/"))
{
path[0] = "/" + path[0];
}
canonicalStringList.AddLast(path[0]);
string query = "";
if (path.Length == 2)
{
var parameterString = path[1];
var parameterList = parameterString.Split('&');
SortedSet<string> sortedQueries = new SortedSet<string>();
foreach (string individualParameterString in parameterList)
{
if (individualParameterString.Contains('='))
{
string[] splitQuery = individualParameterString.Split(new char[] { '=' }, 2);
sortedQueries.Add(splitQuery[0] + "=" + splitQuery[1]);
}
else
{
sortedQueries.Add(individualParameterString + "=");
}
}
query = string.Join("&", sortedQueries);
}
canonicalStringList.AddLast(query);
foreach (string header in headersToSign.Keys)
{
canonicalStringList.AddLast(header + ":" + headersToSign[header]);
}
canonicalStringList.AddLast("");
canonicalStringList.AddLast(string.Join(";", headersToSign.Keys));
if (headersToSign.Keys.Contains("x-amz-content-sha256"))
{
canonicalStringList.AddLast(headersToSign["x-amz-content-sha256"]);
}
else
{
canonicalStringList.AddLast("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
}
return string.Join("\n", canonicalStringList);
}
private SortedDictionary<string, string> GetHeadersToSign(RestSharp.IRestRequest request)
{
var headers = request.Parameters.Where(p => p.Type.Equals(RestSharp.ParameterType.HttpHeader)).ToList();
SortedDictionary<string, string> sortedHeaders = new SortedDictionary<string, string>();
foreach (var header in headers)
{
string headerName = header.Name.ToLower();
string headerValue = header.Value.ToString();
if (!ignoredHeaders.Contains(headerName))
{
sortedHeaders.Add(headerName, headerValue);
}
}
return sortedHeaders;
}
private void SetDateHeader(RestSharp.IRestRequest request, DateTime signingDate)
{
request.AddHeader("x-amz-date", signingDate.ToString("yyyyMMddTHHmmssZ"));
}
private void SetHostHeader(RestSharp.IRestRequest request, RestSharp.IRestClient client)
{
request.AddHeader("Host", client.BaseUrl.Host + (client.BaseUrl.Port != 80 ? ":" + client.BaseUrl.Port : string.Empty));
}
private void SetContentSha256(RestSharp.IRestRequest request)
{
if (request.Method == RestSharp.Method.PUT || request.Method.Equals(RestSharp.Method.POST))
{
var bodyParameter = request.Parameters.Where(p => p.Type.Equals(RestSharp.ParameterType.RequestBody)).FirstOrDefault();
if (bodyParameter == null)
{
request.AddHeader("x-amz-content-sha256", "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
return;
}
byte[] body = null;
if (bodyParameter.Value is string)
{
body = System.Text.Encoding.UTF8.GetBytes(bodyParameter.Value as string);
}
if (bodyParameter.Value is byte[])
{
body = bodyParameter.Value as byte[];
}
if (body == null)
{
body = new byte[0];
}
SHA256 sha256 = System.Security.Cryptography.SHA256.Create();
byte[] hash = sha256.ComputeHash(body);
string hex = BitConverter.ToString(hash).Replace("-", string.Empty).ToLower();
request.AddHeader("x-amz-content-sha256", hex);
}
else
{
request.AddHeader("x-amz-content-sha256", "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
}
}
private void SetContentMd5(RestSharp.IRestRequest request)
{
if (request.Method == RestSharp.Method.PUT || request.Method.Equals(RestSharp.Method.POST))
{
var bodyParameter = request.Parameters.Where(p => p.Type.Equals(RestSharp.ParameterType.RequestBody)).FirstOrDefault();
if (bodyParameter == null)
{
return;
}
byte[] body = null;
if (bodyParameter.Value is string)
{
body = System.Text.Encoding.UTF8.GetBytes(bodyParameter.Value as string);
}
if (bodyParameter.Value is byte[])
{
body = bodyParameter.Value as byte[];
}
if (body == null)
{
body = new byte[0];
}
MD5 md5 = MD5.Create();
byte[] hash = md5.ComputeHash(body);
string base64 = Convert.ToBase64String(hash);
request.AddHeader("Content-MD5", base64);
}
}
}
////////////////////////
public class MainClass
{
public void Execute()
{
var client = new RestClient("https://nm47849kod.execute-api.ap-southeast1.amazonaws.com/samplegateway/");
var request = new RestRequest("/", Method.POST);
var postData = new { Mode = 4 };
request.AddParameter("application/json",JsonConvert.SerializeObject(postData),ParameterType.RequestBody); AwsAuthenticator awsAuthenticator = new AwsAuthenticator("AccessKeyXXXXX", "SECKEYxxxx12313123123123123", "apsoutheast-1");
awsAuthenticator.Authenticate(client,request);
IRestResponse response = client.Execute(request);
var content = response.Content; // raw content as string
Console.WriteLine(content);
Console.ReadLine();
}
}
Error Details:
{"message":"The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.\n\nThe Canonical String for this request should have been\n'POST\n/samplegateway/\n\ncontent-md5:rkT7BbUvFInBgrPCuA0UZw==\nhost:nm47849kod.execute-api.ap-southeast-1.amazonaws.com\nx-amz-content-sha256:0318f62547c9078687e73f987ec26fa557047b67f54bb99b8047c950990ae42c\nx-amz-date:20190601T102835Z\n\ncontent-md5;host;x-amz-content-sha256;x-amz-date\n0318f62547c9078687e73f987ec26fa557047b67f54bb99b8047c950990ae42c'\n\nThe String-to-Sign should have been\n'AWS4-HMAC-SHA256\n20190601T102835Z\n20190601/ap-southeast-1/execute-api/aws4_request\n8f89bd5010655fb26a8de5e29d48d6129ac7875e5eb6bc2faeb8e41864b4d49e'\n"}.
We identified the problem.
Below is the working code and this resolves my issue. I am sharing this so that the group can get benefitted. The above class is entirely rewritten and when invoked it worked.
public class ApiRequest
{
private const string ServiceName = "execute-api";
private const string Algorithm = "AWS4-HMAC-SHA256";
private const string ContentType = "application/json";
private const string SignedHeaders = "content-type;host;x-amz-date;x-api-key";
private const string DateTimeFormat = "yyyyMMddTHHmmssZ";
private const string DateFormat = "yyyyMMdd";
public AwsApiGatewayRequest AwsApiGatewayRequest;
public ApiRequest(AwsApiGatewayRequest request)
{
AwsApiGatewayRequest = request;
if (string.IsNullOrEmpty(AwsApiGatewayRequest.RequestMethod))
AwsApiGatewayRequest.RequestMethod = "POST";
if (string.IsNullOrEmpty(AwsApiGatewayRequest.xApiKey))
AwsApiGatewayRequest.xApiKey = "";
}
public WebResponse GetPostResponse()
{
var request = GetPostRequest();
return request.GetResponse();
}
public WebRequest GetPostRequest()
{
string hashedRequestPayload = CreateRequestPayload(AwsApiGatewayRequest.JsonData);
string authorization = Sign(hashedRequestPayload, AwsApiGatewayRequest.RequestMethod, AwsApiGatewayRequest.AbsolutePath, AwsApiGatewayRequest.QueryString);
string requestDate = DateTime.UtcNow.ToString(DateTimeFormat);
var webRequest = WebRequest.Create($"https://{AwsApiGatewayRequest.Host}{AwsApiGatewayRequest.AbsolutePath}");
webRequest.Timeout = AwsApiGatewayRequest.RequestTimeout.HasValue ? AwsApiGatewayRequest.RequestTimeout.Value : 50000;
webRequest.Method = AwsApiGatewayRequest.RequestMethod;
webRequest.ContentType = ContentType;
webRequest.Headers.Add("X-Amz-date", requestDate);
webRequest.Headers.Add("Authorization", authorization);
webRequest.Headers.Add("x-amz-content-sha256", hashedRequestPayload);
if (!string.IsNullOrEmpty(AwsApiGatewayRequest.AdditionalHeaders))
{
// parse apart and apply the additional headers
string[] headers = AwsApiGatewayRequest.AdditionalHeaders.Split(';');
foreach (string header in headers)
{
var headervalue = header.Split('=');
if (headervalue.Count() == 2)
webRequest.Headers.Add(headervalue[0], headervalue[1]);
}
}
if (!string.IsNullOrEmpty(AwsApiGatewayRequest.SessionToken))
webRequest.Headers.Add("X-Amz-Security-Token", AwsApiGatewayRequest.SessionToken);
webRequest.ContentLength = AwsApiGatewayRequest.JsonData.Length;
var encoding = new ASCIIEncoding();
var data = encoding.GetBytes(AwsApiGatewayRequest.JsonData);
using (var newStream = webRequest.GetRequestStream())
{
newStream.Write(data, 0, data.Length);
newStream.Close();
}
return webRequest;
}
private string CreateRequestPayload(string jsonString)
{
return HexEncode(Hash(ToBytes(jsonString)));
}
private string Sign(string hashedRequestPayload, string requestMethod, string canonicalUri, string canonicalQueryString)
{
var currentDateTime = DateTime.UtcNow;
var dateStamp = currentDateTime.ToString(DateFormat);
var requestDate = currentDateTime.ToString(DateTimeFormat);
var credentialScope = $"{dateStamp}/{AwsApiGatewayRequest.RegionName}/{ServiceName}/aws4_request";
var headers = new SortedDictionary<string, string> {
{ "content-type", ContentType },
{ "host", AwsApiGatewayRequest.Host },
{ "x-amz-date", requestDate },
{ "x-api-key", AwsApiGatewayRequest.xApiKey }
};
var canonicalHeaders = string.Join("\n", headers.Select(x => x.Key.ToLowerInvariant() + ":" + x.Value.Trim())) + "\n";
// Task 1: Create a Canonical Request For Signature Version 4
var canonicalRequest = $"{requestMethod}\n{canonicalUri}\n{canonicalQueryString}\n{canonicalHeaders}\n{SignedHeaders}\n{hashedRequestPayload}";
var hashedCanonicalRequest = HexEncode(Hash(ToBytes(canonicalRequest)));
// Task 2: Create a String to Sign for Signature Version 4
var stringToSign = $"{Algorithm}\n{requestDate}\n{credentialScope}\n{hashedCanonicalRequest}";
// Task 3: Calculate the AWS Signature Version 4
var signingKey = GetSignatureKey(AwsApiGatewayRequest.SecretKey, dateStamp, AwsApiGatewayRequest.RegionName, ServiceName);
var signature = HexEncode(HmacSha256(stringToSign, signingKey));
// Task 4: Prepare a signed request
// Authorization: algorithm Credential=access key ID/credential scope, SignedHeadaers=SignedHeaders, Signature=signature
var authorization = $"{Algorithm} Credential={AwsApiGatewayRequest.AccessKey}/{dateStamp}/{AwsApiGatewayRequest.RegionName}/{ServiceName}/aws4_request, SignedHeaders={SignedHeaders}, Signature={signature}";
return authorization;
}
private byte[] GetSignatureKey(string key, string dateStamp, string regionName, string serviceName)
{
var kDate = HmacSha256(dateStamp, ToBytes("AWS4" + key));
var kRegion = HmacSha256(regionName, kDate);
var kService = HmacSha256(serviceName, kRegion);
return HmacSha256("aws4_request", kService);
}
private byte[] ToBytes(string str)
{
return Encoding.UTF8.GetBytes(str.ToCharArray());
}
private string HexEncode(byte[] bytes)
{
return BitConverter.ToString(bytes).Replace("-", string.Empty).ToLowerInvariant();
}
private byte[] Hash(byte[] bytes)
{
return SHA256.Create().ComputeHash(bytes);
}
private byte[] HmacSha256(string data, byte[] key)
{
return new HMACSHA256(key).ComputeHash(ToBytes(data));
}
}
Execution Parameter:
var request = new AwsApiGatewayRequest()
{
RegionName = "",
Host = ,
AccessKey = "",
SecretKey = "",
RequestMethod = "POST",
AbsolutePath = ,
JsonData = "{\"Mode\":\"4\"}",
SessionToken = ""
};//Invoke this using RestClient...
The problem here is we failed to add an additional header which was required by AWS. In this version, we have added hence it rectified.
Thanks for your support.
I am making a merge code to take data from my spreadsheet and populate merge tags in a Google Doc. The part of the code I am unable to write correctly is the part that writes the tags back to the Google Doc. I have been able to locate the tags but the code doesn't replace them.
Here is what I've written so far.
function mergeApplication() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Merge Data");
var range = sheet.getActiveRange();
var formSheet = ss.getSheetByName("Form Responses");
var lastRow = formSheet.getLastRow();
var lastColumn = sheet.getMaxColumns();
function checkAndComplete() {
var urlColumn = lastColumn;
var checkColumn = (urlColumn - 1);
var checkRange = sheet.getRange(2, checkColumn, (lastRow - 1), 1);
var check = checkRange.getBackgrounds();
var red = "#ff0404";
var yellow = "#ffec0a";
var green = "#3bec3b";
for (var i = 0; i < check.length; i++) {
if (check[i] == green) {
continue;
} else {
var statusCell = sheet.getRange((i+2), checkColumn, 1, 1);
var urlCell = sheet.getRange((i+2), urlColumn, 1, 1);
var dataRow = sheet.getRange((i+2), 1, 1, (lastColumn - 2));
function mergeTasks() {
function docCreator() {
// var templateConditionRange = sheet.getRange((i+2), column);
// var templateConditionCheck = templateConditionRange.getValues();
var docTemplate1 = DriveApp.getFileById(id);
// var docTemplate2 = DriveApp.getFileById(id);
// var docTemplate3 = DriveApp.getFileById(id);
var folderDestination = DriveApp.getFolderById(id);
var clientName = sheet.getRange((i+2), 3).getValue();
var date = sheet.getRange((i+2), 1).getValue();
// if (templateConditionCheck[i] == "") {
var docToUse = docTemplate1;
// }
// if (templateConditionCheck[i] == "") {
// var docToUse = docTemplate2;
// }
// if (templateConditionCheck[i] == "") {
// var docToUse = docTemplate3;
// }
var docName = "Merge Tester Doc for " + clientName + " [" + date + "]";
var docCopy = docToUse.makeCopy(docName, folderDestination);
var docId = docCopy.getId();
var docURL = DriveApp.getFileById(docId).getUrl();
var docToSend = DriveApp.getFileById(docId);
var docBody = DocumentApp.openById(docId).getBody().getText();
function tagReplace() {
var taggedArray = [docBody.match(/\<{2}[\w\d\S]+\>{2}/g)];
var headerArray = [sheet.getRange(1, 1, 1, (lastColumn - 2)).getValues()];
var dataArray = [dataRow.getValues()];
var strippedArray = [];
Logger.log("The preliminary length of taggedArray is " + taggedArray.length);
Logger.log(taggedArray);
function tagStrip() {
for (var t = 0; t < taggedArray.length; t++) {
var strippedString = taggedArray[t].slice(2, -3).toString();
strippedArray.push(strippedString);
Logger.log("The current strippedArray length is " + strippedArray.length);
}
Logger.log("The final strippedArray length is " + strippedArray.length);
Logger.log("The final taggedArray length is " + taggedArray.length);
Logger.log("The final, completed strippedArray is " + strippedArray);
}
function dataMatch() {
for (var s = 0; s < strippedArray.length;) {
for (var h = 0; h < headerArray.length;) {
if (strippedArray[s] == headerArray[h]) {
docBody.replaceText(taggedArray[s].String(), dataArray[h].String());
h=0;
s++;
} else {
h++;
}
}
}
}
tagStrip;
dataMatch;
}
function emailCreator() {
var emailTag = sheet.getRange((i+2), (urlColumn - 2)).getValue();
var emailBody = HtmlService.createHtmlOutputFromFile("Email Template").getContent();
var personalizers = clientName + " [" + date + "]";
var subject = "Merge Tester Email for " + personalizers;
MailApp.sendEmail(emailTag, subject, emailBody, {
name: "Christopher Anderson",
attachments: [docToSend],
html: emailBody,
});
}
tagReplace();
statusCell.setBackground(yellow);
emailCreator();
urlCell.setValue(docURL)
}
statusCell.setBackground(red);
docCreator();
statusCell.setBackground(green);
}
mergeTasks();
}
}
}
checkAndComplete();
}
The problem section is here:
function tagReplace() {
var taggedArray = [docBody.match(/\<{2}[\w\d\S]+\>{2}/g)];
var headerArray = [sheet.getRange(1, 1, 1, (lastColumn - 2)).getValues()];
var dataArray = [dataRow.getValues()];
var strippedArray = new Array();
Logger.log("The preliminary length of taggedArray is " + taggedArray.length);
Logger.log(taggedArray);
function tagStrip() {
for (var t = 0; t < taggedArray.length; t++) {
var strippedString = taggedArray[t].slice(2, -3).toString();
strippedArray.push(strippedString);
Logger.log("The current strippedArray length is " + strippedArray.length);
}
Logger.log("The final strippedArray length is " + strippedArray.length);
Logger.log("The final taggedArray length is " + taggedArray.length);
Logger.log("The final, completed strippedArray is " + strippedArray);
}
function dataMatch() {
for (var s = 0; s < strippedArray.length;) {
for (var h = 0; h < headerArray.length;) {
if (strippedArray[s] == headerArray[h]) {
docBody.replaceText(taggedArray[s].String(), dataArray[h].String());
h=0;
s++;
} else {
h++;
}
}
}
}
tagStrip;
dataMatch;
}
It doesn't even log anything having to do with strippedArray.
It seems to be skipping over that section entirely.
Am I using the correct method of completing this task and/or is there a simpler way of doing it?
It's worth mentioning that my tags in the doc have 2 "<>" around them. That's the reason for my RegEx looking how it does.
Also, when logging the .length of taggedArray, it returns a value of 1.
You never actually call tagStrip which is supposed to work on strippedArray.
You declare it with function tagStrip(){} and later you reference the function with tagStrip; but you never actually call it. The same is happening with dataMatch.
Try calling the two functions by writing
tagStrip();
dataMatch();
If you don't include the parentheses you don't call it you just run the function Objects as statements.
Here is a portion of code I use in my add-on Simply Send, I use the same <<>> merge tags.
//copy template
var mDocDrive = doc.makeCopy(title, folder);
var mDoc = DocumentApp.openById(mDocDrive.getId());
var mDocDriveApp = DriveApp.getFileById(mDoc.getId());
var docToAttach = mDoc.getUrl();
var driveToShare = mDocDriveApp;
// replace text inside template
var body = mDoc.getBody();
body.replaceText("<<SS Title>>", title);
body.replaceText("<<timestamp>>", lastR.timestamp);
body.replaceText("<<username>>", lastR.email);
for (i in lastR.theResponses){
var cur = lastR.theResponses[i];
var name = cur.title;
name = name.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); // this will allow fields that include special characters.
var response = cur.response;
var searchPattern = "<<"+name+">>";
body.replaceText(searchPattern, response);
}
// this will replace any unused tags with nothing.
var ques = getQuestionList();
for (j in ques){
var curq = ques[j].name;
curq = curq.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
var searchPattern2 = "<<"+curq+">>";
body.replaceText(searchPattern2, "");
}
mDoc.saveAndClose();
//create pdf
if (mmDefaults.shareAs == "pdf"){
// uncomment if you want to make the pdf in the merge folder
var asPdf = mDoc.getAs('application/pdf');
asPdf.setName(mDoc.getName()+ ".pdf");
var pdf = DriveApp.createFile(asPdf);
folder.addFile(pdf);
DriveApp.removeFile(pdf);
mDocDriveApp.setTrashed(true);
var docToAttach = pdf;
driveToShare = pdf;
}
I am new to emberjs and making one simple CRUD application. I am using ember data and localstorage-adapter to save record in local storage of browser.
I am trying to update record using localstorage-adapter but it is throwing error.
I have listed my code here :
updatecontact: function(){//save data in local storage
var fname = this.obj_form_edit_data.get('cont_data.fname');
var lname = this.get('cont_data.lname');
var email = this.get('cont_data.email');
var contactno = this.get('cont_data.contactno');
var gendertype = ((this.get('isMale') == true) ? true : false);
var contactype = $(".selectpicker").val();
Grid.ModalModel.updateRecords({
fname: fname,
lname: lname,
email: email,
contactno: contactno,
gendertype: gendertype,
contactype: contactype
});
this.get('store').commit();
}
I am getting following error using above code :
Uncaught TypeError: Object function () {
if (!wasApplied) {
Class.proto(); // prepare prototype...
}
o_defineProperty(this, GUID_KEY, undefinedDescriptor);
o_defineProperty(this, '_super', undefinedDescriptor);
var m = meta(this);
m.proto = this;
if (initMixins) {
// capture locally so we can clear the closed over variable
var mixins = initMixins;
initMixins = null;
this.reopen.apply(this, mixins);
}
if (initProperties) {
// capture locally so we can clear the closed over variable
var props = initProperties;
initProperties = null;
var concatenatedProperties = this.concatenatedProperties;
for (var i = 0, l = props.length; i < l; i++) {
var properties = props[i];
Ember.assert("Ember.Object.create no longer supports mixing in other definitions, use createWithMixins instead.", !(properties instanceof Ember.Mixin));
for (var keyName in properties) {
if (!properties.hasOwnProperty(keyName)) { continue; }
var value = properties[keyName],
IS_BINDING = Ember.IS_BINDING;
if (IS_BINDING.test(keyName)) {
var bindings = m.bindings;
if (!bindings) {
bindings = m.bindings = {};
} else if (!m.hasOwnProperty('bindings')) {
bindings = m.bindings = o_create(m.bindings);
}
bindings[keyName] = value;
}
var desc = m.descs[keyName];
Ember.assert("Ember.Object.create no longer supports defining computed properties.", !(value instanceof Ember.ComputedProperty));
Ember.assert("Ember.Object.create no longer supports defining methods that call _super.", !(typeof value === 'function' && value.toString().indexOf('._super') !== -1));
if (concatenatedProperties && indexOf(concatenatedProperties, keyName) >= 0) {
var baseValue = this[keyName];
if (baseValue) {
if ('function' === typeof baseValue.concat) {
value = baseValue.concat(value);
} else {
value = Ember.makeArray(baseValue).concat(value);
}
} else {
value = Ember.makeArray(value);
}
}
if (desc) {
desc.set(this, keyName, value);
} else {
if (typeof this.setUnknownProperty === 'function' && !(keyName in this)) {
this.setUnknownProperty(keyName, value);
} else if (MANDATORY_SETTER) {
Ember.defineProperty(this, keyName, null, value); // setup mandatory setter
} else {
this[keyName] = value;
}
}
}
}
}
finishPartial(this, m);
delete m.proto;
finishChains(this);
this.init.apply(this, arguments);
} has no method 'updateRecords'
I am using following code to create new record which working fine :
savecontact: function(){//save data in local storage
var fname = this.obj_form_edit_data.get('cont_data.fname');
var lname = this.obj_form_edit_data.get('cont_data.lname');
var email = this.obj_form_edit_data.get('cont_data.email');
var contactno = this.obj_form_edit_data.get('cont_data.contactno');
var gendertype = ((this.get('isMale') == true) ? true : false);
var contactype = $(".selectpicker").text();
Grid.ModalModel.createRecord({
fname: fname,
lname: lname,
email: email,
contactno: contactno,
gendertype: gendertype,
contactype: contactype
});
this.get('store').commit();
}
You're using updateRecords as a plural, it should be updateRecord
I'm attempting to get typical properties (capacity, free space, name) from the DataStores in my VMware ESXi server. I'm having trouble getting the TraversalSpec, ObjectSpec and PropertySpecs.
Can someone please tell me what I'm doing wrong?
public void GetDataStoreValues()
{
PropertyFilterSpec spec = GetDataStoreQuery();
ObjectContent[] objectContent = _service.RetrieveProperties(_sic.propertyCollector, new[] { spec } );
foreach (ObjectContent content in objectContent)
{
if (content.obj.type == "DataStore")
{
//... get values
}
}
}
private PropertyFilterSpec GetDataStoreQuery()
{
try
{
// Traversal to get to the host from ComputeResource
TraversalSpec tSpec = new TraversalSpec
{
name = "HStoDS",
type = "HostSystem",
path = "dataStore",
skip = false
};
// Now create Object Spec
var objectSpec = new ObjectSpec
{
obj = _sic.rootFolder,
skip = true,
selectSet = new SelectionSpec[] { tSpec }
};
var objectSpecs = new[] { objectSpec };
// Create PropertyFilterSpec using the PropertySpec and ObjectPec
// created above.
// Create Property Spec
string[] propertyArray = new[] {
"summary.capacity"
,"summary.freeSpace"
,"summary.name"
};
var propertySpec = new PropertySpec
{
all = true,
pathSet = propertyArray,
type = "DataStore"
};
var propertySpecs = new[] { propertySpec };
var propertyFilterSpec = new PropertyFilterSpec
{
propSet = propertySpecs,
objectSet = objectSpecs
};
return propertyFilterSpec;
}
catch (Exception)
{
}
return null;
}
Also, are object type names case sensitive? I seem to see all sorts of cases when I look at samples.
Thanks for any suggestions.
First question: You can use the following code to get properties of DataStore. I tested this code on vCenter 5.1
public void Test()
{
var properties = GetProperties(
new ManagedObjectReference { type = "Datastore", Value = "<your_datastore_key>" },
new[] {"summary.capacity", "summary.freeSpace", "summary.name"});
}
private List<DynamicProperty> GetProperties(ManagedObjectReference objectRef, string[] properties)
{
var typesAndProperties = new Dictionary<string, string[]> { { objectRef.type, properties } };
var objectContents = RetrieveResults(typesAndProperties, new List<ManagedObjectReference> { objectRef });
return ExtractDynamicProperties(objectRef, objectContents);
}
private List<ObjectContent> RetrieveResults(Dictionary<string, string[]> typesAndProperties, List<ManagedObjectReference> objectReferences)
{
var result = new List<ObjectContent>();
var tSpec = new TraversalSpec { path = "view", skip = false };
var oSpec = new ObjectSpec { skip = true, selectSet = new SelectionSpec[] { tSpec } };
oSpec.obj = service.CreateListView(serviceContent.viewManager, objectReferences.ToArray());
tSpec.type = "ListView";
var fSpec = new PropertyFilterSpec
{
objectSet = new[] { oSpec },
propSet = typesAndProperties.Keys.Select(typeName => new PropertySpec { type = typeName, pathSet = typesAndProperties[typeName] }).ToArray()
};
PropertyFilterSpec[] pfs = { fSpec };
var retrieveResult = service.RetrievePropertiesEx(serviceContent.propertyCollector, pfs, new RetrieveOptions());
if (retrieveResult != null)
{
result.AddRange(retrieveResult.objects);
while (!String.IsNullOrEmpty(retrieveResult.token))
{
retrieveResult = service.ContinueRetrievePropertiesEx(serviceContent.propertyCollector, retrieveResult.token);
result.AddRange(retrieveResult.objects);
}
service.DestroyView(oSpec.obj);
}
return result;
}
private static List<DynamicProperty> ExtractDynamicProperties(ManagedObjectReference objectRef, IEnumerable<ObjectContent> objectContents)
{
var result = new List<DynamicProperty>();
foreach (var objectContent in objectContents)
{
if (objectContent.propSet == null) continue;
if (objectContent.obj == null) continue;
if (objectContent.obj.type != objectRef.type || objectContent.obj.Value != objectRef.Value) continue;
result.AddRange(objectContent.propSet);
}
return result;
}
How to run the sample:
Initialize the service by object of VimService class and the serviceContent by object of ServiceContent class.
Login to vCenter or ESX using service.
Replace <your_datastore_key> with Key of your datastore. You can use the Managed Object Browser to find keys of their datastores. To get a description of datastore object, go to following links in MOB: content -> rootFolder -> childEntity -> datastoreFolder -> childEntity. Value of "Managed Object ID" on top of page is correct Key (like datastore-46).
Second question: Yes, the type of ManagedObjectReference is case sensitive.