Make
checkout
great again

Адрес доставки
Контакты
Платежная карта
Адрес доставки
Контакты
Платежная карта
<input
    autocomplete="street-address"
    name="street-address"
    type="text"
    placeholder="Адрес" />
<input
    autocomplete="address-level2"
    name="address-level2"
    type="text"
    placeholder="Номер карты" />
<input
    autocomplete="cc-number"
    name="cc-number"
    type="text"
    placeholder="Город" />

Credential Management Level 1

QRCODE cо ссылкой

https://w3.org/TR/credential-management-1/

Web Authentication: An API for accessing Public Key Credentials Level 1
QRCODE cо ссылкой

https://w3.org/TR/webpayments-overview/

if (window.PasswordCredential) {
    //…
}
navigator.credentials.get({
        password: true,
        mediation: 'optional',
    }).then({…});
  • required
  • optional
  • silent
navigator
    .credentials
        .preventSilentAccess();
navigator.credentials.get({…})
    .then(credential => {
        if (credential) {
            // credential.password
            // credential.id
        }
    });

Web payments working group

QRCODE cо ссылкой

https://www.w3.org/Payments/WG

  • methodData
  • details
  • options
<button id="pay">Купить</button >
const methodData = [{
    supportedMethods: "basic-card",
}];
const methodData = [{
    supportedMethods: "https://apple.com/apple-pay",
    data: {
        version: 3,
        merchantIdentifier: "merchant.com.example",
        merchantCapabilities: [
            "supports3DS",
            "supportsCredit",
            "supportsDebit"],
        supportedNetworks: ["amex", "discover", "masterCard", "visa"],
        countryCode: "US",
    },
}];
const details = {
  id: "order-1",
  displayItems: [{
    label: "Вотлшебный Говорящий Медведь-Проститутка",
    amount: {
      currency: "USD",
      value: "5.00"
    },
  },
{
  label: "Cвинка",
  amount: {
    currency: "USD",
    value: "3.00"
  },
}],
  total: {
    label: "Всего",
    amount: {
      currency: "USD",
      value: "8.00"
    },
  },
};
const options = {
  requestPayerEmail: true,
  requestPayerName: true,
  requestPayerPhone: true,
  requestShipping: false,
};
let request = new PaymentRequest(
    methodData,
    details,
    options);
const button = document.getElementById('pay');
button.addEventListener('click', pay);
const pay = async function () {
    const response = await request.show();
    await response.complete(validate());
    …
};
{
    details: {},
    methodName: "basic-card",
    payerEmail: "thesilentimp@gmail.com",
    payerName: "Anton",
    payerPhone: "+380502773882",
    requestId: "order-1",
    shippingAddress: null,
    shippingOption: null,
}

It's fine!

$ 99.99
  • Merchant ID
  • Merchant Identity Certificate
  • Register and verify your domain
request.onmerchantvalidation =
    async event => { … }
const response = await fetch('/validate', {
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json'
  },
  method: 'POST',
  json: true,
  body: JSON.stringify({ validationURL: event.validationURL }),
});
if (response.ok) {
  return event.complete(response.json());
}
app.post(
    '/validate',
    async (req, res, next) => {…}
);
const certPath = resolve(__dirname, 'apple.cer');
const keyPath = resolve(__dirname, 'apple.cer');
const cert = fs.readFileSync(certPath);
const key = fs.readFileSync(keyPath);
const { validationURL } = req.body;
const appleURL =
    url.parse(`${validationURL}/paymentSession`);
const options = {
  key,
  cert,
  hostname: appleURL.hostname,
  path: appleURL.path,
  method: 'POST',
  "headers": {
    "Content-Type": "application/json",
  },
  json: true,
};
const POSTJSONString = JSON.stringify({
  merchantIdentifier: 'merchant.moto.courses',
  displayName: 'Moto Courses',
  initiative: 'web',
  initiativeContext: 'moto.courses',
});
const HTTPBody = Buffer.from(POSTJSONString, "utf8");
import https from 'https';
…
const request = https.request(
    options,
    function(responce) {…}
);
request.on('error', err => {…});
request.write(HTTPBody);
request.end();
responce.on('end', () => {
    res.send(JSON.stringify(response));
});
Error: error:0906D06C:PEM routines: PEM_read_bio:no start line
$ openssl
    req -sha256 -nodes -newkey rsa:2048
    -keyout applepaytls.key
    -out applepaytls.csr
$ openssl
    x509 -inform der
    -in certFromApple.cer
    -out merchant_identity.pem
const certPath =
    resolve(__dirname, 'merchant_identity.pem');
const keyPath =
    resolve(__dirname, 'applepaytls.key');
https://qp.payhub.com.ua/#/payment/13976
    ?iframe=qp
    &EMAIL=test@test.com
    &FIO=Иванов
    &PH=0501111111
    &amount=1000
    &autoCheck
<script src="https://js.stripe.com/v3/">

if (Stripe !== undefined) {
    const stripe = Stripe('pk_cQQjittH');
    // …
}
const items = [{
    amount: 4000
    , label: 'maintenance.course'
}];
const paymentRequest = stripe.paymentRequest({
  country: 'US'
  , currency: 'uah'
  , requestPayerName: true
  , requestPayerEmail: true
  , requestPayerPhone: true
  , requestShipping: false
  , displayItems: items
  , total: {
    label: 'Мастеркласс'
    , amount: 4000
  }});
const elements = stripe.elements();
  const prButton = elements.create(
    'paymentRequestButton',
    { paymentRequest }
  );
const response = await fetch('/skus');
const sku = await response.json();
const stripe = require('stripe')('sku_CckkusdfZ');
stripe.skus.retrieve('sku_JENMndnU3jS',
  (error, sku) => {
    if (error === null) {
      res.send(JSON.stringify(sku)).status(200).end();
    } else {
      res.status(error.statusCode, error.message)
        .end(http.STATUS_CODES[error.statusCode]);
    }});
const result = await paymentRequest.canMakePayment();
if (result) {
    prButton.mount('#payment-request-button');
} else {
    // …
}
paymentRequest.on('token', async (event) => {
    const {
        token,
        payerPhone:phone,
        payerName:name,
        payerEmail:email,
    } = event;
    const response = await fetch('/order', {
        method: 'POST'
        , body: JSON.stringify({ token, sku, phone, email, name })
        , headers: {'content-type': 'application/json'}
    });
});
const order = await stripe.orders.create({
  email,
  , currency: sku.currency
  , items: [{
      type: 'sku'
      , parent: sku.id
    }]});

const paidOrder = await stripe.orders.pay(order.id, {
  source: (token.livemode ? token.id : 'tok_visa'),
});

const fulfilledOrder = await stripe.orders
    .update(order.id, {
      status: 'fulfilled'
    });

res.send(JSON.stringify(fulfilledOrder))
    .status(200).end();

Антон Немцев

skype: ravencry

QRCODE cо ссылкой на доклад

https://goo.gl/y3lvfc