Stripe - how call confirmCardSetup without cardElement? - stripe-payments

I'm using my own form for the credit card creedentials.
I was trying to follow the instructions here https://laravel.com/docs/7.x/billing#storing-payment-methods
Based on the Stripe's instructions, you can pass cardElement or Card object. I would like to create the Card object myself, but I can't find which info does that object have:
cardButton.addEventListener('click', async (e) => {
const { setupIntent, error } = await stripe.confirmCardSetup(
clientSecret, {
payment_method: {
card: cardElement, //or Card object
billing_details: { name: cardHolderName.value }
}
}
);
if (error) {
// Display "error.message" to the user...
} else {
// The card has been verified successfully...
}
});
Not clear if I should simply use specific ids in my inputs, and then simply pass the form there, but I can't find that information.

You can see the details of the Card object here, which looks like this:
card: {
number: '4242424242424242',
exp_year: '2024',
exp_month: '02',
cvc: '123',
}
However, using Elements is strongly recommended.
It's important to be aware of the PCI compliance implications of this. It is your responsibility to make sure your implementation is compliant, and you will be required to provide additional documentation for your business.

Related

Iterate over an array of objects and mint an NFT on NEAR protocol

I have this method:
#[payable]
pub fn nft_mint(&mut self, nft_list: Vec<Nft>) -> Vec<Token> {
let mut t_result: Vec<Token> = Vec::new();
for nft in nft_list {
let s = self.tokens.mint(nft.token_id, nft.receiver_id, Some(nft.token_metadata));
t_result.push(s);
}
return t_result;
}
and from frontend:
let token_list = [{
token_id: nanoid(),
receiver_id: window.accountId,
token_metadata: { id: i, title: "test", myNumber: 123, price: 10, url: "http://..."}
}];
window.contract
.nft_mint({ nft_list: token_list })
.then((res) => {
console.log("Success", res);
}).catch(err => {
console.log("Error", err);
});
after deploying and initializing the contract, when I try to call the method, even that I have enough NEAR (on testnet 190NEAR) I get this error:
{
"type": "action",
"error": {
"type": "functionCallError",
"error": {
"type": "executionError",
"error": "Smart contract panicked: panicked at 'Must attach 6290000000000000000000
yoctoNEAR to cover storage',
/home/HideThePainHarold/.cargo/registry/src/github.com-1ecass99db9ec823/near-contract-standards-3.2.0/src/non_fungible_token/utils.rs:33:5"
}
}
}
and how would I make the sender pay for the actual minting (not just gas fees)?
Storing information on-chain costs $NEAR. The smart contract chargers users who mint NFTs for the $NEAR that it costs. At the time of writing this, it costs 1 $NEAR for every 100kb of data stored.
If the smart contract didn't charge the user and minting was open to the public (not allowlisted), the contract could be subject to a storage attack.
All you need to do to fix your problem is attach $NEAR to the call.
To gain a better understanding as to what's happening behind the scenes, there's a great section of the NFT zero to hero tutorial that talks about minting NFTs.

Contentful NodeJs SDK, Client.getEntries | Load nested ContentType fields

I have the following structure
User {
image: Asset
...
}
Comment {
author: User
...
}
BlogArticle {
slug: Text
author: User
comments: Comment[]
}
When I pull entries with the following method
const articles = await client.getEntries({ content_type: "BlogArticle" })
console.log(articles.entries.fields.comments)
I only get the sys property for the author
[
{
author: {
sys: {
...
}
fields ??????
}
}
]
PS: This is the case for all types that come in second level of nesting
I checked the docs and the apis but with no luck
Any help ?
I created a similar content model and was able to get the fields of the Author successfully. One thing you can do is use the include parameter. With the include parameter, your code should look as follow:
const articles = await client.getEntries({ content_type: "BlogArticle", include: 2 })
console.log(articles.entries.fields.comments)
You can learn more about it here

YubiKey + Webauth: userHandle is always null

