Data communication between two userInterface (ui) - Apps script refer to client instantiated sidebar - client-side

For the use of a google sheet stock management by several people, I use a sidebar for authentication (login). This running well, but i would like to allow different and simultaneous authentications (on different client computers)
In fact, my google scripts andZ html forms (integrated in userInterfaces) should be able to know and use the current agent, memorized by a sidebar field, as long as it is not closed.
I tried to use userProperties, scriptProperties, documentProperties,and cacheService but the connected agent is then memorized and common for all users instead of being specific to each workstation running the application. I have to work on the client side.
I know how to read and modify the DOM of the sidebar by the javascript code that i place there and also to recover this information within my google script. But here it is in fact a question of finding information from the instantiated sidebar.
My Apps Script:
function init_SideBar(e) { // init & show the sidebar
htmlSideBar = HtmlService.createHtmlOutputFromFile('htmlSideBar')
.setTitle('htmlSideBar')
.setWidth(300);
htmlSideBar.info="blabla"; // could it be a lead ?
SpreadsheetApp.getUi().showSidebar(htmlSideBar);
}
function gScriptFcGiveToSidebar() { // to send datas in an array to html page
let jSONforSheet= JSON.stringify(objForSheet);
return jSONforSheet;
}
function calledFromFormSubmit(sidebarForm) { // Receive datas from html sidebar
agentConnected=sidebarForm;
if(agentConnected=="Deconnecté"){
ss.toast("Deconnecté")
}else{
ss.toast("Bonjour "+agentConnected);
}
}
htmlSideBar.html:
<html>
<head>
<title>HTML DOM Objects</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js">
</script>
</head>
<body>
<label for="dowloading">dowloading</label>
<script>
function submitForm() { // envoi les données du form "sidebarForm" vers la fonction qui dans google script va les récupérer
// login & password verification (tablUser contains a column au login and a column of mp)
var elmts=document.getElementById("sidebarForm");
for(let iUsers=0;iUsers<sidebarObj.tablUser.length;iUsers++){
if (sidebarObj.tablUser[iUsers][0]==elmts.agentId.value){
if(sidebarObj.tablUser[iUsers][1]==elmts.mpId.value ){
document.getElementById('labelConnectId').innerHTML =elmts.agentId.value;
google.script.run.calledFromFormSubmit(elmts.agentId.value);
return;
}
}
}
alert ("password false, try again");
}
function deconnect(){
document.getElementById('labelConnectId').innerHTML ="Deconnecté";
document.getElementById('agentId').value ="Deconnecté";
google.script.run.calledFromFormSubmit("Deconnecté");
}
function jsFcGiveToForm(jSONforSheet){ //
$('#rangeResult').text(jSONforSheet); //$('#rangeResult').text(<nom de la variable qui va finalement délivrer au js, les données du google script>)
sidebarObj=JSON.parse(jSONforSheet);
document.write('<label id="labelConnectId" form="sidebarForm" > '+sidebarObj.agentConnected+'</label>');
document.write('<br><input type="button" value="Deconnect" onclick="deconnect();" />');
document.write('<form id="sidebarForm">');
document.write('<select name="agent" id="agentId">');
document.write('<option value="'+sidebarObj.agentConnected+'">'+sidebarObj.agentConnected+'</option>');
for(let iUsers=0;iUsers<sidebarObj.tablUser.length;iUsers++){
document.write('<option value="'+sidebarObj.tablUser[iUsers][0]+'">'+sidebarObj.tablUser[iUsers][0]+'</option>');
}
document.write('</select>');
document.write('<br /><input type="text" name="mp" id="mpId" value="password">');
document.write('<br /><input type="button" value="Submit" onclick="submitForm();" />');
document.write('<input type="button" value="Close" onclick="google.script.host.close()" />');
}
document.close(); // HYPER IMPORTANT !! libere le navigateur pour qu il continu a charger la page
google.script.run.withSuccessHandler(jsFcGiveToForm).gScriptFcGiveToSidebar();
</script>
</form>
</body>
</html>
Some leads ? :
Must i use scriptless
<?= blablabla?>
Using Meta tags :
var x = document.createElement("META");
x.setAttribute("name", "description");
x.setAttribute("content", "blablabla");
document.head.appendChild(x);
Using a property of htmlOutpu:
htmlSideBar.info="blabla";
Thanks a lot for your participation ! :)

