Skip to content

Releases: payneteasy/hosted-fields-examples

v0.4.0

Choose a tag to compare

@github-actions github-actions released this 11 Sep 13:19
ca45797

Example integrations of Hosted Fields: the same payment, one server per language.

  • hosted-fields-examples-go_*_linux_*.tar.gz — one static binary with the pages
    embedded, plus deploy/. Needs no runtime.
  • hosted-fields-examples-go_*_darwin_arm64.tar.gz,
    hosted-fields-examples-go_*_windows_amd64.zip — the same binary for trying the
    example on a laptop. No deploy/: the systemd unit and the nginx snippet are for
    a Linux server.
  • hosted-fields-examples-nodejs-express-js_*.tar.gz — bundled server.js with
    public/, views/ and deploy/. Needs Node 20+, no node_modules.
  • hosted-fields-examples-php.tar.gz — the sources with public/, views/ and
    deploy/. Needs PHP 8.4 with curl and openssl, no Composer: php -S for a look,
    PHP-FPM behind nginx for anything else.
  • hosted-fields-examples-python.tar.gz — the sources with tests/, public/,
    views/ and deploy/. Needs Python 3.12+ and, unlike the others, a
    pip install -r requirements.txt into a venv on the target; then gunicorn.
  • hosted-fields-examples-ruby.tar.gz — the sources with test/, public/,
    views/ and deploy/. Needs Ruby 3.1+ and a bundle install on the target, then
    puma. Note that macOS's system Ruby 2.6 will not run it.
  • hosted-fields-examples-java.tar.gz — one jar with the pages inside it, plus
    deploy/. Needs a JRE 21+ and nothing else: java -jar hosted-fields-example-java.jar.
  • hosted-fields-examples-rust_linux_*.tar.gz — one binary with the pages compiled
    in, plus deploy/. Needs a glibc-based Linux and nothing else.
  • hosted-fields-examples-rust_darwin_arm64.tar.gz,
    hosted-fields-examples-rust_windows_amd64.zip — the same binary for trying the
    example on a laptop. No deploy/: the systemd unit and the nginx snippet are for
    a Linux server.
  • hosted-fields-examples-nextjs.tar.gz — the standalone Next.js server with
    public/, .next/ and deploy/. Needs Node 20+, node server.js. The URL
    prefix is compiled in: rebuild from source to change it.

Settings and the RSA key are supplied through the environment, see the README.

What's Changed

  • Add rust-axum-js, an eighth Hosted Fields example by @evsinev in #9

Full Changelog: v0.3.0...v0.4.0

v0.3.0

Choose a tag to compare

@github-actions github-actions released this 11 Sep 12:38

Example integrations of Hosted Fields: the same payment, one server per language.

  • hosted-fields-examples-go_*_linux_*.tar.gz — one static binary with the pages
    embedded, plus deploy/. Needs no runtime.
  • hosted-fields-examples-go_*_darwin_arm64.tar.gz,
    hosted-fields-examples-go_*_windows_amd64.zip — the same binary for trying the
    example on a laptop. No deploy/: the systemd unit and the nginx snippet are for
    a Linux server.
  • hosted-fields-examples-nodejs-express-js_*.tar.gz — bundled server.js with
    public/, views/ and deploy/. Needs Node 20+, no node_modules.
  • hosted-fields-examples-php.tar.gz — the sources with public/, views/ and
    deploy/. Needs PHP 8.4 with curl and openssl, no Composer: php -S for a look,
    PHP-FPM behind nginx for anything else.
  • hosted-fields-examples-python.tar.gz — the sources with tests/, public/,
    views/ and deploy/. Needs Python 3.12+ and, unlike the others, a
    pip install -r requirements.txt into a venv on the target; then gunicorn.
  • hosted-fields-examples-ruby.tar.gz — the sources with test/, public/,
    views/ and deploy/. Needs Ruby 3.1+ and a bundle install on the target, then
    puma. Note that macOS's system Ruby 2.6 will not run it.
  • hosted-fields-examples-java.tar.gz — one jar with the pages inside it, plus
    deploy/. Needs a JRE 21+ and nothing else: java -jar hosted-fields-example-java.jar.
  • hosted-fields-examples-nextjs.tar.gz — the standalone Next.js server with
    public/, .next/ and deploy/. Needs Node 20+, node server.js. The URL
    prefix is compiled in: rebuild from source to change it.

