Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <form id='cart' method='post' name='dalenysForm' onsubmit='submitForm(event)'>
  <div class='w1'>
    <p>
      <label>
        Card number
      </label>
      <input class='cc-num' id='cardnum' name='cc-number' oninput='cancel(this);' onkeyup='dalenys.brandDetector.detectBrandsByBin(this.value, function (brands) { manageDefaultBrand(brands) })' placeholder='•••• •••• •••• ••••' required type='tel'>
    </p>
  </div>
  <div class='w2'>
    <p>
      <label>
        Expiry
      </label>
      <input id='cardexp' maxlength='7' name='cc-exp' oninput='cancel(this)' placeholder='MM/YY' required type='tel'>
    </p>
  </div>
  <div class='w2'>
    <p>
      <label>
        CVV
      </label>
      <input id='cardcvv' maxlength='4' name='cc-csc' oninput='cancel(this)' placeholder='•••' required type='tel'>
    </p>
  </div>
  <div class='w1'>
    <p>
      <input type='submit' value='Pay'>
    </p>
  </div>
  <!-- This hidden input will receive the selected brandtoken -->
  <input id='selected-brand' name='selected-brand' type='hidden'>
</form>
              
            
!

CSS

              
                // Dalenys colors

// Primary color
$yellow: #fff756

// Background
$white: #fff
$silver: #ebebfa

// Secondary colors
$coral: #ff7063
$teal: #37dcc8
$light-blue: #8ddaff
$pink: #ffc4d3
$orange: #ffc758

body,
body *
	box-sizing: border-box

body *
	font-family: "Open Sans", "Century Gothic", "Calibri", "Trebuchet MS", Arial, Helvetica, sans-serif
	font-size: 1em
	transition: all 250ms ease-in-out

body
	min-width: 280px
	padding: 20px
	background-color: $silver

.w1
	width: 100%

.w2
	width: 48%
	display: inline-block

form
	width: 100%
	max-width: 240px
	margin: 0 auto
	box-sizing: border-box
	overflow: hidden
	padding: 21px
	background-color: white
	box-shadow: 5px 5px 5px rgba(0,0,0,.2)
	
	label
		font-weight: 600

	p,
	p label
		display: block
		width: 100%
	
	div:not(:last-of-type) p
		margin-bottom: 15px
	
	.w2
		
		&:nth-of-type(3) p
			margin-left: 20%
	
		p
			width: 80%

	input[type=text],
	input[type=tel]
		display: inline-block
		max-width: 100%
		height: 2em
		overflow: hidden
		margin-top: 7px
		padding: 5px 7px 3px 7px
		border: 1px solid darkgrey
		border-radius: 5px
		box-shadow: 0 0 0 1px darkgrey
		transition: all 250ms ease-in-out

		&.valid
			border: 2px solid $teal

		&.invalid
			border: 2px solid $coral

	input[type=submit]
		width: 100%
		max-width: 300px
		margin-top: 7px
		padding: 3px 14px 7px 14px
		border: 0
		border-top: 1px solid rgba(255, 255, 255, 1)
		border-radius: 5px
		background: $teal
		font-size: 1.5em
		font-family: "Titillium Web", Arial, sans-serif
		font-weight: 600
		color: white
		vertical-align: baseline
		cursor: pointer
		transition: all 500ms

		&:hover
			background-color: lighten($teal, 20%)


              
            
!

JS

              
                // Encryption and submition script
