Slide 1

Slide 1 text

BUILDING HOSTED FIELDS Jeff Carpenter - @jcarp Engineer at Braintree

Slide 2

Slide 2 text

DISCLAIMER This talk is: > About the front-end, not Node.js > In English, not in ೔ຊޠ

Slide 3

Slide 3 text

> େֶͷ࣌ʹͪΐͬͱ೔ຊޠΛษڧ͠·ͨ͠ > ೔ຊେ޷͖ > Ͷ͋ͭ͜Ί͕޷͖Ͱ͔͢ʁ

Slide 4

Slide 4 text

Braintree helps companies like Uber, Airbnb, GitHub, and Dropbox accept credit cards, PayPal, Venmo, Bitcoin, Apple Pay, and Android Pay

Slide 5

Slide 5 text

CREDIT CARD FORMS

Slide 6

Slide 6 text

Some background...

Slide 7

Slide 7 text

PCI DSS A set of rules that companies accepting credit cards must follow

Slide 8

Slide 8 text

2015 - PCI DSS VERSION 3 Credit card information must now be entered on the domain of your payment provider

Slide 9

Slide 9 text

Slide 10

Slide 10 text

DROP-IN UI

Slide 11

Slide 11 text

DROP-IN UI: !

Slide 12

Slide 12 text

But what if the Drop-in UI doesn't match the style of your checkout form?

Slide 13

Slide 13 text

HOSTED FIELDS

Slide 14

Slide 14 text

HOSTED FIELDS: A NEW INTEGRATION FOR MATCHING THE STYLE OF YOUR CHECKOUT FORM AND BEING PCI COMPLIANT

Slide 15

Slide 15 text

BUILDING HOSTED FIELDS

Slide 16

Slide 16 text

We decided that the only way to give merchants the most customizability was to make each input an iframe

Slide 17

Slide 17 text

BEFORE

Slide 18

Slide 18 text

AFTER

Slide 19

Slide 19 text

BEFORE

Slide 20

Slide 20 text

AFTER

Slide 21

Slide 21 text

How does the merchant style the iframes?

Slide 22

Slide 22 text

STYLING CONSIDERATIONS > Guard against XSS > Minimal change to existing CSS workflow > Easy and intuitive

Slide 23

Slide 23 text

APPROACHES WE CONSIDERED

Slide 24

Slide 24 text

INFER STYLES FROM CONATINER > ! No extra work for the merchant > " Requires watching for updates > " Black box to the merchant

Slide 25

Slide 25 text