Settings and the RSA key are supplied through the environment, see the README.

What's Changed

  • Add a Java + Spring Boot example by @evsinev in #8

Full Changelog: v0.2.0...v0.3.0

v0.2.0 — six languages, one payment

Choose a tag to compare

@github-actions github-actions released this 11 Sep 07:20

The same Hosted Fields payment, now written six times. v0.1.2 had one example; this release has
one per language, and the point of having more than one is that the interesting half — the card
iframes, the tokenization, the 3DS return — happens in the page, and the server behind it is
interchangeable.

Server Runs with
Go standard library only one static binary, no runtime
Node.js express only Node 20+, no node_modules
PHP no Composer at all PHP 8.4+, php -S or PHP-FPM
Python Flask + cryptography Python 3.12+, python app.py or gunicorn
Ruby Sinatra + puma Ruby 3.1+, ruby app.rb or puma
Next.js React 19, TypeScript Node 20+, the page is a React tree

What is new since v0.1.2

Four more examples. Next.js and React first, then PHP, Python on Flask and Ruby on Sinatra.
Each implements exactly the same seven routes and nothing else, and each documents the traps its
own language sets — PHP's $_POST renaming parameters, Python's urlopen raising on the 4xx that
carries a decline, Sinatra's http_origin protection rejecting the gateway's own 3DS callback.

The browser half lives once. shared/ is the source of truth for the stylesheet, the three
client scripts and the two pages, and scripts/sync-shared.sh copies it into every app. The
copies stay committed, so each directory still runs on its own with no pre-step, and CI fails a
copy that has drifted. Nothing in views/ is templated any more: the only thing any of these
servers generates is config.js, which is what lets the same HTML serve from all six.

Security work across every example. A Content-Security-Policy with no 'unsafe-inline',
naming the SDK origin in script-src, frame-src and connect-src; the 3DS return verified
twice over the same checksum, so a hand-edited URL gets a 403 instead of somebody else's order;
the POST /pay body filtered against a fixed list of eight customer_browser_* keys, so a caller
cannot choose what to charge; a CSPRNG client_orderid; loopback binding by default; and gateway
reply bodies kept out of the logs, which had been carrying the card's last four digits and the
holder's name.

An end-to-end suite. e2e-tests/ starts a fake gateway on one origin — both the API the
servers call and the SDK the browser loads — points every app at it through the environment, and
drives a real browser through the payment: the happy path, the SDK's field-state classes,
validation before tokenizing, a missing ticket, a refused Sale, a decline, the 3DS hop out to the
issuer and back through the signed callback, and forged signatures. Sixty tests, ten per app. The
OAuth signature is verified against a generated public key and the Sale's amount is checked
against the server's own, so a green run means the handshake works rather than that a page
rendered. It is local only — it needs every toolchain and a browser.

Which archive to take

