Google.Cloud.RecaptchaEnterprise error on CreateAssessment() - "Request contains an invalid argument" - google-cloud-platform

I'm trying to use the Google.Cloud.RecaptchaEnterprise library to validate captcha requests for the new enterprise key my client has obtained.
string _siteKey = ConfigurationManager.AppSettings["GoogleCaptcha.CheckboxCaptcha.SiteKey"];
string _apiKey = ConfigurationManager.AppSettings["GoogleCaptcha.ApiKey"];
string _projectId = ConfigurationManager.AppSettings["GoogleCaptcha.ProjectId"];
string recaptchaAction = "CreateAccountAssessment";
try {
var appPath = System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath;
string credential_path = appPath + "googlecredentials.json";
System.Environment.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS", credential_path);
RecaptchaEnterpriseServiceClient client =
RecaptchaEnterpriseServiceClient.Create();
CreateAssessmentRequest createAssessmentRequest = new CreateAssessmentRequest()
{
Assessment = new Assessment()
{
Event = new Event()
{
SiteKey = _siteKey,
Token = formResponse,
ExpectedAction = "Create_Account"
},
Name = recaptchaAction,
},
Parent = _projectId
};
Assessment response = client.CreateAssessment(createAssessmentRequest);
if (response.TokenProperties.Valid == false)
{
Sitecore.Diagnostics.Log.Error("The CreateAssessment() call failed " +
"because the token was invalid for the following reason: " +
response.TokenProperties.InvalidReason.ToString(), this);
return "Invalid captcha.";
}
else
{
if (response.Event.ExpectedAction == recaptchaAction)
{
Sitecore.Diagnostics.Log.Error("The reCAPTCHA score for this token is: " +
response.RiskAnalysis.Score.ToString(), this);
return "";
}
else
{
Sitecore.Diagnostics.Log.Error("The action attribute in your reCAPTCHA " +
"tag does not match the action you are expecting to score", this);
return "Invalid captcha.";
}
}
}
catch (Exception ex)
{
Sitecore.Diagnostics.Log.Error("Error validating captcha on " + _url + "; " + ex.Message, this);
return "Unable to connect to captcha service.";
}
As far as I can tell all my properties are correct, but it throws an error on Assessment response = client.CreateAssessment(createAssessmentRequest);:
Status(StatusCode="InvalidArgument", Detail="Request contains an invalid argument.", DebugException="Grpc.Core.Internal.CoreErrorDetailException: {"created":"#1621287236.280000000","description":"Error received from peer ipv6:[2607:f8b0:4006:81a::200a]:443","file":"T:\src\github\grpc\workspace_csharp_ext_windows_x64\src\core\lib\surface\call.cc","file_line":1062,"grpc_message":"Request contains an invalid argument.","grpc_status":3}")

I strongly suspect the problem (or at least a problem) is the Parent property of the request.
From the documentation:
The name of the project in which the assessment will be created, in the format "projects/{project}".
... whereas I suspect your project ID is just the ID, rather than the resource name starting with "projects/".
I would recommend using the generated resource name classes as far as possible, with the corresponding properties. So in this case, you'd have:
CreateAssessmentRequest createAssessmentRequest = new CreateAssessmentRequest
{
Assessment = new Assessment
{
Event = new Event
{
SiteKey = _siteKey,
Token = formResponse,
ExpectedAction = "Create_Account"
},
Name = recaptchaAction,
},
ParentAsProjectName = new ProjectName(_projectId)
};

Related

Facebook graph API me endpoint errors out the first time and successful the next time

I am using facebook login in my coldfusion application. I went through all the steps to get access_token. I am making cfhttp call to "/me" endpoint with access_token and fields parameters and getting "I/O Exception: peer not authenticated" error in the response/Errordetail. I made the same cfhttp call again and able to get successful response of id and name mentioned in fields parameters.
I am expecting the successful response in the first call but have to call twice, so the first call errors out and second one succeeds.
Any help on how to debug or find the issue with the first call. so i should be making one call and get a successful response of current user's information.
i should be making one call and get a successful response of current user's information
<cfscript>
if (code EQ "") {
cfoauth(type = 'facebook', clientid = appId, secretkey = appSecret, result = "res", scope = "public_profile, email", redirecturi = redirectUri);
}
if (code NEQ "") { // code is a parameter I get from url redirect after cfoauth response
try {
cfhttp(method = "GET", charset = "utf-8", url = "https://graph.facebook.com/v15.0/oauth/access_token", result = "fbcoderesponse") {
cfhttpparam(name = "code", type = "url", value = code);
cfhttpparam(name = "client_id", type = "url", value = appId);
cfhttpparam(name = "client_secret", type = "url", value = appSecret);
cfhttpparam(name = "redirect_uri", type = "url", value = redirectUri);
}
dresponse = deserializeJSON(fbcoderesponse.filecontent);
accessToken = dresponse.access_token;
writedump(accessToken);
accessTokenurl = "https://graph.facebook.com/v15.0/me?fields=id,name&access_token=" & accessToken;
writedump(accessTokenurl);
} catch (any e) {
writeoutput(e);
}
if (accessToken NEQ "") {
try {
cfhttp(method = "GET", charset = "utf-8", url = accessTokenurl, result = "fbaccesstokenresponse”){}
writedump(fbaccesstokenresponse);
if (fbaccesstokenresponse.errordetail != "") {
cfhttp(method = "GET", charset = "utf-8", url = accessTokenurl, result = "fbaccesstokenresponse1");
writeoutput("fbaccesstokenresponse1 response");
writedump(fbaccesstokenresponse1);
}
} catch (any e) {
writeoutput("exception of daccesstokenresponse");
writedump(e);
}
} else {
writeoutput("accesstoken is empty");
}
}
</cfscript>

Spring WebFlux project that connects to ElasticSearch Unit Testing

I am currently working on a Spring WebFlux project that connects to ElasticSearch. I have a Rest Service that in turn calls a method in the Service Layer that connects to the ES. I am having trouble writing UnitTests for my Service Layer. Any help would be appreciated as this is the first time I am working with Reactive Programming. Below are the code snippets for my Controller and Service methods.
Controller Code :
#GetMapping(path = "/api/apis/services/{id}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
Flux<ClassA> serviceApis(#PathVariable final String serviceKey) {
return apiService.getDataForService(serviceKey);
}
Service Layer :
#PreAuthorize("isFullyAuthenticated()")
public Flux<ClassA> getDataForService(
final String id) {
IdentityToken token = GSLSecurityContext.getCurrentUserIdentityToken();
if (token == null) {
return Flux.error(new Exception("No token found"));
}
String securityQueryJson = getSecurityShould(token);
String queryToRun = QUERY
.replace("XXX_SIZE_XXX", config.getValueAsString("scroll.size"))
.replace("XXX_SECURITY_SHOULD_XXX", securityQueryJson)
.replace("XXX_SERVICE_KEY_XXX", id);
WebClient client = ClientUtil.getDataLakeWebClient(config);
Flux<ClassA> response = getData(client, queryToRun);
return response;
}
The getData code is as below :
protected Flux<ClassA> getData(
final WebClient client,
final String queryToRun) {
String scrollTimeoutQuery = "?scroll=" + config.getValueAsString("scroll.timeout");
long timeout = config.getValueAsLong("query.timout");
return Flux.generate(
() -> null,
(scrollId, sink) -> {
ClassAWrapper lastWrapper = null;
if (scrollId == null) {
Mono<ClassAWrapper> wrapper = client.post()
.uri(getSearchURI() + scrollTimeoutQuery)
.body(BodyInserters.fromObject(queryToRun)).retrieve()
.bodyToMono(ClassAWrapper.class)
.onErrorMap(original -> new Exception("Unable to retrieve from elastic search for query " + queryToRun, original))
.log();
try {
lastWrapper = wrapper.block(Duration.ofSeconds(timeout));
} catch (IllegalStateException ex) {
LOG.error("Timedout after " + timeout + " seconds while getting data from elastic search for query " + queryToRun);
lastWrapper = null;
} catch (Exception ex) {
LOG.error("Error in getting message details",ex);
lastWrapper = null;
}
} else {
String scrollQuery = "{\"scroll\" : \"" + config.getValueAsString("scroll.timeout") + "\", \"scroll_id\" : \"" + scrollId + "\"}";
Mono<ClassAWrapper> wrapper = client.post()
.uri("_search/scroll")
.body(BodyInserters.fromObject(scrollQuery)).retrieve()
.bodyToMono(ClassAWrapper.class)
.onErrorMap(original -> new Exception("Unable to retrieve next page of data from elastic search", original))
.log();
try {
lastWrapper = wrapper.block(Duration.ofSeconds(timeout));
} catch (IllegalStateException ex) {
LOG.error("Timeout after " + timeout + " seconds while getting data from elastic search for query " + queryToRun);
lastWrapper = null;
} catch (Exception ex) {
LOG.error("Error in getting message details",ex);
lastWrapper = null;
}
}
if (lastWrapper == null || lastWrapper.getResult() == null || lastWrapper.getResult().getDetails().isEmpty()) {
sink.next(new ClassA());
sink.complete();
return null;
}
sink.next(lastWrapper.getResult());
return lastWrapper.getScrollId();
}
);
}
Here, queryToRun is the ES query to be executed. config is the configuration. I need to test the method "getDataForService()".

Vimeo API C# - Uploading a video

I'm following the api's guide about resumable uploads.
I managed to get a response after step 1 ("create the video"),
with a uri and a upload_link.
About the second part, things are not as clear.
It only says which headers should I sent, but there are two things I don't get,
first - where do I need to put the "upload_link"?
Should the call be like this:
/me/{upload_link}? (of course im also adding the access token, etc)
second, what about the actual file? I guess i should send it in the same method, but how? No word about it.
This is the code for the PATCH request:
public string UploadPatch(
string uploadlink,
string method)
{
var headers = new WebHeaderCollection()
{
{ "Tus-Resumable", "1.0.0" },
{ "Upload-Offest", "0" }
};
method = method.ToUpper();
string body = "";
string contentType = "application/offset+octet-stream";
return Helpers.HTTPUpload(uploadlink, method, headers, body, contentType);
}
And HTTPUpload():
public static string HTTPPatch(string url, string method,
WebHeaderCollection headers, string payload,
string contentType)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.CreateHttp(url);
if (Proxy != null) request.Proxy = Proxy;
request.Headers = headers;
request.Method = method;
request.Accept = "application/vnd.vimeo.*+json; version=3.1";
request.ContentType = contentType;
request.KeepAlive = false;
if (!String.IsNullOrWhiteSpace(payload))
{
var streamBytes = Helpers.ToByteArray(payload);
request.ContentLength = streamBytes.Length;
Stream reqStream = request.GetRequestStream();
reqStream.Write(streamBytes, 0, streamBytes.Length);
reqStream.Close();
}
HttpWebResponse response = (HttpWebResponse)(request.GetResponse());
Debug.WriteLine(((HttpWebResponse)response).StatusDescription);
var dataStream = response.GetResponseStream();
StreamReader reader = new StreamReader(dataStream);
string responseFromServer = reader.ReadToEnd();
reader.Close();
dataStream.Close();
response.Close();
Debug.WriteLine(String.Format("Response from URL {0}:", url), "HTTPFetch");
Debug.WriteLine(responseFromServer, "HTTPFetch");
return responseFromServer;
}
Thanks
The upload_link is the URL where you upload the video to. In other words, make your call to the https://[...].cloud.vimeo.com/upload?[...] URL instead of the https://api.vimeo.com host that is used for other API requests.
Additionally, when you make a request to that cloud.vimeo.com upload_link, only provide the required headers as specified in the documentation.
https://developer.vimeo.com/api/upload/videos#resumable-approach
The code is VB.Net, but you can change to C#
'Imports / use these classes
'Imports System.Net
'Imports Newtonsoft.Json
'Imports System.IO
Protected Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Try
'Receive the video from File Upload
If Not IsNothing(fuVideo.PostedFile) Then
'You will need this for SSL
System.Net.ServicePointManager.SecurityProtocol = (SecurityProtocolType.Tls Or (SecurityProtocolType.Tls11 Or SecurityProtocolType.Tls12))
'Path to save the video Save
Dim vFilePath As String = Server.MapPath("App_data/Videos")
Dim vFileNameAndPath As String = vFilePath & "/" & fuVideo.PostedFile.FileName
'Save Video
fuVideo.PostedFile.SaveAs(vFileNameAndPath)
'Get the size
Dim vSize As String = New FileInfo(vFileNameAndPath).Length()
'Vimeo URL
Dim vVimeURL As String = "https://api.vimeo.com/me/videos"
Dim wc As WebClient = New WebClient()
wc.Headers.Clear()
wc.Headers.Add("Authorization", "bearer XXXXXXXXXXXXXXXXX") 'Use your App Code
wc.Headers.Add("Content-Type", "application/json")
wc.Headers.Add("Accept", "application/vnd.vimeo.*+json;version=3.4")
wc.Encoding = System.Text.Encoding.UTF8
'txtName is a text box, so you can give a Title to the Video
Dim vData As String = "{ ""upload"": {""approach"": ""tus"",""size"": """ & vSize & """ }, ""name"" : """ & txtName.Text & """ }"
Dim vimeoTicket = JsonConvert.DeserializeObject(wc.UploadString(vVimeURL, "POST", vData))
wc.Headers.Clear()
wc.Headers.Add("Content-Type", "application/offset+octet-stream")
wc.Headers.Add("Accept", "application/vnd.vimeo.*+json;version=3.4")
wc.Headers.Add("Tus-Resumable", "1.0.0")
wc.Headers.Add("Upload-Offset", "0")
Dim vupload_link As String = vimeoTicket("upload")("upload_link").Value 'Json from Vimeo has the upload_link
Dim vResponse As Byte() = wc.UploadFile(vupload_link, "PATCH", vFileNameAndPath)
Response.Write(System.Text.Encoding.Unicode.GetString(vResponse)) ' If everething is ok, vResponse is Nothing
End If
Catch ex As Exception
ltrErro.Text = "Error"
End Try
End Sub
for this may look at the sample code below:-
I am using a nuget library vimeo-dot-net also at https://github.com/mfilippov/vimeo-dot-net, this has a wrapper built around upload, delete etc.
public ActionResult UploadChapterVideoVimeo(HttpPostedFileBase file, string productID = "")
{
if (file != null){
var authCheck = Task.Run(async () => await vimeoClient.GetAccountInformationAsync()).Result;
if (authCheck.Name != null)
{
BinaryContent binaryContent = new BinaryContent(file.InputStream, file.ContentType);
int chunkSize = 0;
int contenetLength = file.ContentLength;
int temp1 = contenetLength / 1024;
if (temp1 > 1)
{
chunkSize = temp1 / 1024;
chunkSize = chunkSize * 1048576;
}
else
{ chunkSize = chunkSize * 1048576; }
binaryContent.OriginalFileName = file.FileName;
var d = Task.Run(async () => await vimeoClient.UploadEntireFileAsync(binaryContent, chunkSize, null)).Result;
vmodel.chapter_vimeo_url = "VIMEO-" + d.ClipUri;
}
return RedirectToAction("ProductBuilder", "Products", new { productId = EncryptedProductID, message = "Successfully Uploaded video", type = 1 });
}
}
catch (Exception exc)
{
return RedirectToAction("ProductBuilder", "Products", new { productId = EncryptedProductID, message = "Failed to Uploaded video " + exc.Message, type = 0 });
}
}
return null; }

Get Command from Action call

As part of the Sitecore workflow, how can I get the command name that executed the action? For example,
I have 3 states: Accept, Draft, Review and the Draft and Review both have a custom Email Action that should look at a different dictionary item depending on command that executed (Save or Submit in the drafting state and Approve or Reject in the review state). I would like to use the current workflow state and the command to determine which dictionary item to pull, how can I do that? Here is the function that I'm using.
public void Process(WorkflowPipelineArgs args)
{
Assert.ArgumentNotNull(args, "args");
var processorItem = args.ProcessorItem;
if (processorItem == null)
{
return;
}
var currentItem = args.DataItem;
var innerItem = processorItem.InnerItem;
var fullPath = innerItem.Paths.FullPath;
var recipient = currentItem.Fields["Primary Email"].Value;
var candidateName = currentItem.Fields["Candidate Name"].Value;
var formName = currentItem.Name;
if (string.IsNullOrEmpty(recipient)) return;
var from = GetText(innerItem, "from", args);
var mailServer = GetText(innerItem, "mail server", args);
var currentWorkflowState = currentItem.Fields[FieldIDs.WorkflowState].Value;
var subject = string.Format(Translate.Text("cb-candidate-submission-subject"), formName);
var message = string.Format(Translate.Text("cb-candidate-submission-body"), candidateName, formName);
Error.Assert(#from.Length > 0, "The 'From' field is not specified in the mail action item: " + fullPath);
Error.Assert(subject.Length > 0,
"The 'Subject' field is not specified in the mail action item: " + fullPath);
Error.Assert(mailServer.Length > 0,
"The 'Mail server' field is not specified in the mail action item: " + fullPath);
var mailMessage = new MailMessage();
mailMessage.To.Add(recipient);
mailMessage.From = new MailAddress(#from);
mailMessage.Subject = subject;
mailMessage.Body = message;
var client = new SmtpClient(mailServer) { EnableSsl = false };
try
{
client.Send(mailMessage);
}
catch (Exception ex)
{
Log.Error("EmailExAction Threw An Exception", ex, this);
}
}
WorkflowPipeleneArgs have public properties: ID NextStateId and WorkflowState PreviousState, Item CommandItem. You can use them to define item state.
WorkflowPipelineArgs have CommandItem , this Item have current state and current command details.
var currentCommandName = arg.CommandItem.Name;

Salesforce Webservice Error

I am receiving the following error from a class that invokes a webservice.
"You have uncommitte​d work pending. Please commit or rollback before calling out"
Here is the class that is calling the webservice:
global class myWS
{
WebService static string invokeExternalWs(string childValue, string parentValue)
{
HttpRequest req = new HttpRequest();
req.setEndpoint('https://externalURL/Services');
req.setMethod('POST');
req.setHeader('Content-Type', 'text/xml; charset=utf-8');
req.setHeader('SOAPAction', 'http://externalService/externalMethod');
string b = '--soap request goes here--';
req.setBody(b);
Http http = new Http();
try {
//Execute web service call here
String xObjectID ='';
HTTPResponse res = http.send(req);
Dom.Document doc = res.getBodyDocument();
String soapNS = 'http://schemas.xmlsoap.org/soap/envelope/';
Dom.XmlNode root = doc.getRootElement();
for(dom.XmlNode node1 : root.getChildElements()) {
for(dom.XmlNode node2 : node1.getChildElements()) {
for(dom.XmlNode node3 : node2.getChildElements()) {
for(dom.XmlNode node4 : node3.getChildElements()) {
xObjectID = node4.getText();
}
}
}
}
return xObjectID;
} catch(System.CalloutException e){
return 'ERROR:' + e;
}
}
}
UPDATE: Here is my class that is executing myWS
public void applyURLString(ID ArgBuildID) {
Builder__c current_build = [SELECT id, name, LLURL__c, column1, column2, Opportunity__c
FROM Builder__c
WHERE id = :ArgBuildID];
if(current_build.LLURL__c == null || current_build.LLURL__c.trim().length() == 0)
{
String tmpFolderName = current_build.column1 + ' - ' + current_build.column2;
String LLWSResultPattern = '[0-9]{2,}';
String myWSXMLResult = myWS.invokeExternalWs(tmpFolderName,'test');
Boolean LLWSPatternMatched = pattern.matches(LLWSResultPattern,myWSXMLResult);
if(LLWSPatternMatched)
{
Opportunity oppt = [SELECT Id,Name
FROM Opportunity
WHERE Id = :current_build.Opportunity__c
LIMIT 1];
oppt.LLURL__c = 'https://someService/' + myWSXMLResult;
update oppt;
}
}
}
UPDATE #2 - Here is where applyURLString() is executed. This is the only place that DML is executed prior to my HTTP request. Yet I need the ID of the new Builder record.
Builder__c insertBuild = new Builder__c();
insertBuild.Opportunity__c = opportunityId;
insertBuild.Product_Group__c = selectedBuild.Product_Group__c;
insertBuild.Manual_Build_Product__c = selectedBuild.Manual_Build_Product__c;
insert insertBuild;
applyURLString(insertBuild.Id);
Any ideas why this error would occur?
#JCD's suggestion to use an #future annotation solved my problem. Thanks again!