applyIf styles: [ { // base styles color: 'green', fontFamily: 'Helvetica' }, { // setting styles for focused elements applyIf: function(inputElement) { return inputElement.isFocused; }, color: 'limegreen' }, { // media queries applyIf: function() { return window.innerWidth > 600; }, fontSize: '16pt' } ]

Slide 26

Slide 26 text

applyIf > ! Not constrained to CSS rules > ! Anything you can write in JS works > ! Supports media queries > " Not intuitive > " Requires inter-frame communication for every CSS change

Slide 27

Slide 27 text

CSS IN A SCRIPT TAG input { font-size: 16pt; color: #ccc; } > ! Intuitive > " Requires parsing CSS in JS

Slide 28

Slide 28 text

No content

Slide 29

Slide 29 text

stylesheet.insertRule { 'input': { 'font-size': '16pt' } } Becomes: stylesheet.insertRule('input { font-size: 16pt; }');

Slide 30

Slide 30 text

stylesheet.insertRule > ! Close to CSS syntax > ! Supports media queries > ! Makes XSS more difficult { 'input': { 'font-size': '16pt' } }

Slide 31

Slide 31 text

INNER VS. OUTER STYLES

Slide 32

Slide 32 text

OUTER STYLES: APPLIED TO THE CONTAINER Like border or background-color

Slide 33

Slide 33 text

OUTER STYLES: APPLIED TO THE CONTAINER
#card-number { background-color: white; }

Slide 34

Slide 34 text

INNER STYLES: FOR THE TEXT Like color or font-size

Slide 35

Slide 35 text

INNER STYLES: FOR THE TEXT braintree.setup('client-token', 'custom', { hostedFields: { styles: { 'input': { 'font-size': '16pt' }, ':focus': { 'color': '#ddd' } } } });

Slide 36

Slide 36 text

MEDIA QUERIES ALSO SUPPORTED braintree.setup('client-token', 'custom', { hostedFields: { styles: { '@media any': { 'input': { /*...*/ } } } } });

Slide 37

Slide 37 text

SHOULD WE USE A COOL COMPILE-TO-JS LANGUAGE?

Slide 38

Slide 38 text

WE EVALUATED USING TYPESCRIPT function sum(a: number, b: number): number { return a + b; } > Easy if your entire project is TypeScript > Must write type declarations for all plain JS

Slide 39

Slide 39 text

WE ALSO EVALUATED USING BABEL FOR ES6 > Vanilla JS™ on the merchant page > Babel/ES6 inside iframes

Slide 40

Slide 40 text

WE ALSO EVALUATED JEST > Front-end testing framework from Facebook > Based on jsdom (JS implementation of the DOM) > Auto-mocks everything by default const API = require('api'); console.log(API); // => {}

Slide 41

Slide 41 text

ENDED UP USING KARMA, PHANTOMJS, AND MOCHA FOR TESTING

Slide 42

Slide 42 text

MERCHANT CAN NO LONGER ACCESS CREDIT CARD NUMBER

Slide 43

Slide 43 text

HOW DOES VALIDATION WORK?

Slide 44

Slide 44 text

We thought of ways to expose information merchants need from the form, like events and validation

Slide 45

Slide 45 text

EVENT LIFECYCLE hostedFields: { onFieldEvent: function (event) { if (event.type === "focus") { // Handle focus } else if (event.type === "blur") { // Handle blur } else if (event.type === "fieldStateChange") { // Handle a change in validation or card type console.log(event.isValid); // true|false if (event.card) { console.log(event.card.type); // visa|master-card|american-express|diners-club|discover|jcb|unionpay|maestro } } } }

Slide 46

Slide 46 text

INCREMENTAL VALIDATION

Slide 47

Slide 47 text

VALIDATING AS YOU TYPE 3 => {isValid: false, isPotentiallyValid: true, type: null} 37 => {isValid: false, isPotentiallyValid: true, type: 'Amex'} 373 => {isValid: false, isPotentiallyValid: true, type: 'Amex'} 3736 => {isValid: false, isPotentiallyValid: false, type: null} 4111111111111111 => {isValid: true, isPotentiallyValid: true, type: 'Visa'}

Slide 48

Slide 48 text

No content

Slide 49

Slide 49 text

HOW DO THE IFRAMES TALK TO EACH OTHER?

Slide 50

Slide 50 text

FRAMEBUS bus.on('message', function (data) { console.log(data); // => '͜Μʹͪ͸'; }); bus.emit('message', '͜Μʹͪ͸');

Slide 51

Slide 51 text

No content

Slide 52

Slide 52 text

TEAM DYNAMICS > 4 programmers (2 pairs) > Pair programming 100% of the time > Rotate pairs every few days

Slide 53

Slide 53 text

BONOBOS: HOSTED FIELDS + REACT.JS

Slide 54

Slide 54 text

No content

Slide 55

Slide 55 text

Huge thanks to Kyle, Mrak, Evan, Rohit, Trevor, and everyone else who worked on Hosted Fields

Slide 56

Slide 56 text

No content

Slide 57

Slide 57 text

Slides and links to everything: https://github.com/jeffcarp/building-hosted-fields

Slide 58

Slide 58 text

Let's talk about JS or payments - @jcarp Thank you!! ͋Γ͕ͱ͏͍͟͝·͢ʂ