Example integrations of Hosted Fields: the same payment, one server per language.

  • hosted-fields-examples-go_*_linux_*.tar.gz — one static binary with the pages
    embedded, plus deploy/. Needs no runtime.
  • hosted-fields-examples-go_*_darwin_arm64.tar.gz,
    hosted-fields-examples-go_*_windows_amd64.zip — the same binary for trying the
    example on a laptop. No deploy/: the systemd unit and the nginx snippet are for
    a Linux server.
  • hosted-fields-examples-nodejs-express-js_*.tar.gz — bundled server.js with
    public/, views/ and deploy/. Needs Node 20+, no node_modules.
  • hosted-fields-examples-php.tar.gz — the sources with public/, views/ and
    deploy/. Needs PHP 8.4 with curl and openssl, no Composer: php -S for a look,
    PHP-FPM behind nginx for anything else.
  • hosted-fields-examples-python.tar.gz — the sources with tests/, public/,
    views/ and deploy/. Needs Python 3.12+ and, unlike the others, a
    pip install -r requirements.txt into a venv on the target; then gunicorn.
  • hosted-fields-examples-ruby.tar.gz — the sources with test/, public/,
    views/ and deploy/. Needs Ruby 3.1+ and a bundle install on the target, then
    puma. Note that macOS's system Ruby 2.6 will not run it.
  • hosted-fields-examples-nextjs.tar.gz — the standalone Next.js server with
    public/, .next/ and deploy/. Needs Node 20+, node server.js. The URL
    prefix is compiled in: rebuild from source to change it.

Settings and the RSA key are supplied through the environment, see the README.

What's Changed

  • Add a Hosted Fields example on Next.js and React by @evsinev in #1
  • Share the browser half from shared/, and drop templated views by @evsinev in #2
  • Act on the review of eca9448: 3DS return, browser-field allowlist, and the rest by @evsinev in #3
  • test: add a local e2e suite for all three examples by @evsinev in #4
  • Add a PHP example by @evsinev in #5
  • Add a Python (Flask) example by @evsinev in #6
  • Add a Ruby (Sinatra) example by @evsinev in #7

New Contributors

Full Changelog: v0.1.2...v0.2.0

v0.1.2

Choose a tag to compare

@github-actions github-actions released this 11 Sep 02:04

Two merchant integrations of Hosted Fields — the same payment on a Go server and on a Node.js
one, with a browser half that is byte-for-byte identical between them.

See the README for screenshots and
a walk through the code.

Download

Example Platform File
Go Linux x86-64 hosted-fields-examples-go_linux_amd64.tar.gz
Go Linux arm64 hosted-fields-examples-go_linux_arm64.tar.gz
Go macOS Apple silicon hosted-fields-examples-go_darwin_arm64.tar.gz
Go Windows x64 hosted-fields-examples-go_windows_amd64.zip
Node.js any hosted-fields-examples-nodejs-express-js.tar.gz

The Go archives hold one static binary with the pages compiled in and need no runtime. The Node
archive holds a bundled server.js and needs Node 20+, but no npm install.

Verify with sha256sum -c SHA256SUMS.

The Linux archives also carry deploy/ with a systemd unit, an nginx snippet and an environment
template. The macOS and Windows builds do not: those are for trying the example on a laptop.

The macOS binary is not signed or notarised. Downloaded through a browser it arrives quarantined,
and Gatekeeper will refuse to start it until the attribute is cleared:

xattr -d com.apple.quarantine hosted-fields-examples-go

Running one