I found a solution and described the sequences using the commented steps A1-4 and B1-12) which you just have to follow
Sidebar.gs:
function init_SideBar(e) { //A-1) init & show the sidebar.html
htmlSideBar = HtmlService.createHtmlOutputFromFile('htmlSideBar')
.setTitle('htmlSideBar')
.setWidth(300);// n'est plus modifiable fixé par google à 300 px
htmlSideBar.info="blabla";
HtmlService.SandboxMode=HtmlService.XFrameOptionsMode;
SpreadsheetApp.getUi().showSidebar(htmlSideBar);
}
function gScriptFcGiveToSidebar() { // A-3) to send google sheet datas (array or json...) to htmlSideBar.html page
let jSONforSheet= JSON.stringify(objForSheet);
ss.toast("json"+jSONforSheet);
return jSONforSheet;
}
function gScriptFromSidebarThenGiveToFormIn(sidebarAgent,provenanceFlag){
//Browser.msgBox("2 4 sidebarAgent="+sidebarAgent+" cache="+cacheService.get('sidebarAgent')+"init="+init);
if (provenanceFlag==false) { // B-7) Called by the de html htmlFormIn...withSuccessHandler(jsFcGiveToFormIn)
// Utilities.sleep(8000); // simulating an excess of a retention time of the cache
sidebarAgent=cacheService.get('sidebarAgent'); // B-8) Retieve the useful data in the cache
if (sidebarAgent==null) {return "echec";} // B-9) Abort in case the cache got lost (retention time exceeded)
cacheService.remove('sidebarAgent'); // B-10) Free the cache
return sidebarAgent; //B-11) give to formIn.html the data it expects
}else{ // B-2) provenanceFlag=true means that the call is from the htmlSideBar.html file buton.onclick , (sidebarAgent has the useful data)
if (cacheService.get('sidebarAgent')!=null) return false // B-3) cache not freed, abort proces for try again in a few time
cacheService.put('sidebarAgent',sidebarAgent,5); // B-4) Stock in cache the data for 5 secondes
initFormIn(sidebarAgent); //B5 open the user interface formIn.html that will have to take imediately the data in the cache, then free it
}
}
function calledFromFormSubmit(sidebarForm) { // Receive datas from html sidebar
agentConnected=sidebarForm;
//userProperties.setProperty('agentConnected', agentConnected);
if(agentConnected=="Deconnecté"){
ss.toast("Deconnecté")
}else{
ss.toast("Bonjour "+agentConnected);
}
//SpreadsheetApp.getActiveSheet().appendRow(["test",sidebarForm]);
}
htmlSideBar.html:
<!DOCTYPE html>
<html>
<head>
<style>
body { font-size:1em; }
p { color : red; }
</style>
<title>HTML DOM Objects</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js">
</script>
</head>
<body>
<label for="dowloading">dowloading</label>
<?= info?>
<script>
function callFormIn(){ google.script.run.gScriptFromSidebarThenGiveToFormIn(document.getElementById("labelConnectId").innerHTML,true);
}
function submitForm() { // My connect process
var elmts=document.getElementById("sidebarForm");
for(let iUsers=0;iUsers<sidebarObj.tablUser.length;iUsers++){
if (sidebarObj.tablUser[iUsers][0]==elmts.agentId.value){
if(sidebarObj.tablUser[iUsers][1]==elmts.mpId.value ){
document.getElementById('labelConnectId').innerHTML =elmts.agentId.value;
google.script.run.calledFromFormSubmit(elmts.agentId.value);
return;
}
}
}
alert ("mp faux");
}
function writeLabelAndTxtBox(name,id,value){
document.write('<br /><label for="'+name+'">'+name+': </label>');
document.write('<br /><input type="text" name="'+name+'" id="'+id+'" value="'+value+'">');
}
function writeLabel(name){
document.write('<br /><label for="'+name+'">'+name+': </label>');
}
function writeTxtBox(name,id,value){
document.write('<br /><input type="text" name="'+name+'" id="'+id+'" value="'+value+'">');
}
// -----------------------------------------------------------------------------------------------------------------
function clearAndClose(){
google.script.host.close();
}
function deconnect(){
document.getElementById('labelConnectId').innerHTML ="Deconnecté";
document.getElementById('agentId').value ="Deconnecté"; // facultatif ?
google.script.run.calledFromFormSubmit("Deconnecté");
}
function jsFcGiveToSidebar(jSONforSheet){ // A-4) I can Fill the sidebar.html page with json datas received from apps script about goole sheet
// End of the A1-4) states
sidebarObj=JSON.parse(jSONforSheet); // in particular sidebarObj.tablUser[] that contains the sheet columns of logins and passwords
/* sidebarObj.agentConnected was used to don't have to connect when open a new sidebar
(I dont speak aubout the google acount connection)
sidebarObj.keepConnectPropertie==false desactive this mode
i prefer now have to connect on each new sidebar instentiation.
the login is preserved while the sidebar is instantiated.
*/
document.write(new Date().toLocaleDateString());
if (sidebarObj.keepConnectPropertie==false){sidebarObj.agentConnected="Deconnecté"}
document.write('<label id="labelConnectId" form="sidebarForm" > '+sidebarObj.agentConnected+'</label>');
document.write('<br><input type="button" value="Deconnect" onclick="deconnect();" />');
document.write('<form id="sidebarForm">');
document.write('<select name="agent" id="agentId">');
document.write('<option value="'+sidebarObj.agentConnected+'">'+sidebarObj.agentConnected+'</option>');
for(let iUsers=0;iUsers<sidebarObj.tablUser.length;iUsers++){
document.write('<option value="'+sidebarObj.tablUser[iUsers][0]+'">'+sidebarObj.tablUser[iUsers][0]+'</option>');
}
document.write('</select>');
writeTxtBox('mp','mpId','password')
document.write('<br><input type="button" value="Submit" onclick="submitForm();" />');
document.write('<br><input type="button" value="FormIn" onclick="callFormIn();" />'); // B-1) run gScriptFromSidebarThenGiveToFormIn() with data parameter needed
document.write('<input type="button" value="Close" onclick="google.script.host.close()" />');
}
document.close();
google.script.run.withSuccessHandler(jsFcGiveToSidebar).gScriptFcGiveToSidebar(); // A-2) give to jsFcGiveToSidebar() the return of gScriptFcGiveToSidebar()
</script>
</form>
</body>
</html>
htmlFormIn.html:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<style type="text/css">
.myDiv {cursor:pointer;}
.divBlack{background-color:#000; color:#fff;}
</style>
<label for="dowloading">dowloading</label>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script>
// ---------------------------------------------- Functions for Javascript ------------------
function writeLabel(name){
document.write('<br /><label for="'+name+'">'+name+': </label>');
}
function writeTxtBox(name,id,value,prefix){
prefix=prefix||'<br />';
document.write(prefix+'<input type="text" name="'+name+'" id="'+id+'" value="'+value+'">');
}
// -------------------------------------------------Wrinting in Body -----
function addRow(){
cptLine++;
//alert(sidebarAgent); // alert(document.getElementById("idLblSidebarAgent").innerHTML);
//document.getElementById("tableForm").appendChild("tr");
let newLin = document.getElementById("tableForm").insertRow(-1); // ajoute un <tr> à la fin de la table
let newCell=newLin.insertCell(0); // ajoute un <td>
newCell.innerHTML = '<input type="text" name="" id=c"'+cptLine+'" value="v'+cptLine+'"> <input type="text" name="" id=d"'+cptLine+'" value="'+sidebarAgent+'">';
//alert("ajouté");
}
function jsFcGiveToFormIn(aagent){ // B-12) aagent receive the data value return from gScriptFromSidebarThenGiveToFormIn that have been called in A6 state
// B-13) the formIn.html can fill its fields :) - End of the B1-12) states
if (aagent=="echec"){ alert ("htmlFormIn 71 le cache service n'a pas memorisé assez longemps le transfert de donnée depuis la sidebar")}
sidebarAgent=aagent; // pour étendre la portée de cette info dans le script de cette page html
document.write('<label id="idLblSidebarAgent" for="info">'+sidebarAgent+'</label>')
writeTxtBox("Saisie","idSaisie","Entrez un code");
document.getElementById("idSaisie").addEventListener("click", addRow);
document.write('<form id="sidebarForm">');
document.write('<table id="tableForm"><tr id="r'+cptLine+'""><td>');writeTxtBox("Date","iddat","date"," ");writeTxtBox("Ref","idRef"+cptLine,""," ");
writeTxtBox("agent","idAgent",sidebarAgent," ");
document.write('</td></tr>')
document.write('</table>')
document.write('</form>');
}
document.close();
var cptLine=0;
var sidebarAgent;
google.script.run.withSuccessHandler(jsFcGiveToFormIn).gScriptFromSidebarThenGiveToFormIn("",false); // B-6) give to jsFcGiveToFormIn the return of gScriptFromSidebarThenGiveToFormIn("",provenanceFlag=false) with provenanceFlag=false that meaning the call is from formIn.html file.
</script>
</body>
</html>

Related

Google Recaptcha v3 example demo

Until now, I was working with Google Recaptcha v2, but now I want to update my WebApp using the lastest version (v3).
Is it possible to anyone add a fully working Google Recaptcha v3 example for a basic form as I can't find any working demos of it?
I'd really appreciate it.
Thank you very much.
PS: I'm using Java Servlets on the server side, but it doesn't matter if you explain using PHP or whatever.
Simple code to implement ReCaptcha v3
The basic JS code
<script src="https://www.google.com/recaptcha/api.js?render=your reCAPTCHA site key here"></script>
<script>
grecaptcha.ready(function() {
// do request for recaptcha token
// response is promise with passed token
grecaptcha.execute('your reCAPTCHA site key here', {action:'validate_captcha'})
.then(function(token) {
// add token value to form
document.getElementById('g-recaptcha-response').value = token;
});
});
</script>
The basic HTML code
<form id="form_id" method="post" action="your_action.php">
<input type="hidden" id="g-recaptcha-response" name="g-recaptcha-response">
<input type="hidden" name="action" value="validate_captcha">
.... your fields
</form>
The basic PHP code
if (isset($_POST['g-recaptcha-response'])) {
$captcha = $_POST['g-recaptcha-response'];
} else {
$captcha = false;
}
if (!$captcha) {
//Do something with error
} else {
$secret = 'Your secret key here';
$response = file_get_contents(
"https://www.google.com/recaptcha/api/siteverify?secret=" . $secret . "&response=" . $captcha . "&remoteip=" . $_SERVER['REMOTE_ADDR']
);
// use json_decode to extract json response
$response = json_decode($response);
if ($response->success === false) {
//Do something with error
}
}
//... The Captcha is valid you can continue with the rest of your code
//... Add code to filter access using $response . score
if ($response->success==true && $response->score <= 0.5) {
//Do something to denied access
}
You have to filter access using the value of $response.score. It can takes values from 0.0 to 1.0, where 1.0 means the best user interaction with your site and 0.0 the worst interaction (like a bot). You can see some examples of use in ReCaptcha documentation.
I thought a fully-functioning reCaptcha v3 example demo in PHP, using a Bootstrap 4 form, might be useful to some.
Reference the shown dependencies, swap in your email address and keys (create your own keys here), and the form is ready to test and use. I made code comments to better clarify the logic and also included commented-out console log and print_r lines to quickly enable viewing the validation token and data generated from Google.
The included jQuery function is optional, though it does create a much better user prompt experience in this demo.
PHP file (mail.php):
Add secret key (2 places) and email address where noted.
<?php
if ($_SERVER["REQUEST_METHOD"] == "POST") {
# BEGIN Setting reCaptcha v3 validation data
$url = "https://www.google.com/recaptcha/api/siteverify";
$data = [
'secret' => "your-secret-key-here",
'response' => $_POST['token'],
'remoteip' => $_SERVER['REMOTE_ADDR']
];
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => http_build_query($data)
)
);
# Creates and returns stream context with options supplied in options preset
$context = stream_context_create($options);
# file_get_contents() is the preferred way to read the contents of a file into a string
$response = file_get_contents($url, false, $context);
# Takes a JSON encoded string and converts it into a PHP variable
$res = json_decode($response, true);
# END setting reCaptcha v3 validation data
// print_r($response);
# Post form OR output alert and bypass post if false. NOTE: score conditional is optional
# since the successful score default is set at >= 0.5 by Google. Some developers want to
# be able to control score result conditions, so I included that in this example.
if ($res['success'] == true && $res['score'] >= 0.5) {
# Recipient email
$mail_to = "youremail#domain.com";
# Sender form data
$subject = trim($_POST["subject"]);
$name = str_replace(array("\r","\n"),array(" "," ") , strip_tags(trim($_POST["name"])));
$email = filter_var(trim($_POST["email"]), FILTER_SANITIZE_EMAIL);
$phone = trim($_POST["phone"]);
$message = trim($_POST["message"]);
if (empty($name) OR !filter_var($email, FILTER_VALIDATE_EMAIL) OR empty($phone) OR empty($subject) OR empty($message)) {
# Set a 400 (bad request) response code and exit
http_response_code(400);
echo '<p class="alert-warning">Please complete the form and try again.</p>';
exit;
}
# Mail content
$content = "Name: $name\n";
$content .= "Email: $email\n\n";
$content .= "Phone: $phone\n";
$content .= "Message:\n$message\n";
# Email headers
$headers = "From: $name <$email>";
# Send the email
$success = mail($mail_to, $subject, $content, $headers);
if ($success) {
# Set a 200 (okay) response code
http_response_code(200);
echo '<p class="alert alert-success">Thank You! Your message has been successfully sent.</p>';
} else {
# Set a 500 (internal server error) response code
http_response_code(500);
echo '<p class="alert alert-warning">Something went wrong, your message could not be sent.</p>';
}
} else {
echo '<div class="alert alert-danger">
Error! The security token has expired or you are a bot.
</div>';
}
} else {
# Not a POST request, set a 403 (forbidden) response code
http_response_code(403);
echo '<p class="alert-warning">There was a problem with your submission, please try again.</p>';
} ?>
HTML <head>
Bootstrap CSS dependency and reCaptcha client-side validation
Place between <head> tags - paste your own site-key where noted.
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
<script src="https://www.google.com/recaptcha/api.js?render=your-site-key-here"></script>
HTML <body>
Place between <body> tags.
<!-- contact form demo container -->
<section style="margin: 50px 20px;">
<div style="max-width: 768px; margin: auto;">
<!-- contact form -->
<div class="card">
<h2 class="card-header">Contact Form</h2>
<div class="card-body">
<form class="contact_form" method="post" action="mail.php">
<!-- form fields -->
<div class="row">
<div class="col-md-6 form-group">
<input name="name" type="text" class="form-control" placeholder="Name" required>
</div>
<div class="col-md-6 form-group">
<input name="email" type="email" class="form-control" placeholder="Email" required>
</div>
<div class="col-md-6 form-group">
<input name="phone" type="text" class="form-control" placeholder="Phone" required>
</div>
<div class="col-md-6 form-group">
<input name="subject" type="text" class="form-control" placeholder="Subject" required>
</div>
<div class="col-12 form-group">
<textarea name="message" class="form-control" rows="5" placeholder="Message" required></textarea>
</div>
<!-- form message prompt -->
<div class="row">
<div class="col-12">
<div class="contact_msg" style="display: none">
<p>Your message was sent.</p>
</div>
</div>
</div>
<div class="col-12">
<input type="submit" value="Submit Form" class="btn btn-success" name="post">
</div>
<!-- hidden reCaptcha token input -->
<input type="hidden" id="token" name="token">
</div>
</form>
</div>
</div>
</div>
</section>
<script>
grecaptcha.ready(function() {
grecaptcha.execute('your-site-key-here', {action: 'homepage'}).then(function(token) {
// console.log(token);
document.getElementById("token").value = token;
});
// refresh token every minute to prevent expiration
setInterval(function(){
grecaptcha.execute('your-site-key-here', {action: 'homepage'}).then(function(token) {
console.log( 'refreshed token:', token );
document.getElementById("token").value = token;
});
}, 60000);
});
</script>
<!-- References for the optional jQuery function to enhance end-user prompts -->
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script src="form.js"></script>
Optional jQuery function for enhanced UX (form.js):
(function ($) {
'use strict';
var form = $('.contact_form'),
message = $('.contact_msg'),
form_data;
// Success function
function done_func(response) {
message.fadeIn()
message.html(response);
setTimeout(function () {
message.fadeOut();
}, 10000);
form.find('input:not([type="submit"]), textarea').val('');
}
// fail function
function fail_func(data) {
message.fadeIn()
message.html(data.responseText);
setTimeout(function () {
message.fadeOut();
}, 10000);
}
form.submit(function (e) {
e.preventDefault();
form_data = $(this).serialize();
$.ajax({
type: 'POST',
url: form.attr('action'),
data: form_data
})
.done(done_func)
.fail(fail_func);
}); })(jQuery);
I am assuming you have site key and secret in place. Follow this step.
In your HTML file, add the script.
<script src="https://www.google.com/recaptcha/api.js?render=put your site key here"></script>
Also, do use jQuery for easy event handling.
Here is the simple form.
<form id="comment_form" action="form.php" method="post" >
<input type="email" name="email" placeholder="Type your email" size="40"><br><br>
<textarea name="comment" rows="8" cols="39"></textarea><br><br>
<input type="submit" name="submit" value="Post comment"><br><br>
</form>
You need to initialize the Google recaptcha and listen for the ready event. Here is how to do that.
<script>
// when form is submit
$('#comment_form').submit(function() {
// we stoped it
event.preventDefault();
var email = $('#email').val();
var comment = $("#comment").val();
// needs for recaptacha ready
grecaptcha.ready(function() {
// do request for recaptcha token
// response is promise with passed token
grecaptcha.execute('put your site key here', {action: 'create_comment'}).then(function(token) {
// add token to form
$('#comment_form').prepend('<input type="hidden" name="g-recaptcha-response" value="' + token + '">');
$.post("form.php",{email: email, comment: comment, token: token}, function(result) {
console.log(result);
if(result.success) {
alert('Thanks for posting comment.')
} else {
alert('You are spammer ! Get the #$%K out.')
}
});
});
});
});
</script>
Here is the sample PHP file. You can use Servlet or Node or any backend language in place of it.
<?php
$email;$comment;$captcha;
if(isset($_POST['email'])){
$email=$_POST['email'];
}if(isset($_POST['comment'])){
$comment=$_POST['comment'];
}if(isset($_POST['token'])){
$captcha=$_POST['token'];
}
if(!$captcha){
echo '<h2>Please check the the captcha form.</h2>';
exit;
}
$secretKey = "put your secret key here";
$ip = $_SERVER['REMOTE_ADDR'];
// post request to server
$url = 'https://www.google.com/recaptcha/api/siteverify?secret=' . urlencode($secretKey) . '&response=' . urlencode($captcha);
$response = file_get_contents($url);
$responseKeys = json_decode($response,true);
header('Content-type: application/json');
if($responseKeys["success"]) {
echo json_encode(array('success' => 'true'));
} else {
echo json_encode(array('success' => 'false'));
}
?>
Here is the tutorial link: https://codeforgeek.com/2019/02/google-recaptcha-v3-tutorial/
Hope it helps.
We use recaptcha-V3 only to see site traffic quality, and used it as non blocking. Since recaptcha-V3 doesn't require to show on site and can be used as hidden but you have to show recaptcha privacy etc links (as recommended)
Script Tag in Head
<script src="https://www.google.com/recaptcha/api.js?onload=ReCaptchaCallbackV3&render='SITE KEY' async defer></script>
Note: "async defer" make sure its non blocking which is our specific requirement
JS Code:
<script>
ReCaptchaCallbackV3 = function() {
grecaptcha.ready(function() {
grecaptcha.execute("SITE KEY").then(function(token) {
$.ajax({
type: "POST",
url: `https://api.${window.appInfo.siteDomain}/v1/recaptcha/score`,
data: {
"token" : token,
},
success: function(data) {
if(data.response.success) {
window.recaptchaScore = data.response.score;
console.log('user score ' + data.response.score)
}
},
error: function() {
console.log('error while getting google recaptcha score!')
}
});
});
});
};
</script>
HTML/Css Code:
there is no html code since our requirement is just to get score and don't want to show recaptcha badge.
Backend - Laravel Code:
Route:
Route::post('/recaptcha/score', 'Api\\ReCaptcha\\RecaptchaScore#index');
Class:
class RecaptchaScore extends Controller
{
public function index(Request $request)
{
$score = null;
$response = (new Client())->request('post', 'https://www.google.com/recaptcha/api/siteverify', [
'form_params' => [
'response' => $request->get('token'),
'secret' => 'SECRET HERE',
],
]);
$score = json_decode($response->getBody()->getContents(), true);
if (!$score['success']) {
Log::warning('Google ReCaptcha Score', [
'class' => __CLASS__,
'message' => json_encode($score['error-codes']),
]);
}
return [
'response' => $score,
];
}
}
we get back score and save in variable which we later user when submit form.
Reference:
https://developers.google.com/recaptcha/docs/v3
https://developers.google.com/recaptcha/
I have seen most of the articles that don't work properly that's why new developers and professional developers get confused about it.
I am explaining to you in a very simple way. In this code, I am generating a google Recaptcha token at the client side at every 3 seconds of time interval because the token is valid for only a few minutes that's why if any user takes time to fill the form then it may be expired.
First I have an index.php file where I am going to write HTML and JavaScript code.
<!DOCTYPE html>
<html>
<head>
<title>Google Recaptcha V3</title>
</head>
<body>
<h1>Google Recaptcha V3</h1>
<form action="recaptcha.php" method="post">
<label>Name</label>
<input type="text" name="name" id="name">
<input type="hidden" name="token" id="token" />
<input type="hidden" name="action" id="action" />
<input type="submit" name="submit">
</form>
<script src="https://www.google.com/recaptcha/api.js?render=put your site key here"></script>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
setInterval(function(){
grecaptcha.ready(function() {
grecaptcha.execute('put your site key here', {action: 'application_form'}).then(function(token) {
$('#token').val(token);
$('#action').val('application_form');
});
});
}, 3000);
});
</script>
</body>
</html>
Next, I have created recaptcha.php file to execute it at the server side
<?php
if ($_POST['submit']) {
$name = $_POST['name'];
$token = $_POST['token'];
$action = $_POST['action'];
$curlData = array(
'secret' => 'put your secret key here',
'response' => $token
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://www.google.com/recaptcha/api/siteverify");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($curlData));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$curlResponse = curl_exec($ch);
$captchaResponse = json_decode($curlResponse, true);
if ($captchaResponse['success'] == '1' && $captchaResponse['action'] == $action && $captchaResponse['score'] >= 0.5 && $captchaResponse['hostname'] == $_SERVER['SERVER_NAME']) {
echo 'Form Submitted Successfully';
} else {
echo 'You are not a human';
}
}
Source of this code. If you would like to know the explanation of this code please visit. Google reCAPTCHA V3 integration in PHP
For a "basic form" (as the original question asks) what's needed is simple if you're content to validate on the server. Here's a complete HTML page:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<script src="https://www.google.com/recaptcha/api.js"></script>
<script>
<!--
function onSubmit() {
var form = document.forms[0];
if ( form['name'].value ) {
form.submit();
} else {
alert( 'Please provide a name.' );
}
}
//-->
</script>
</head>
<body>
<form action="process.asp" method="post">
Name: <input type="text" name="name" /><br /><br />
<button class="g-recaptcha" data-sitekey="SITE_KEY" data-callback='onSubmit' data-action='contact'>Send</button>
</form>
</body>
</html>
And here's the complete page for processing it, using Classic ASP (filename = process.asp) for simplicity:
<%# Language=JavaScript %>
<%
var name = Request( 'name' ).Item;
var recaptchaResponse = Request( 'g-recaptcha-response' ).Item;
var ip = Request.ServerVariables( 'REMOTE_ADDR' );
var xmlhttp = Server.CreateObject( 'MSXML2.ServerXMLHTTP' );
var query = 'secret=SECRET_KEY&response=' + recaptchaResponse + '&remoteip=' + ip;
xmlhttp.open( 'POST', 'https://www.google.com/recaptcha/api/siteverify?' + query, false ); // false says to wait for response
xmlhttp.send();
var response = JSON.parse( xmlhttp.responseText );
Response.Write( name + ' is a ' + (response.success && response.action == 'contact' && response.score > 0.5 ? 'HUMAN' : 'ROBOT') );
%>
A few notes:
You'll supply your own SITE_KEY and SECRET_KEY.
You'll need a JSON parser.
You'll do the server-side POST using a method suitable for your
server.
I added one simple form field validation so you can see how to
integrate that.
You can make the "action" string anything you want, but be sure that
what's on the server is consistent with what's in the HTML.
You might want to respond differently to a response.success that
isn't true or a response.action that doesn't match your action
string, or do other error checking.
You might want a score conditional other than "> 0.5".
This code has no problems with the two-minute timeout.
I process POST on PHP from an angular ajax call. I also like to see the SCORE from google.
This works well for me...
$postData = json_decode(file_get_contents('php://input'), true); //get data sent via post
$captcha = $postData['g-recaptcha-response'];
header('Content-Type: application/json');
if($captcha === ''){
//Do something with error
echo '{ "status" : "bad", "score" : "none"}';
} else {
$secret = 'your-secret-key';
$response = file_get_contents(
"https://www.google.com/recaptcha/api/siteverify?secret=" . $secret . "&response=" . $captcha . "&remoteip=" . $_SERVER['REMOTE_ADDR']
);
// use json_decode to extract json response
$response = json_decode($response);
if ($response->success === false) {
//Do something with error
echo '{ "status" : "bad", "score" : "none"}';
}else if ($response->success==true && $response->score <= 0.5) {
echo '{ "status" : "bad", "score" : "'.$response->score.'"}';
}else {
echo '{ "status" : "ok", "score" : "'.$response->score.'"}';
}
}
On HTML
<input type="hidden" id="g-recaptcha-response" name="g-recaptcha-response">
On js
$scope.grabCaptchaV3=function(){
var myCaptcha = angular.element('#g-recaptcha-response').val();
var params = {
method: 'POST',
url: 'api/recaptcha.php',
headers: {
'Content-Type': undefined
},
data: {'g-recaptcha-response' : myCaptcha }
}
$http(params).then(function(result){
console.log(result.data);
}, function(response){
console.log(response.statusText);
});
}
if you are newly implementing recaptcha on your site, I would suggest adding api.js and let google collect behavioral data of your users 1-2 days. It is much fail-safe this way, especially before starting to use score.

Polymer 2.0 + firebase can't update properly

I've got a problem using Polymer 2.0 and Firebase.
I want to update data to Firebase with firebase-document but when I want to update only the title, it destroy all the previous data and save only the title.
Example of the strucute before update :
myapp:
categories:
1:
logoName: test.png
title: test
And after :
myapp:
categories:
1:
title: test bis
Do I have to give always the entire record and update only the field I want or can I only give the field I want to update to saveValue.
I try to only give the field but it doesn't seem to work
Here is a part of my code :
<dom-module id="categorie-form">
<template>
<firebase-document
id="document"
app-name="myapp"
data="{{categorieData}}">
</firebase-document>
<iron-form id="categorieIronForm">
<form id="categorieForm">
<label for="title">Nom de la catégorie</label>
<input type="text" name="title" id="title" value="[[name]]">
<paper-button id="validButton" on-click="_submitCategorie" raised>valider</paper-button>
</form>
</iron-form>
</template>
<script>
class CategorieForm extends Polymer.Element {
static get is () { return "categorie-form" }
static get properties () {
return {
categorieData: {
type: Object
}
}
}
_submitCategorie () {
this.categorieData = {
title: form.title.value
};
this.$.document.saveValue('/categories', key)
}
}
customElements.define(CategorieForm.is, CategorieForm);
</script>
</dom-module>
Thank you
try this :
this.$.document.saveValue('/categories/1/title', key)

HOW TO CONVERT TRIPLE TAG IN METEOR 0.7.0.1 ACCORDING TO VERSION 0.8.0

I have updated meteor application to version 0.8.0 from 0.7.0.1. Every changes tried to do but not able to figure out, how to change triple tag according to new version. Referred the following link and tried to do so but still getting error.
The link following is: https://github.com/meteor/meteor/wiki/Using-Blaze
The code of .html file is: Basically this {{{done }}} part. I tried to change according to the above link as {{> done}}. But then getting error as ""Reactive HTML attributes must either have a constant name or consist of a single {{helper}} providing a dictionary of names and values. A template tag of type INCLUSION is not allowed here.
""
<template name="subscribedKeyword">
<div class="issue" >
<div class="issue-content">
<h3>
{{category}}
<input id='check' class="checktype" name="mark" type="checkbox" value="1" {{{ done}}} />Get Notifications
<input type="hidden" name="mark" value="0" />
</h3>
</div>
</div>
</template>
The corresponding .js file code is: I think that there is no need to change anything in this file. As according to the above link, changes need to be done in the html file only.
Template.subscribedKeyword.done = function () {
// alert('inside done function');
var subscribedUsersOfThisDomain= Subscribed.findOne(this._id);
var subscribedPersons = subscribedUsersOfThisDomain.categorySubscribedUsers;
// alert('before if block in done function');
if(subscribedPersons && subscribedPersons.length)
{
var j;
var ch='';
// alert('before loop in done function');
for(j= 0;j< subscribedPersons.length;j++)
{
//alert('j '+j);
//alert('person '+person[j].username);
if(subscribedPersons[j].username === Meteor.user().username)
{
ch ="checked";
// alert('value of ch that is set'+ch);
break;
}
}
if(ch=== 'checked')
{
// alert('while returning value in if block');
return 'checked="checked"';
}
else
{
// alert('while returning value in else block');
return '';
}
}
else
return '';
};
Do let me know what changed need to be done. Thanks in advance
The simplest way I can see is:
<template name="subscribedKeyword">
<div class="issue" >
<div class="issue-content">
<h3>
{{category}}
<input id='check' class="checktype" name="mark" type="checkbox" value="1" checked={{done}} />Get Notifications
<input type="hidden" name="mark" value="0" />
</h3>
</div>
</div>
</template>
Template.subscribedKeyword.done = function () {
// alert('inside done function');
var subscribedUsersOfThisDomain= Subscribed.findOne(this._id);
var subscribedPersons = subscribedUsersOfThisDomain.categorySubscribedUsers;
// alert('before if block in done function');
if(subscribedPersons && subscribedPersons.length)
{
var j;
var ch='';
// alert('before loop in done function');
for(j= 0;j< subscribedPersons.length;j++)
{
//alert('j '+j);
//alert('person '+person[j].username);
if(subscribedPersons[j].username === Meteor.user().username)
{
ch ="checked";
// alert('value of ch that is set'+ch);
break;
}
}
if(ch=== 'checked')
{
// alert('while returning value in if block');
return "checked";
}
else
{
// alert('while returning value in else block');
return null;
}
}
else
return null;
};
According to https://github.com/meteor/meteor/wiki/Using-Blaze#conditional-attributes-with-no-value-eg-checked-selected

How to add Paypal buy buttons to items in aspx page?

I am a newbie to paypal. I got a sandbox test item onpaypal and created an
item Buy button which is embedded html code.
Now whenever I insert the html code in the aspx page, it dosen't redirect to the paypal site.
Maybe because of the form tag that covers the html code. Here is the code for paypal buy button for an item:
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
<input type="hidden" name="cmd" value="_s-xclick">
<input type="hidden" name="hosted_button_id" value="3GWR6RV47BCVE">
<input type="image" src="https://www.paypalobjects.com/en_GB/i/btn/btn_buynowCC_LG.gif" border="0" name="submit" alt="PayPal – The safer, easier way to pay online.">
<img alt="" border="0" src="https://www.paypalobjects.com/en_GB/i/scr/pixel.gif" width="1" height="1">
</form>
I tried this code in a plain HTML file, and it worked. But as soon as I put it in a form runat server tag on aspx, it redirects the page to itself.
The problem is that ASP.NET pages define a form within which all the controls are placed (especially if you are using a master page) and HTML does not allow nested form tags.
There are several ways around this including using a normal ASP image button as described here.
You can also use an anchor link as described in this blog. However as noted by the author, the user can save the page source, edit it (e.g. change the price) and then reload it and click the link.
In fact any method that stores the information in the source of the webpage has potential to be abused. Therefore the approach I like, is to use a combination of an ASP image button and the anchor link approach but to implement this on the sever within the button click event:
1) In your ASP page define an image button where you want the PayPal button to go. You can set the ImageURL to the preferred button type provided by PayPal.
<asp:ImageButton
ID="PayPalBtn"
runat="server"
ImageUrl="https://www.paypalobjects.com/en_GB/i/btn/btn_buynow_LG.gif"
onclick="PayPalBtn_Click" />
2) Use the Click event of the button to generate the required information on the server side and then redirect the browser to the PayPal site.
protected void PayPalBtn_Click(object sender, ImageClickEventArgs e)
{
string business = "<insert your paypal email or merchant id here>";
string itemName = "<insert the item name here>";
double itemAmount = 123.451;
string currencyCode = "GBP";
StringBuilder ppHref = new StringBuilder();
ppHref.Append("https://www.paypal.com/cgi-bin/webscr?cmd=_xclick");
ppHref.Append("&business=" + business);
ppHref.Append("&item_name=" + itemName);
ppHref.Append("&amount=" + itemAmount.ToString("#.00"));
ppHref.Append("&currency_code=" + currencyCode);
Response.Redirect(ppHref.ToString(), true);
}
Disclaimer: It may still be possible for users to abuse this approach (although it is now a bit harder) so it is always best to check what has been paid before dispatching goods.
An ASPX page is like a giant HTML form. You need to close the ASPX form before the PayPal button code starts.
Like this:
<form name="default.aspx">
-- Page content
</form>
<!-- Close the form-->
<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
-- button code
You can also try creating the button as a URL and hyperlink to some text or an image on your site - you can still use the PayPal button image. When you're viewing the button code within PayPal there should be a tab above it labeled "E-mail". Click that and you'll get a URL - if you're creating buttons with a drop-down menu or text field you cannot turn the button into a URL.
This is a hack way of doing it, but before the paypal code enter a closing form tag (This will close the asp pages form) then remove the closing form tag from the paypal code and allow the end of .net page end form tag to close the paypals form..
I did it using an iframe for each button
<iframe height="27" marginheight="0" src="/PayPalButton.htm?button_id=ABCXYZSSSSS" frameborder="0" width="120" marginwidth="0" scrolling="no"></iframe>
Here is the code inside PayPalButton.htm
<html>
<head>
<title>PayPal</title>
<script type = "text/javascript">
// function to get url parameter
function getURLParameters(paramName) {
var sURL = window.document.URL.toString();
if (sURL.indexOf("?") > 0) {
var arrParams = sURL.split("?");
var arrURLParams = arrParams[1].split("&");
var arrParamNames = new Array(arrURLParams.length);
var arrParamValues = new Array(arrURLParams.length);
var i = 0;
for (i = 0; i < arrURLParams.length; i++) {
var sParam = arrURLParams[i].split("=");
arrParamNames[i] = sParam[0];
if (sParam[1] != "")
arrParamValues[i] = unescape(sParam[1]);
else
arrParamValues[i] = "No Value";
}
for (i = 0; i < arrURLParams.length; i++) {
if (arrParamNames[i] == paramName) {
//alert("Param:"+arrParamValues[i]);
return arrParamValues[i];
}
}
return "No Parameters Found";
}
}
// function to get button ID from url
function payPalButtonCode() {
var code = '<input value="_s-xclick" type="hidden" name="cmd" /> <input value="';
code = code + getURLParameters('button_id');
code = code + '" type="hidden" name="hosted_button_id" /> '
document.write(code);
}
function payPalButtonQuantity() {
var button_quantity_low = getURLParameters('button_quantity_low');
var button_quantity_high = getURLParameters('button_quantity_high');
var button_quantity_unit = getURLParameters('button_quantity_unit');
var button_quantity_units = getURLParameters('button_quantity_units');
var code = '';
var i;
if (button_quantity_low != 'No Parameters Found')
{
code = '<select name="quantity">';
for ( i = button_quantity_low; i <= button_quantity_high; i++) {
if (i > 1) {
code = code + String.format('<option value="{0}">{0} {1}</option>', i, button_quantity_units);
}
else {
code = code + String.format('<option value="{0}">{0} {1}</option>', i, button_quantity_unit);
}
}
code = code + '</select>';
}
else
{
code = '';
}
document.write(code);
}
function payPalButtonType() {
var code = '<input alt="PayPal – The safer, easier way to pay online." src="';
var button_type = getURLParameters('button_type');
if (button_type=='buy_now'){
code = code + 'https://www.paypalobjects.com/en_GB/i/btn/btn_buynow_LG.gif" type="image" name="submit" />';
}
else
{
//code = code + 'https://www.paypalobjects.com/en_GB/i/btn/btn_subscribe_SM.gif" type="image" name="submit" />';
code = code + 'https://www.paypalobjects.com/en_GB/i/btn/btn_buynow_LG.gif" type="image" name="submit" />';
}
document.write(code);
}
String.format = function() {
// The string containing the format items (e.g. "{0}")
// will and always has to be the first argument.
var theString = arguments[0];
// start with the second argument (i = 1)
for (var i = 1; i < arguments.length; i++) {
// "gm" = RegEx options for Global search (more than one instance)
// and for Multiline search
var regEx = new RegExp("\\{" + (i - 1) + "\\}", "gm");
theString = theString.replace(regEx, arguments[i]);
}
return theString;
}
</script>
</head>
<body>
<form id="f1" method="post" action="https://www.paypal.com/cgi-bin/webscr" target="_top">
<script type="text/javascript">payPalButtonCode();</script>
<script type="text/javascript">payPalButtonQuantity();</script>
<script type="text/javascript">payPalButtonType();</script>
<img alt="" style="border: 0px solid;" src="https://www.paypalobjects.com/en_GB/i/scr/pixel.gif" />
</form>
</body>
</html>
For fixed-price buttons, there's a VERY easy, html-only workaround. Just copy the email-link provided by paypal, and create a very normal link using <a> ... </a>, which as content has the image that would normally appear in the <form> statement:
<a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=3GWR6RV47BCVE" target="_top">
<img src="https://www.paypalobjects.com/it_IT/IT/i/btn/btn_buynowCC_LG.gif" border="0" title="submit" alt="PayPal – The safer, easier way to pay online." />
</a>
I've been searching for a solution today, so even if this thread hasn't been active lately, maybe this can be useful to someone else who wants to avoid code-behind.