When I authenticate using WebAuthn and my YubiKey, the response.userHandle property is always null. That is the user id and displayName that I registered the credential with does not get returned. Is this becuase of something I am doing wrong during the registration / authentication process:
async function register() {
const publicKeyCredentialCreationOptions = {
challenge: Uint8Array.from("this-is-a-test", (c) => c.charCodeAt(0)),
rp: {
name: "Webauthn Test",
id: "localhost",
},
user: {
id: Uint8Array.from("a1b2c3d4e5f6", (c) => c.charCodeAt(0)),
name: "just-a-test",
displayName: "MrUser",
},
pubKeyCredParams: [{ alg: -7, type: "public-key" }],
authenticatorSelection: {
authenticatorAttachment: "cross-platform",
},
timeout: 60000,
attestation: "direct",
};
const credential = await navigator.credentials.create({
publicKey: publicKeyCredentialCreationOptions,
});
}
This is the code I use to authenticate:
async function authenticate() {
const publicKeyCredentialRequestOptions = {
challenge: Uint8Array.from("test", (c) => c.charCodeAt(0)),
allowCredentials: [
{
id: credentialId,
type: "public-key",
transports: ["usb", "ble", "nfc"],
},
],
timeout: 60000,
};
const assertion = await navigator.credentials.get({
publicKey: publicKeyCredentialRequestOptions,
});
console.log(assertion);
}
What I end up with is:
{
rawId: ArrayBuffer(64),
id: "U-nitqhlORmmdltp7TLO3i18KNoWsSebFyrtc3OIRvcktvwlz-dJZCA1_1gxXrNHzqReU7xGAHdfVP75N2aJSw",
response: {
authenticatorData: ArrayBuffer(37) {}
clientDataJSON: ArrayBuffer(101) {}
signature: ArrayBuffer(71) {}
userHandle: null
}
type: "public-key"
}
As you can see: userHandle is null. Can anyone tell me why?
The userHandle can be null depending on which type of WebAuthn credential the relying party requested to be created.
The default WebAuthn behavior will create a non-discoverable credential and the userHandle returned in the assertion will be null. No data is stored on the authenticator for this type of credential so there is nothing to return.
To create a WebAuthn client-side discoverable credential, a.k.a. resident key, you must set the requireResidentKey member to true. This will store credential data on the authenticator and will return the userHandle in the assertion. Refer to the AuthenticatorSelectionCriteria in the W3C WebAuthn spec for the details.
Here is an example:
authenticatorSelection: {
authenticatorAttachment: "cross-platform",
requireResidentKey: true
},
See Yubico's WebAuthn Dev Guide to learn more about resident keys and the userHandle.
I have tried to understand what you are dealing with. I played with https://u2f.bin.coffee/ to get a feeling for the data flow. As a result of authentication I have received a response like:
Got response:
{
"keyHandle": "F74UNCdNv1d43zw7hqxYgkjR3O6dcevopiSb3jrcB3rMFRUM486LbsVExJD0R3ESC5MCb3zeFGdxvS3ksZ7sCA",
"clientData": "eyJ0eXAiOiJuYXZpZ2F0b3IuaWQuZ2V0QXNzZXJ0aW9uIiwiY2hhbGxlbmdlIjoiTXpPTjhXRHpvSDlhZHU0bTk5YWF0ZyIsIm9yaWdpbiI6Imh0dHBzOi8vdTJmLmJpbi5jb2ZmZWUiLCJjcm9zc09yaWdpbiI6ZmFsc2UsImV4dHJhX2tleXNfbWF5X2JlX2FkZGVkX2hlcmUiOiJkbyBub3QgY29tcGFyZSBjbGllbnREYXRhSlNPTiBhZ2FpbnN0IGEgdGVtcGxhdGUuIFNlZSBodHRwczovL2dvby5nbC95YWJQZXgifQ",
"signatureData": "AQAAAAUwRAIgEqi5POKKUraU97W3vbfn34DSWqXwiZwEi5g9QPPtS6MCIBbLYW1_b3aRjHQivSRZQUAfBobx6CZnQ0_VVvuu1LJJ"
}
Now I assume the keyHandle here is your authenticatorData, the clientData here is your clientDataJSON and that signatureData is your signature. Whatever this userHandle is you are missing, it does not seem to be required.
Look at this picture too:
If the userHandle were the handle, the authentication would not work with a null value. But it does if I understand your example correctly.
So I believe you are dealing with a field that is reserved for future purposes or other flows than that which you need at the moment.

