How to implement Recaptcha V3 for Kentico? - kentico

We are going to apply the Recaptcha V3 for our sites. But Kentico is supporting the V2 only.
So are there any documents or guides to do it?
Or should we keep using the V2?
Thanks,
Duc Huynh

I resolved it by building a custom code to render the V3 Captcha.
Then I will check the reCaptcha Code before save the form.

Here is the Steps:
Create a Class > Function for Validate ReCaptcha - see attached code;
Call the Function Validate in this Event: viewBiz_OnBeforeSave once submitting a form;
If Valid then Store the info
You can use it via Ajax or Submit Directly.
public static GooogleRecaptchaResponse ValidateGgRecaptchaToken(string responseToken, Action InvalidHandler) {
if (string.IsNullOrEmpty(responseToken)) {
EventLogProvider.LogInformation("ValidateGgRecaptchaToken", "Invalid", "Recaptcha was empty");
InvalidHandler?.Invoke();
return null;
}
string secretKey = SettingsKeyInfoProvider.GetValue(WebUtils.CaptchaSecretKeyName);
var request = (HttpWebRequest) WebRequest.Create("https://www.google.com/recaptcha/api/siteverify");
var postData = "response=" + responseToken;
postData += "&secret=" + secretKey;
var data = Encoding.ASCII.GetBytes(postData);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = data.Length;
using(var stream = request.GetRequestStream()) {
stream.Write(data, 0, data.Length);
}
var response = (HttpWebResponse) request.GetResponse();
var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
var res = JsonConvert.DeserializeObject < GooogleRecaptchaResponse > (responseString);
if (res == null || !res.success || res.score < 0.5) {
EventLogProvider.LogInformation("ValidateGgRecaptchaToken", "Invalid", JsonConvert.SerializeObject(res));
InvalidHandler?.Invoke();
}
return res;
}

Related

Create Folder and Update Title and Custom Field in Sharepoint Online