Load dynamic list of elements AFTER FINISHED loading of several form elements

I have...
a dynamic populated select box
several input boxes
a submit button
form fields are loaded initially using cookies
several dynamic populated divs
I want...
start loading the content of my DIVs after all FORM elements have been loaded completely (= filled with data, select boxes are populated)
Sample code:
<script type="text/javascript">
$(document).ready(function() {
// Populate <select>
var options ='';
for (var i = 0; i < j.length; i++) {
options += '<option value="' + i + '">' + i + '</option>';
}
$("select#myid").html(options);
})
...
</script>
<form>
<select id="myselect></select>
<input id="mytext" type="text" value="" />
<input type="submit" value="Search" />
</form>
<% foreach( MyElement element in MyListing) { %>
<div>
<script type="text/javascript">
$(document).ready(function() {
DoSomething($(select#myid).val());
})
</script>
</div>
<% } %>
Any help is very appreciated.
Edited for the extra information:
jQuery(function($) { // note that this is equivalent to $(document).load()
// if we are here, then all your page and form elements have loaded.
// Populate <select> as per your code above
$('div').each(function(index) { // perhaps give them a class?
$(this).load(<<someURL>>);
// it's not clear from your question how you intend to get the
// dynamic content, ie: what url to use?
});
});

Resources