(function (window) {
  function createXhrPost(serviceUrl, resolve) {
    let xhr = new XMLHttpRequest();
    xhr.open("POST", serviceUrl, true);
    xhr.setRequestHeader("Content-Type", "application/json");
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4 && xhr.status === 200) {
        var json = JSON.parse(xhr.responseText);
        resolve(json);
      }
    };
    return xhr;
  }

  function fetchPublicKey(serviceUrl, apiKeyId) {
    return new Promise((resolve) => {
      let xhr = createXhrPost(serviceUrl, resolve);
      var data = JSON.stringify({
        apiKeyId: apiKeyId
      });
      xhr.send(data);
    });
  }

  function encryptPlainText(plainText, publicKey) {
    let cryptoSubtle;
    let btoa = window.btoa;
    let atob = window.atob;
    // Fix Apple prefix if needed
    if (window.crypto && !window.crypto.subtle && window.crypto.webkitSubtle) {
      cryptoSubtle = window.crypto.subtle;
    } else if (window.crypto && window.crypto.subtle) {
      cryptoSubtle = window.crypto.subtle;
    }

    if (!cryptoSubtle) {
      throw "No crypto api";
    }

    function getMessageEncoding(message) {
      let enc = new TextEncoder();
      return enc.encode(message);
    }

    function encryptMessage(publicKey, message) {
      let encoded = getMessageEncoding(message);
      return cryptoSubtle.encrypt(
        {
          name: "RSA-OAEP"
        },
        publicKey,
        encoded
      );
    }

    function arrayBufferToBase64(buffer) {
      var binary = "";
      var bytes = new Uint8Array(buffer);
      var len = bytes.byteLength;
      for (var i = 0; i < len; i++) {
        binary += String.fromCharCode(bytes[i]);
      }
      return btoa(binary);
    }

    function strToArrayBuffer(str) {
      const buf = new ArrayBuffer(str.length);
      const bufView = new Uint8Array(buf);
      for (let i = 0, strLen = str.length; i < strLen; i++) {
        bufView[i] = str.charCodeAt(i);
      }
      return buf;
    }

    function importRsaKey(pem) {
      // base64 decode the string to get the binary data
      const binaryDerString = atob(pem);
      // convert from a binary string to an ArrayBuffer
      const binaryDer = strToArrayBuffer(binaryDerString);
      return cryptoSubtle.importKey(
        "spki",
        binaryDer,
        {
          name: "RSA-OAEP",
          hash: "SHA-1"
        },
        true,
        ["encrypt"]
      );
    }

    return importRsaKey(publicKey)
      .then((binaryPublicKey) => {
        return encryptMessage(binaryPublicKey, plainText);
      })
      .then((encryptedBytes) => {
        return arrayBufferToBase64(encryptedBytes);
      });
  }

  /**
	* serviceUrl: form post url
	* postPayload: expected content {
	*     "ENCRYPTEDDATA": base64Message,
	*     "ENCRYPTIONKEYID": encryptionKeyId,
	*     "APIKEYID": apiKeyId
	* };
	* */
  function postEncryptedData(serviceUrl, postPayload) {
    console.log(postPayload);
    return fetch(serviceUrl, {
      method: "POST",
      headers: {
        Accept: "application/json",
        "Content-Type": "application/json"
      },
      body: JSON.stringify(postPayload)
    }).then(async function (response) {
      return await response.json();
    }).catch(error => { 
      return {"error": error};
    });
  }

  async function preparePayload(cseServiceUrl, apiKeyId, cardInfo) {
    let plainText = JSON.stringify(cardInfo);
    let rsaPublicKey = await cseLib.fetchPublicKey(cseServiceUrl, apiKeyId);
    console.log(rsaPublicKey);
    let encryptedMsd = await cseLib.encryptPlainText(
      plainText,
      rsaPublicKey.encryptionPublicKey
    );
    return {
      ENCRYPTEDDATA: encryptedMsd,
      ENCRYPTIONKEYID: rsaPublicKey.encryptionKeyId,
      APIKEYID: apiKeyId
    };
  }

  window.cseLib = {
    fetchPublicKey: fetchPublicKey,
    encryptPlainText: encryptPlainText,
    preparePayload: preparePayload,
    postEncryptedData: postEncryptedData
  };
})(window);

const cseLib = window.cseLib;

// Form submission function

function submitForm(e) {
  let apiKeyId = "62acc7fe-3496-434d-b24e-b14ebf296340";
  let cseServiceUrl = "https://sandbox-payment.dlns.io/cseKeys";
  let postFormUrl = "https://secure-test.dalenys.com/hosted-fields/service/tokenize";

  e.preventDefault();
	
  let jsonData = {
		CARDCODE: document.getElementById('cardnum').value.replaceAll(' ', ''),
		CARDVALIDITYDATE: document.getElementById('cardexp').value.replace('/', '-').replaceAll(' ', ''),
		CARDCVV: document.getElementById('cardcvv').value,
		SELECTEDBRAND: document.querySelector('#selected-brand').value
	};

  cseLib.preparePayload(cseServiceUrl, apiKeyId, jsonData).then(
    (postPayLoad) => {
      cseLib.postEncryptedData(postFormUrl, postPayLoad).then((response) => {
        if (response.EXECCODE !== '0000') {
          alert("Error : " + response.MESSAGE);
          return;
        }
        prompt("Generated token:", response.HFTOKEN);
      });
    },
    (reason) => {
      console.error(reason);
    }
  );
}

// jQuery.payment
jQuery(function($) {
	
	$('#cardnum').payment('formatCardNumber');
	$('#cardexp').payment('formatCardExpiry');
	$('#cardcvv').payment('formatCardCVC');

	$('form').submit(function(e) {
		e.preventDefault();
		
		const cardNumField = document.querySelector('#cardnum');
		const cardExpField = document.querySelector('#cardexp');
		const cardCvvField = document.querySelector('#cardcvv');
		const cardType = $.payment.cardType($('#cardnum').val());
		
		let validCardNum = $.payment.validateCardNumber($('#cardnum').val());
		!validCardNum ? cardNumField.classList.add('invalid') : cardNumField.classList.add('valid');
		
		let validCardExp = $.payment.validateCardExpiry($('#cardexp').payment('cardExpiryVal'));
		!validCardExp ? cardExpField.classList.add('invalid') : cardExpField.classList.add('valid');
		
		let validCardCvv = $.payment.validateCardCVC($('#cardcvv').val(), cardType);
		!validCardCvv ? cardCvvField.classList.add('invalid') : cardCvvField.classList.add('valid');
		
	});

});

// Input fields style reset
function cancel(e)
{
	e.classList.remove('valid');
	e.classList.remove('invalid');
}

// Manages the selected default brand
function manageDefaultBrand(brands)
{
	if(brands != '' && brands != 'null') {
		const defaultBrand = brands[0]['brand']
		document.querySelector('#selected-brand').value = defaultBrand;
	}
}
              
            
!
999px

Console