recaptcha server side integration - recaptcha

i'm trying to add recaptcha to an existing contact form.
i have done step 1 (client side integration) on google
but i don't understand step2
the directions for server side say:
send a POST request with these parameters:
URL: https://www.google.com/recaptcha/api/siteverify
secret (required) 6LfWAFAUAAAAALhRhjHZ1OdoMexS50EqSuxoF5jq
response (required) The value of 'g-recaptcha-response'.
remoteip The end user's ip address.
i have my own secret key but how do i "send a POST"?
if anyone has the patience to explain this whole step, i'd greatly appreciate it.

When user deals with re-captcha, re-captcha response is appended into the relevant div by google code. You wouldn't need to worry about it.
What you need to do is to ensure if it is there and valid.
For my case, I use jqBootstrapValidation to help validating my form components.
$("#myElement").jqBootstrapValidation({
preventSubmit: true,
submitError: function($form, event, errors) {
// do something useful for error case
},
submitSuccess: function($form, event) {
event.preventDefault(); // prevent default submit behaviour
// get values from FORM
var name = $("input#name").val();
// ...
var g_captcha_response = $("#g-recaptcha-response").val();
// if response does not exist, do NOT proceed
if (!(g_captcha_response && g_captcha_response.length>0)){
return;
}
// User is HUMAN. So charge ahead.!
...
EDIT
I use recaptcha-V2 for my site.

Related

How to track pageviews in RemixJS?

I am building a Remix app, and wanted to record some user analytics in my database based on what page the user was viewing. I also wanted to do so on a route by route basis, rather than just simply the raw URL.
For example: I wanted to know "user viewed URL /emails/123" as well as "user viewed route /emails/$emailId"
This problem could be generalized as "I want to run a piece of server code once per user navigation"
For my tracking I'm assuming users have javascript enabled in their browser.
Solutions I tried:
Record in the loader
This would be something like:
export const loader: LoaderFunction = async ({ request, params }): Promise<LoaderData> => {
myDb.recordPageVisit(request.url);
}
This doesn't work because the loader can be called multiple times per page visit (eg. after an action is run)
It's possible that there's some value hidden in the request parameter that tells us whether this is an initial page load or if it's a later visit, but if so I couldn't find it, including when I examined the raw HTTP requests.
It's also annoying to have to put this code inside of every loader.
Record the URL in the node code
I'm using #remix-run/node as my base remix server, so I have the escape hatch of setting up node middleware, and I thought that might be a good answer:
const app = express();
app.use((req, res, next) => {
if (req.url.indexOf("_data") == -1) {
myDb.recordPageVisit(req.url);
}
next();
});
I tried ignoring routes with _data in them, but that didn't work because remix is being efficient and when the user navigates, it is using an ajax-y call to only get the loaderData rather than getting the full rendered page from the server. I know this is the behavior of Remix, but I had not remembered it before I went down this path :facepalm:
As far as I can tell it's impossible to stateless-ly track unique pageviews (ie based purely on the current URL) - you need see the user's previous page as well.
I wondered if referer would allow this to work statelessly, but it appears that the referer is not behaving how I'd hoped: the referer header is already set to the current page in the first loader request for the data for the page. So initial load and load-after-mutation appear identical based on referer. I don't know if this is technically a bug, but it's certainly not the behavior I'd expect.
I ended up solving this by doing the pageview tracking in the client. To support recording this in the DB, I implemented a route that just received the POSTs when the location changed.
The documentation for react-router's useLocation actually includes this exact scenario as an example.
From https://reactrouter.com/docs/en/v6/api#uselocation:
function App() {
let location = useLocation();
React.useEffect(() => {
ga('send', 'pageview');
}, [location]);
return (
// ...
);
}
However, that doesn't quite work in remix - the location value is changed after actions (same text value, but presumably different ref value). So I started saving the last location string seen, and then only report a new pageview when the location string value has changed.
So after adding that stateful tracking of the current location, I landed on:
export default function App() {
// ...other setup omitted...
const [lastLocation, setLastLocation] = useState("");
let location = useLocation();
const matches = useMatches();
useEffect(() => {
if (lastLocation == location.pathname) {
return;
}
// there are multiple matches for parent route + root route, this
// will give us the leaf route
const routeMatch = matches.find((m) => m.pathname == location.pathname);
setLastLocation(location.pathname);
fetch("/api/pageview", {
body: JSON.stringify({
url: location.pathname,
// routeMatch.id looks like: "/routes/email/$emailId"
route: routeMatch?.id }),
method: "POST",
}).then((res) => {
if (res.status != 200) {
console.error("could not report pageview:", res);
}
});
}, [location]);
The matches code is not necessary for tracking just raw URLs, but I wanted to extract the route form (eg /emails/$emailId), and matches.id is a close match to that value - I strip "routes/" serverside. Matches docs: https://remix.run/docs/en/v1/api/remix#usematches
Client side pageview tracking is a bit annoying since clients are flaky, but for the current remix behavior I believe this is the only real option.
Did it a different way for routes, remix is funny cuz of the whole parent route thing * so I use a route logger
Beans.io
https://www.npmjs.com/package/beansio

AWS Cognito SignUP with custom Attributes in node js causing error

I am trying to build Signup through a lambda function with AWS user pool where I added a custom attribute called type.
When I am sending a type value with signup, an error "A client attempted to write unauthorized attribute" is populating.
I am using 'amazon-cognito-identity-js' package to save data.
Here is my code snippet
const attributeList = [];
attributeList.push(new AmazonCognitoIdentity.CognitoUserAttribute({Name:"name",Value:user.username}));
attributeList.push(new AmazonCognitoIdentity.CognitoUserAttribute({Name:"custom:type",Value:'asd'}));
attributeList.push(new AmazonCognitoIdentity.CognitoUserAttribute({Name:"gender",Value:user.gender}));
attributeList.push(new AmazonCognitoIdentity.CognitoUserAttribute({Name:"email",Value:user.email}));
userPool.signUp(user.email, user.password, attributeList, null, function(err, result){
if (err) {
return reject(err);
}
return resolve(result);
});**strong text**
After that you added a new attribute, you should select the user attributes this app client can read and write.
Steps:
Go to your Cognito User Pool page
Click on the "App Client" from the left side menu
Click on the "Set attribute read and write permissions"
Make sure you added the necessary(read/write) permissions for the needed attribute
In addition to the above answer, sometimes custom attributes may take time to reflect under clients. Because I noticed it around 15 mins but after 1 hour it was there.

Braintree, How do I delete a users credit card with the nonce from the client?

Server side there is a function to delete a payment method (result = Braintree::PaymentMethod.delete("the_token")) but it takes a payment method token. How do I get the payment methods token with the nonce from the client?
edit: I'm not using the drop in UI. I have a custom list of credit cards the user has (using the Javascript v3 SDK). I want to have a button to delete cards. The JS SDK dosnt give the credit cards token, just a nonce. What is the process for turning the data available to the client into something I can use to delete the card on the server?
edit2: The list of credit cards on the clent side uses the VaultManager from the JavaScript v3 SDK. It returns a fetchPaymentMethodsPayload.
This is the client side code:
_loadPaymentMethods() {
this.paymentService.getBraintreeToken().then( token => {
this.braintreeClient.create({
authorization: token
}, (clientErr, clientInstance) => {
if (clientErr) {
// Handle error in client creation
return;
}
var options = {
client: clientInstance,
};
this.vaultManager.create(options, (err, vaultInstance) => {
if (err) {
console.log(err);
return;
}
vaultInstance.fetchPaymentMethods({ defaultFirst: true }, (err, paymentMethods) => {
paymentMethods.forEach( paymentMethod => {
if(paymentMethod.type == 'CreditCard') {
this.cards.push(paymentMethod);
if(paymentMethod.default) {
this.card = paymentMethod;
}
}
});
});
});
});
});
}
Full disclosure: I work at Braintree. If you have any further questions, feel free to contact support.
If using VaultManager on the client-side to populate your cards, you will not have the functionality to allow a user to delete one of those cards. The reason for this goes back to what you said, that nonces are what's returned on the fetchPaymentMethodsPayload method. VaultManager can populate a nonce that's associated with an already created card, since it's only passing that nonce into a Transaction.sale() call. Since the nonce is populated when the form is rendered, you can not search for that nonce compared to a payment method in the vault, since it will not exist previously and nonces are meant for one time use. This is why nonces aren't passed into PaymentMethod.find() calls.
To accomplish your task you would need to build out custom logic that mimics what Vault Manager does; however, would need to returns the tokens. One way would be as mentioned in my comment: by finding the customer object and grabbing the customer's payment methods, and then pulling out the tokens associated with those payment methods.
I noticed that when you create a payment method with same creds, it won't get duplicated. So it's kinda like "find or create", you can then use that result to get the token and then do a gateway.payment_method.delete( result.payment_method.token )

Parse.com not returning emailVerified value on User object

I've set up my app to enable email verification and the emails come through fine. Trouble is, when I make a call to retrieve a User object, either with Parse.User.current() or by querying by id, the response does not contain the emailVerified field. I can't therefore check if the user is email verified or not.
I've tried this both in client side code and in cloud code with the same result.
You can try this out in your own code with a very simple snippet in the console:
var user = Parse.User.logIn("your_username", "your_password", {
success: function(user) {
console.log(user)
}
});
That field seems to be protected, the only solution I can think of would be to query for where the value is true using some variant of where and check if you get a user back or not. If user is null, they haven't verified their email.

How to handle application errors for json api calls using CakePHP?

I am using CakePHP 2.4.
I want my frontend make api calls to my CakePHP backend using ajax.
Suppose this is to change passwords.
Change password action can throw the following application errors:
old password wrong
new password and confirm new passwords do not match
In my frontend, I have a success callback handler and a error callback handler.
The error callback handler handles all the non 200 request calls such as when I throw NotFoundException or UnAuthorizedAccessException in my action.
The success callback handler handles all the 200 request calls including of course, the above 2 scenarios.
My questions are:
Should I continue to do it this way? Meaning to say, inside all success callback handler, I need to watch out for application success and application error scenarios.
Should I send application errors back with actual HTTP error codes?
if I should do 2, how do I implement this in CakePHP?
Thank you.
Don't use http error codes for system errors like:
old password wrong
new password and confirm new passwords do not match
etc etc...
Now using success handler you can show messages and code flow as:
Create Ajax post or get to submit the form, I am showing you post example
var passwordValue = $('#password').val();
$.post( "/updatePassword", { passwordText: passwordValue })
.done(function(response) {
if(response.status === 'Success'){
// Success msg
// whatever
}else{
// Error msg
// whatever
}
});
json response would like:
{
"status": "Failed/Success",
"message": "old password wrong."
}
Create one function in controller
public function updatePassword() {
$myModel = $this->MyModel->find('first' // YOUR CODE LOGIC);
if($this->request->is('ajax') {
$this->layout=null;
// What else?
echo json_encode($myModel);
exit;
// What else?
}
}
Do something like this, hope it will solve your query!

Resources