Every setting comes from the environment and none of them has a default: the app refuses to start
until the gateway URLs, the endpoint, the merchant login, the control key and the RSA private key
are all provided. See deploy/*.env.example in the Linux archive, and the README for what to ask
the gateway for.

Each app mounts everything under a URL prefix, so several of them fit behind one nginx.

Notes

  • The RSA key signs the server calls and never leaves the server. It is not in this repository
    and must not be committed.
  • Field validation messages the payer sees come from the SDK the gateway serves, not from this
    code. To show them in a language of your own, switch on error.code rather than printing
    error.payerMessage.

Changes since v0.1.1

  • Release archives no longer carry the version in their file name, so a link to
    releases/latest/download/<name> keeps working across releases. The directory inside the
    archive still names the version.
  • The README now opens with the two examples, screenshots of both screens, and a download table.

v0.1.1

Choose a tag to compare

@github-actions github-actions released this 11 Sep 01:58

The same two Hosted Fields examples as v0.1.0, now built for a laptop as well as a server.

What the examples show

Card number, expiry and CVV are iframes served by the payment gateway, so the card never reaches
the merchant server. Everything around them is the merchant's: the layout, the light and dark
themes, the result panel — and one of the merchant's own inputs, the cardholder name, sitting
between the gateway's fields in the same visual row. A redirect to a hosted payment page cannot
do that.

Both examples cover the whole flow: the single-use ephemeral ticket, tokenization, the Sale with
hosted_fields_token, status polling, and the 3DS return whose control checksum is verified
before the page renders. The browser half is byte-for-byte identical between the two.

Artefacts

File Contents Requires
hosted-fields-examples-go_v0.1.1_linux_amd64.tar.gz static binary with the pages compiled in, plus deploy/ nothing
hosted-fields-examples-go_v0.1.1_linux_arm64.tar.gz the same, for arm64 nothing
hosted-fields-examples-go_v0.1.1_darwin_arm64.tar.gz the same, for Apple silicon nothing
hosted-fields-examples-go_v0.1.1_windows_amd64.zip the same, as .exe nothing
hosted-fields-examples-nodejs-express-js_v0.1.1.tar.gz bundled server.js with public/, views/ and deploy/ Node 20+, no node_modules

Verify with sha256sum -c SHA256SUMS.

The macOS and Windows builds carry no deploy/: the systemd unit and the nginx snippet are for a
Linux server, and these builds are for trying the example locally.

The macOS binary is not signed or notarised. Downloaded through a browser it arrives quarantined,
and Gatekeeper will refuse to start it until the attribute is cleared:

xattr -d com.apple.quarantine hosted-fields-examples-go

Running one

Every setting comes from the environment and none of them has a default: the app refuses to start
until the gateway URLs, the endpoint, the merchant login, the control key and the RSA private key
are all provided. See deploy/*.env.example in the Linux archive, and the README for what to ask
the gateway for.

Each app mounts everything under a URL prefix, so several of them fit behind one nginx.

Notes

  • The RSA key signs the server calls and never leaves the server. It is not in this repository
    and must not be committed.
  • Field validation messages the payer sees come from the SDK the gateway serves, not from this
    code. To show them in a language of your own, switch on error.code rather than printing
    error.payerMessage.

Changes since v0.1.0

  • Release binaries for Windows x64 and macOS arm64.

v0.1.0

Choose a tag to compare

@github-actions github-actions released this 11 Sep 01:52

First release of the two Hosted Fields integration examples: the same payment implemented on two
servers, with a browser half that is byte-for-byte identical between them.

What the examples show

Card number, expiry and CVV are iframes served by the payment gateway, so the card never reaches
the merchant server. Everything around them is the merchant's: the layout, the light and dark
themes, the result panel — and one of the merchant's own inputs, the cardholder name, sitting
between the gateway's fields in the same visual row. A redirect to a hosted payment page cannot
do that.

Both examples cover the whole flow: the single-use ephemeral ticket, tokenization, the Sale with
hosted_fields_token, status polling, and the 3DS return whose control checksum is verified
before the page renders.

Artefacts

File Contents Requires
hosted-fields-examples-go_v0.1.0_linux_amd64.tar.gz one static binary with the pages compiled in, plus deploy/ nothing
hosted-fields-examples-go_v0.1.0_linux_arm64.tar.gz the same, for arm64 nothing
hosted-fields-examples-nodejs-express-js_v0.1.0.tar.gz bundled server.js with public/, views/ and deploy/ Node 20+, no node_modules

Verify with sha256sum -c SHA256SUMS.

Running one

Every setting comes from the environment and none of them has a default: both apps refuse to
start until the gateway URLs, the endpoint, the merchant login, the control key and the RSA
private key are all provided. See deploy/*.env.example in either archive, and the README for
what to ask the gateway for.

Each app mounts everything under a URL prefix, so several of them fit behind one nginx; deploy/
carries the systemd unit and the nginx snippet.

Notes

  • The RSA key signs the server calls and never leaves the server. It is not in this repository
    and must not be committed.
  • Field validation messages the payer sees come from the SDK the gateway serves, not from this
    code. To show them in a language of your own, switch on error.code rather than printing
    error.payerMessage.