I try to create folder in sharepoint online, based on some of tutorial. the problem comes since creating folder is not given "Title" column value.
I want to create folder and also update column "Title".
here is the code for create folder
public string CreateDocumentLibrary(string siteUrl, string relativePath)
{
//bool responseResult = false;
string resultUpdate = string.Empty;
string responseResult = string.Empty;
if (siteUrl != _siteUrl)
{
_siteUrl = siteUrl;
Uri spSite = new Uri(siteUrl);
_spo = SpoAuthUtility.Create(spSite, _username, WebUtility.HtmlEncode(_password), false);
}
string odataQuery = "_api/web/folders";
byte[] content = ASCIIEncoding.ASCII.GetBytes(#"{ '__metadata': { 'type': 'SP.Folder' }, 'ServerRelativeUrl': '" + relativePath + "'}");
string digest = _spo.GetRequestDigest();
Uri url = new Uri(String.Format("{0}/{1}", _spo.SiteUrl, odataQuery));
// Set X-RequestDigest
var webRequest = (HttpWebRequest)HttpWebRequest.Create(url);
webRequest.Headers.Add("X-RequestDigest", digest);
// Send a json odata request to SPO rest services to fetch all list items for the list.
byte[] result = HttpHelper.SendODataJsonRequest(
url,
"POST", // reading data from SP through the rest api usually uses the GET verb
content,
webRequest,
_spo // pass in the helper object that allows us to make authenticated calls to SPO rest services
);
string response = Encoding.UTF8.GetString(result, 0, result.Length);
if (response != null)
{
//responseResult = true;
responseResult = response;
}
return responseResult;
}
I already tried to use CAML, but, the problem is, the list of sharepoint is big, so got the error prohibited access related to limit tresshold.
Please help.
Refer below code to update folder name.
function renameFolder(webUrl,listTitle,itemId,name)
{
var itemUrl = webUrl + "/_api/Web/Lists/GetByTitle('" + listTitle + "')/Items(" + itemId + ")";
var itemPayload = {};
itemPayload['__metadata'] = {'type': getItemTypeForListName(listTitle)};
itemPayload['Title'] = name;
itemPayload['FileLeafRef'] = name;
var additionalHeaders = {};
additionalHeaders["X-HTTP-Method"] = "MERGE";
additionalHeaders["If-Match"] = "*";
return executeJson(itemUrl,"POST",additionalHeaders,itemPayload);
}
function getItemTypeForListName(name) {
return"SP.Data." + name.charAt(0).toUpperCase() + name.slice(1) + "ListItem";
}

How to change the default values when add link Sharepoint 2013

In Add Link page, is it possible to change the default values like title, address, show these links to, by using URL parameters?
According to this, it seems possible in sharepoint2010. Does anyone know whether it works in 2013??
If not, is it possible to add a link by post REST API??
This problem can be solved by the steps below.
Add a custom action. Just follow the steps here.
In my case code is as below
SP.SOD.executeFunc("callout.js", "Callout", function() {
var itemCtx = {};
itemCtx.Templates = {};
itemCtx.BaseViewID = 'Callout';
// Define the list template type
itemCtx.ListTemplateType = 101;
itemCtx.Templates.Footer = function(itemCtx) {
// context, custom action function, show the ECB menu (boolean)
return CalloutRenderFooterTemplate(itemCtx, AddCustomAction, true);
};
SPClientTemplates.TemplateManager.RegisterTemplateOverrides(itemCtx);
});
function AddCustomAction(renderCtx, calloutActionMenu) {
// Add your custom action
calloutActionMenu.addAction(new CalloutAction({
text: "FAVORITE",
// tooltip: 'This is your custom action',
onClickCallback: function() {
CreateCustomNewQuickLink(renderCtx.CurrentItem.FileLeafRef, renderCtx.CurrentItem.FileRef);
}
}));
// Show the default document library actions
CalloutOnPostRenderTemplate(renderCtx, calloutActionMenu);
}
function CreateCustomNewQuickLink(title, url) {
var urlAddress = $(location).attr('protocol') + "//" + $(location).attr('host') + '/_Layouts/quicklinksdialogformTEST.aspx?Mode=Link' +
'&title=' + encodeURIComponent(title) +
'&url=' + encodeURIComponent(url);
ShowNewQuicklinkPopup(urlAddress, PageRefreshOnDialogClose);
}
Create a new add link page which is copied from "quicklinksdialogform.aspx". I add some javascript as below.
$(init)
function init() {
var args = new Object();
args = GetUrlParms();
if (args["title"] != undefined) {
$(".ms-long")[0].value = decodeURIComponent(args["title"]);
}
if (args["url"] != undefined) {
$(".ms-long")[1].value = decodeURIComponent(args["url"]);
}
}
function GetUrlParms() {
var args = new Object();
var query = location.search.substring(1);
var pairs = query.split("&");
for (var i = 0; i < pairs.length; i++) {
var pos = pairs[i].indexOf('=');
if (pos == -1) continue;
var argname = pairs[i].substring(0, pos);
var value = pairs[i].substring(pos + 1);
args[argname] = unescape(value);
}
return args;
}
It works like below

Making HTTPS call in C# with the BouncyCastle library

Using C# 4.0, I need to make HTTPS call with the BouncyCastle library (Short story : Windows XP + TLS 1.2).
When using the following code, I get a "HTTP Error 400. The request verb is invalid."
Here is my code :
using (var client = new TcpClient("serverName", 443))
{
var sr = new SecureRandom();
var cl = new MyTlsClient();
var protocol = new TlsClientProtocol(client.GetStream(), sr);
protocol.Connect(new MyTlsClient());
using (var stream = protocol.Stream)
{
var hdr = new StringBuilder();
hdr.AppendLine("GET /Url/WebService.asmx?wsdl HTTP/1.1");
hdr.AppendLine("Host: serverName");
hdr.AppendLine("Content-Type: text/xml; charset=utf-8");
hdr.AppendLine("Connection: close");
hdr.AppendLine();
var dataToSend = Encoding.ASCII.GetBytes(hdr.ToString());
sr.NextBytes(dataToSend);
stream.Write(dataToSend, 0, dataToSend.Length);
int totalRead = 0;
string response = "";
byte[] buff = new byte[1000];
do
{
totalRead = stream.Read(buff, 0, buff.Length);
response += Encoding.ASCII.GetString(buff, 0, totalRead);
} while (totalRead == buff.Length);
}
}
class MyTlsClient : DefaultTlsClient
{
public override TlsAuthentication GetAuthentication()
{
return new MyTlsAuthentication();
}
}
class MyTlsAuthentication : TlsAuthentication
{
public TlsCredentials GetClientCredentials(CertificateRequest certificateRequest) { return null; }
public void NotifyServerCertificate(Certificate serverCertificate) { }
}
What I've already done :
Using WireShark to decrypt the ssl stream and inspect the request send => I've never succeeded to decrypt ssl stream
Using fiddler to decrypt the https stream => No detection by fiddler so I suspect something might be badly encrypted
Any ideas ?
Thanks to PeterDettman who gave me the solution :
I must not use the sr.NextBytes(instructions), so the code becomes :
using (var client = new TcpClient("serverName", 443))
{
var sr = new SecureRandom();
var cl = new MyTlsClient();
var protocol = new TlsClientProtocol(client.GetStream(), sr);
protocol.Connect(new MyTlsClient());
using (var stream = protocol.Stream)
{
var hdr = new StringBuilder();
hdr.AppendLine("GET /Url/WebService.asmx?wsdl HTTP/1.1");
hdr.AppendLine("Host: serverName");
hdr.AppendLine("Content-Type: text/xml; charset=utf-8");
hdr.AppendLine("Connection: close");
hdr.AppendLine();
var dataToSend = Encoding.ASCII.GetBytes(hdr.ToString());
stream.Write(dataToSend, 0, dataToSend.Length);
int totalRead = 0;
string response = "";
byte[] buff = new byte[1000];
do
{
totalRead = stream.Read(buff, 0, buff.Length);
response += Encoding.ASCII.GetString(buff, 0, totalRead);
} while (totalRead == buff.Length);
}
}

Microsoft Face Detect API code example Bad Request

I have been trying to solve this bad request error. I am able to make the request call and Azure reports total calls correctly and also reports total errors.
I can not get this code example to work; however if I send this via their online console all is fine:
static async void MakeRequest()
{
string key1 = "YourKey"; // azure the one should work
string data = "https://pbs.twimg.com/profile_images/476054279438868480/vvv5YG0Q.jpeg";
var client = new HttpClient();
var queryString = HttpUtility.ParseQueryString(string.Empty);
// Request parameters
queryString["returnFaceId"] = "true";
// Request headers
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", key1);
Console.Beep();
var uri = "https://westus.api.cognitive.microsoft.com/face/v1.0/detect?" + queryString;
//string statusURL = HttpContext.Current.Request.Url.Host;
//console.WriteLine("Your Status URL address is :" + statusURL);
HttpResponseMessage response;
// Request body
// byte[] byteData = Encoding.UTF8.GetBytes("{url: https://pbs.twimg.com/profile_images/476054279438868480/vvv5YG0Q.jpeg}");
byte[] byteData = Encoding.UTF8.
GetBytes("{"+ "url"+":"+"https://pbs.twimg.com/profile_images/476054279438868480/vvv5YG0Q.jpeg" + "}");
using (var content = new ByteArrayContent(byteData))
{
content.Headers.ContentType =
new MediaTypeHeaderValue("application/json");
response = await client.PostAsync(uri, content);
}
HttpRequestMessage request =
new HttpRequestMessage(HttpMethod.Post, uri);
request.Content = new StringContent("{body}",
Encoding.UTF8,
"application/json");
//CONTENT-TYPE header
await client.SendAsync(request)
.ContinueWith(responseTask =>
{
Console.WriteLine("Response: {0}", responseTask.Result);
Console.WriteLine("-----------------------------------");
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine("End of Post return from MS");
Console.WriteLine("Hit ENTER to exit...");
Console.ReadKey();
});
}// end of Make request
Your JSON is malformed. Your fields and non-scalar fields must be quoted. You also have some unnecessary code. Here's code that works:
static async void MakeRequest()
{
string key1 = "YourKey"; // azure the one should work
string imageUri = "https://pbs.twimg.com/profile_images/476054279438868480/vvv5YG0Q.jpeg";
var client = new HttpClient();
var queryString = HttpUtility.ParseQueryString(string.Empty);
// Request parameters
queryString["returnFaceId"] = "true";
// Request headers
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", key1);
var uri = "https://westus.api.cognitive.microsoft.com/face/v1.0/detect?" + queryString;
string body = "{\"url\":\"" + imageUri + "\"}";
using (var content = new StringContent(body, Encoding.UTF8, "application/json"))
{
await client.PostAsync(uri, content)
.ContinueWith(async responseTask =>
{
var responseBody = await responseTask.Result.Content.ReadAsStringAsync();
Console.WriteLine("Response: {0}", responseBody);
Console.WriteLine("-----------------------------------");
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine("End of Post return from MS");
Console.WriteLine("Hit ENTER to exit...");
Console.ReadKey();
});
}
}// end of Make request
If you're using Visual Studio, I would recommend the NuGet package as this will handle much of the mundane details for you, including C# types for responses.

Need Help: Account Name on Contact Phone Call

I am new to CRM and have been able to figure out everything up to now. I have read so many post and internet post and tried them. I have watched some many videos. It seems it should be easy. The contact record has the ParentCustomerID, and ParentCustomerName that holds the account if there is one associated. Now I am just totally confused on the required steps.
Requirement: - I need Account Name to be displayed on the contact level phone call form and saved in phone call table so that it can be visible in the phone call view.
I have in Phone Call N:1 Relationship field str_companyid (lookup) primary Entity is Account with Referential behavior.
I tried a Phone Call N:1 Relationship field new_companystring (lookup) primary Entity is Contact with Referential behavior. I came to the conclusion that this is not a valid approach. Let me know if incorrect.
Do I need a N:N instead?
I have added the str_companyid field to the form. I went to the "Create a phone call for a contact" workflow process. On the "Create PhoneCall" step I have added the dynamic field {Company(Contact)}. After save and publishes; I created a phone call and it isn't populated.
I have tried different Web Resource JS. I have added the JS in the onload of the form properties.
Why doesn't something as easy as this work? I can't seem to get the retrieveRecord to work. I have also tried the xmlHttpObject object but it returns 0.
Can someone help assist me on what I am missing? What are the complete steps to accomplish this?
![I have screenshots below and the code I was running][1]
function PopulateCompanyName()
{
//get group GUID
if (Xrm.Page.getAttribute("to").getValue()[0].id != null) {
var lookup = Xrm.Page.getAttribute("to").getValue();
alert(lookup[0].id);
alert(lookup[0].typename);
alert(lookup[0].name);
alert(lookup);
SDK.JQuery.retrieveRecord(lookup[0].id,
lookup[0].typename,
"ParentCustomerID",
null,
function (lookup) {
Xrm.Page.getAttribute("Company").setValue(lookup[0].str_companyid);
});
}
else {
Xrm.Page.getAttribute("str_companyid").setValue(null);
}
}
function GetCompany()
///Get lookup ID
{
alert("I am Here");
var lookupfield = Xrm.Page.getAttribute("to").getValue();
if (lookupfield != null && lookupfield [0] != null)
{
var householdlookupvalue = lookupfield [0].id;
}
else
{
var householdlookupvalue = " ";
}
alert("I am here2");
alert(householdlookupvalue);
}
// Prepare variables for a contact to retrieve.
var authenticationHeader = Xrm.Page.context.getAuthenticationHeader();
// Prepare the SOAP message.
var xml = ""+
""+
authenticationHeader+
""+
""+
"contact"+
""+lookupfield [0].id+""+
""+
""+
"parentcustomerid"+
""+
""+
""+
""+
"";
alert(xml );
// Prepare the xmlHttpObject and send the request.
var xHReq = new ActiveXObject("Msxml2.XMLHTTP");
xHReq.Open("POST", "/mscrmservices/2007/CrmService.asmx", false);
xHReq.setRequestHeader("SOAPAction","http://schemas.microsoft.com/crm/2007/WebServices/Retrieve");
xHReq.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
xHReq.setRequestHeader("Content-Length", xml.length);
xHReq.send(xml);
// Capture the result.
var resultXml = xHReq.responseXML;
alert("at results");
var errorCount = resultXml.selectNodes('//error').length;
alert("errorCount " + errorCount); ////////////////////////////////////returns 0; it shouldn't
alert("After the result XML "+resultXml .toString() + " ::::");
// Check for errors.
var errorCount = resultXml.selectNodes('//error').length;
if (errorCount != 0)
{
}
// Display the retrieved value.
else
{
//Create an array to set as the DataValue for the lookup control.
var lookupData = new Array();
//Create an Object add to the array.
var lookupItem= new Object();
//Set the id, typename, and name properties to the object.
lookupItem.id = resultXml.selectSingleNode("//q1:parentcustomerid").nodeTypedValue;
lookupItem.entityType = 'account';
lookupItem.name = resultXml.selectSingleNode("//q1:parentcustomerid").getAttribute("name");
// Add the object to the array.
lookupData[0] = lookupItem;
alert(lookupitem.name)
// Set the value of the lookup field to the value of the array.
Xrm.Page.getAttribute("str_companyid").setValue(lookupData);
}
var contact = new Array();
contact = Xrm.Page.getAttribute("to").getValue();
alert("I am here");
alert(contact);
if (contact == null || contact[0].entityType != "contact" || contact.length > 1) {
return;
}
alert("inside if")
var serverUrl = Xrm.Page.context.getClientUrl();
var oDataSelect = serverUrl + "/XRMServices/2011/OrganizationData.svc/ContactSet?$select=ParentCustomerId&$filter=ContactId eq guid'" + contact[0].id + "'";
var retrieveReq = new XMLHttpRequest();
retrieveReq.open("GET", oDataSelect, false);
retrieveReq.setRequestHeader("Accept", "application/json");
retrieveReq.setRequestHeader("Content-Type", "application/json;charset=utf-8");
retrieveReq.onreadystatechange = function () {
GetContactData(this);
};
retrieveReq.send();
}
I replied in the other forum but I post here as reference and with more technical details.
The to attribute of phonecall entity is a partylist type, this means that it can handle several records from different entities. In your case you want to get the Parent Account (field parentcustomerid) if a contact is inside the to field.
Your first code contains same typo and use the msdn Retrieve example, the second code uses CRM 4.0 endpoints, they are still supported inside CRM 2011, but it's better to avoid them so you can use the REST endpoint instead of the SOAP one.
a working code in your case can be:
function setToParentAccount() {
// set only if to Field (Recipient) has 1 record and is a contact
if (Xrm.Page.getAttribute("to").getValue() != null) {
var recipient = Xrm.Page.getAttribute("to").getValue();
if (recipient.length == 1 && recipient[0].entityType == "contact") {
var contactId = recipient[0].id;
var serverUrl;
if (Xrm.Page.context.getClientUrl !== undefined) {
serverUrl = Xrm.Page.context.getClientUrl();
} else {
serverUrl = Xrm.Page.context.getServerUrl();
}
var ODataPath = serverUrl + "/XRMServices/2011/OrganizationData.svc";
var contactRequest = new XMLHttpRequest();
contactRequest.open("GET", ODataPath + "/ContactSet(guid'" + contactId + "')", false);
contactRequest.setRequestHeader("Accept", "application/json");
contactRequest.setRequestHeader("Content-Type", "application/json; charset=utf-8");
contactRequest.send();
if (contactRequest.status === 200) {
var retrievedContact = JSON.parse(contactRequest.responseText).d;
var parentAccount = retrievedContact.ParentCustomerId;
if (parentAccount.Id != null && parentAccount.LogicalName == "account") {
var newParentAccount = new Array();
newParentAccount[0] = new Object();
newParentAccount[0].id = parentAccount.Id;
newParentAccount[0].name = parentAccount.Name;
newParentAccount[0].entityType = parentAccount.LogicalName;
Xrm.Page.getAttribute("str_companyid").setValue(newParentAccount);
} else {
Xrm.Page.getAttribute("str_companyid").setValue(null);
}
} else {
alert("error");
}
} else {
Xrm.Page.getAttribute("str_companyid").setValue(null);
}
}
}
to be called inside OnLoad event and OnChange event of the to field.

Resources