How to customize the payment method in payment intent example in stripe

I am trying to follow the example shown in the following link https://stripe.com/docs/payments/accept-a-payment.
I have the following code in the client side
var cardNumber = elements.create('cardNumber', {
placeholder:'',
style: style
});
var cardexpiry = elements.create('cardExpiry',{
placeholder:'',
style:style
});
var cardCVV = elements.create('cardCvc',{
placeholder:'',
style:style
});
// Add an instance of the card Element into the `card-element` <div>.
cardNumber.mount('#card-element');
cardexpiry.mount("#card-expiry")
cardCVV.mount("#card-cvv")
instead of this
var card = elements.create("card", { style: style });
card.mount("#card-element");
Because the I wanted to some UI manipulation. According to the code posted in the link
I should do the following
var submitButton = document.getElementById('submit');
submitButton.addEventListener('click', function(ev) {
stripe.confirmCardPayment(clientSecret, {
payment_method: {card: card}
}).then(function(result) {
if (result.error) {
// Show error to your customer (e.g., insufficient funds)
console.log(result.error.message);
} else {
// The payment has been processed!
if (result.paymentIntent.status === 'succeeded') {
// Show a success message to your customer
// There's a risk of the customer closing the window before callback
// execution. Set up a webhook or plugin to listen for the
// payment_intent.succeeded event that handles any business critical
// post-payment actions.
}
}
});
});
However in the example above in the payment_method the card object is passed, which is not the case in my code. How can I pass my card number and exp/date as well CVC separately in the stripe.confirmCardPayment(clientSecret, {
payment_method: {card: card}
There was a similar question about how to call stripe.createToken() when you aren't using a card element.
According to the Stripe documentation for createToken:
The cardNumber Element you wish to tokenize data from. If applicable, the Element pulls data from other elements you’ve created on the same instance of Elements to tokenize—you only need to supply one Element as the parameter.
Now, for this case in particular, the section for confirmCardPayment says:
Use stripe.confirmCardPayment with payment data from an Element by passing a card or cardNumber Element as payment_method[card] in the data argument.
Basically you just have to pass the cardNumber element to payment_method["card"] and it will pull the data from the other elements you’ve created.
...
stripe.confirmCardPayment(clientSecret, {
payment_method: {card: cardNumber}
})
...
I ended up using this code
var stripe = Stripe('#YOUR KEY');
var elements = stripe.elements();
/// STYLE HERE
var style = {
base: {
fontSize: '16px',
color: "#32325d",
'::placeholder': {
color: '#CFD7E0',
fontSize: '12px'
}
}
};
// Create an instance of the card Element.
var card = elements.create('card', {
hidePostalCode: true,
placeholder: '',
style: style,
});
card.mount('#card-element');
card.addEventListener('change', function (event) {
var displayError = document.getElementById('card-errors');
if (event.error) {
displayError.textContent = '';
} else {
displayError.textContent = '';
}
});

Pass CVC to stripe.createPaymentMethod JS?

I need a separate input for CVC and Expiry, so I have created 3 Stripe Elements:
let elements = stripe.elements();
let cardNumber = elements.create('cardNumber');
cardNumber.mount('#card-number');
let cardExpiry = elements.create('cardExpiry');
cardExpiry.mount('#card-expiry');
let cardCvc = elements.create('cardCvc');
cardCvc.mount('#card-cvc');
...
Stripe Docs only mention about how to pass card or cardNumber Element to PaymentMethod, but how do I pass cardExpiry and cardCvc?
function paymentMethod() {
return stripe.createPaymentMethod({
type: 'card',
card: cardNumber,
billing_details: {
name: userName,
email: userEmail,
},
}).then(function(result) {
// code
});
}
Stripe Docs only mention that
Stripe.js methods automatically use all the different elements on your page under the hood, so you don't need to pass CVC and Expiry elements manually, createPaymentMethod will do that automatically under the hood for you.

Resources