Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

magensa-bluetooth

Package Overview
Dependencies
Maintainers
1
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

magensa-bluetooth

Interface between Chromium browser and MagTek devices

  • 1.1.2
  • next
  • latest
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
8
increased by700%
Maintainers
1
Weekly downloads
 
Created
Source

magensa-bluetooth

npm version
Interface between MagTek® Bluetooth devices, and Chromium based browsers.

Browser Support

ChromeOperaEdgeSamsung
Latest ✔Latest ✔Latest ✔Latest ✔

This library utilizes WebBluetooth API.
WebBluetooth compatibility information can be found at the implementation status README and caniuse.com.
Additionally, we have put together detailed compatibility information, as well as initial pair instructions, in our Playground.

Installation

NPM:

npm install magensa-bluetooth

Yarn:

yarn add magensa-bluetooth

Grab your MagTek® device and Get Started

In order to utilize this library, you must have a MagTek® device with Bluetooth capabilities. Currently the compatible devies are

If you have a device, and would like to see this library in action, please head over to our Playground.
If you would like to purchase a device, please head over to the MagTek Store.

Usage

The implementation below will prompt a pair window displaying all MagTek devices in range. Once the end user selects the appropriate device from the pair window, the response to this function call will be a device object.
The device pair window is part of the WebBluetooth API, and is currently mandatory (no bypass exists as of this time).

import { scanForDevices } from 'magensa-bluetooth';

function exampleCallback(dataObj) {
    console.log("data send from device", dataObj);
};

//Using Promises:
scanForDevices(exampleCallback).then( connectedDevice => 
    /*
        'connectedDevice', in this example, is a return object containing device information  
        and the interface needed to interact with your paired device.  
        See Device Object under the 'Return Objects' header below, for more details.  

        Store this device object in a manner that makes sense for your application.  
        This example saves the object to a global namespace:  
    */
    window.MagTekDevice = connectedDevice;
    /*
        Now the device can be acccessed globally. 
        if you wish to limit the scope of the connected device - please do so at your discretion.
    */
).catch(err => console.error(err));

//Using async/await:
const examplePairing = async() => {
    try {
        const connectedDevice = await scanForDevices(exampleCallback);
        /*  
            Now 'connectedDevice' contains the device object.  
            Store this in a manner that makes sense for your application.  
        */
        window.MagTekDevice = connectedDevice;
    }
    catch(error) {
        console.error(error);
    }
}

The callback function(s) provided are the only way the paired device can send data to the host.

  • All data returned to the provided callbacks will be of type object. Please see Return Objects section for more information.
  • Please see the Callbacks section below for more information about user provided callback functions.
  • For single page applications, please ensure that the callback function(s) provided is always "mounted" to receive data.

Device Interface API

All methods are asynchronous (isDeviceOpen being the only synchronous exception). Be sure to catch all exceptions - as any error occured upon invocation of these functions will throw an Error.

FunctionInput ParametersOutputNotes
scanForDevicescallbacks [,deviceName[, deviceType]]Device ObjectPlease refer to callback examples below. Device name is optional. Device type is optional and supports special cases. Available types listed here
startTransactionemvOptionsSuccessInitiates EMV transaction. emvOptions is optional - any property supplied will override the default
cancelTransactionnoneSuccessCancel any transaction that is in progress.
openDevicenoneSuccessOpens paired device to receive commands
closeDevicenoneSuccessClears session (when applicable) and closes device safely
clearSessionNumber (optional)SuccessRemoves previous card data from device's volatile memory. Only PinPad devices have session. Optional input is "Bitmap slot number" for displaying custom display templates
deviceInfononeDevice InformationBe aware this call will clear device session prior to returning device information
requestCardSwipeswipeOptionsSuccessswipeOptions is optional. Any property supplied will override the default
isDeviceOpennoneBooleansynchronous function that returns device's open status
sendCommandHex String or Array<Number>objectsend raw command to device. Output will be an object (if the response has a parser) or array (if returning raw device response)
forceDisconnectnonevoidSever device connection, in the case that the device becomes unresponsive
requestPinEntrypinOptionsSuccessPinPad devices only
setDisplayMessagedisplayOptionsSuccessPinPad devices only
sendUserSelectionNumberSuccessSCRA devices only. This command is only used to respond to device's userSelectionRequest
sendArpcResponseHex String or Array<Numbers>SuccessFor more information about building ARPC, please see the MagTek® documentation
setDeviceDateTimeJavaScript Date objectSuccessSCRA devices only
requestTipOrCashbacktipCashbackOptionsSuccessDynaPro Go Only

EMV Options Object

Emv Options object is the input object for the startTransaction function. All property values have default values. Any property supplied will override the default value, while any not supplied will use default values.
There are some differences between devices - so this section will be broken down into four parts:

  1. Properties that are shared by both device types
  2. Properties for SCRA devices only
  3. PinPad properties only
  4. DynaPro Go properties only

Shared Properties:


Property NameDescriptionTypeAcceptable ValuesDefault Value
timeouttime, in seconds, before transaction timeoutNumber1 - 25560
cardTypetypes of cards to accept for transactionString'msr', 'chip', 'chipMsr', 'contactless', 'contactlessChip', 'all'chipMsr
cashBackamount to process as cashback transaction. For transactionType 'refund', this value must be 0Number or Array<Numbers>Number or 6 'byte' n12 format representation of number Number type has limitations, please plan accordingly0
currencyCodetype of currency. 'default' uses device's application terminal setting (usually USA dollar)String'dollar', 'euro', 'pound', 'default''dollar'
authorizedAmountamount to authorize for transaction. For transactionType 'refund', this value must be 0Number or Array<Numbers>Number or 6 'byte' n12 format representation of number Number type has limitations, please plan accordingly100


SCRA properties only:


Property NameDescriptionTypeAcceptable ValuesDefault Value
emvOptionsonline EMV optionsString'normal', 'byPassPin', 'forceOnline', 'quickChip', 'pinByPassQuickChip', 'forceOnlineQuickChip''quickChip'
transactionTypetype of transaction to processString'purchase', 'cashback', 'refund', 'contactlessCashback''purchase'
reportVerbosityEMV Transaction Status/Progress messaging levelString'minimum', 'medium', 'verbose''minimum'


PinPad properties only:


Property NameDescriptionTypeAcceptable ValuesDefault Value
emvOptionsonline EMV optionsString'normal', 'byPassPin', 'forceOnline', 'acquirerNotAvailable''normal'
transactionTypetype of transaction to processString'purchase', 'cashAdvance', 'cashback', 'purchaseGoods', 'purchaseServices', 'cashManual', 'refund', 'chipOnlyPayment''purchase'
pinTimeoutwait time in seconds for cardholder to enter PINNumber1 -25520
toneChoiceSelect device beep behaviorString'noSound', 'oneBeep', 'twoBeeps''oneBeep'
isQuickChiparm in QuickChip mode, or notBooleantrue or falsetrue


DynaPro Go properties only:


Property NameDescriptionTypeAcceptable ValuesDefault ValueNotes
taxAmountTotal tax amountNumber or Array<Numbers>Number or 6 'byte' n12 format representation of number0No decimal points. Number type has limitations, please plan accordingly
taxPercentTax percentage rateNumber or Array<Numbers>Number or 4 'byte' (n6 format x 100) representation of number0 - 99This number is for display purposes only - device does not perform tax calculations
tipAmountTotal tip amountNumber or Array<Numbers>Number or 6 'byte' n12 format representation of number0No decimal points. Number type has limitations, please plan accordingly
balanceBeforeGenAC(Contactless Only) Balance Read Before Gen AC (EMV Tag DF8104)Number or Array<Numbers>Number or 6 'byte' n12 format representation of number0No decimal points. Number type has limitations, please plan accordingly
balanceAfterGenAC(Contactless Only) Balance Read After Gen AC (EMV Tag DF8105)Number or Array<Numbers>Number or 6 'byte' n12 format representation of number0No decimal points. Number type has limitations, please plan accordingly
trxCategoryCode(PayPass/MCL Tag 9F53)NumberN/A0Optional value


Swipe Options Object

Swipe options are only valid for PinPad devices. Swipe options passed to a SCRA device will be ignored.
Property NameDescriptionTypeAcceptable ValuesDefault Value
timeouttime, in seconds, before transaction timeoutNumber1 - 255 (0 for infinite wait)60
displayTypechoose which display customer will see on device display'swipeIdleAlternate', 'swipeCard', 'pleaseSwipe', 'pleaseSwipeAgain', 'chipErrorUseSwipe' 'pleaseSwipe'
toneChoiceSelect device beep behaviorString'noSound', 'oneBeep', 'twoBeeps''oneBeep'
isFallbackexecute swipe with fallback flag. Be aware this will set displayType to 'chipErrorUseSwipe'Booleantrue or falsefalse

PIN Options Object

Property NameDescriptionTypeAcceptable ValuesDefault ValueNotes
languageSelectionDefine language prompt behaviorString'disabled', 'englishFrench', 'allSpecified' 'disabled''allSpecified' uses tag DFDF2D to define available languages
displayTypeDefine prompt template for PIN entryString'enterPin', 'enterPinAmount', 'reEnterPin', 'reEnterPinAmount', 'verifyPin''enterPin'
timeouttime, in seconds, before requestPin timeoutNumber0 - 255 (0 for 256 seconds)30
toneChoiceSelect device beep behaviorString'noSound', 'oneBeep', 'twoBeeps''oneBeep'
pinBlockFormatDefine Pin Block FormatString'iso0', 'iso3''iso0'This value is only respected if device is sent a PAN. If device has no PAN, device creates EPB using ISO Format 1
verifyPinShould device prompt for PIN verificationBooleantrue, falsetrue
waitMessageDisplay wait messageBooleantrue, falsetrue
maxPinLengthSpecify maximum PIN lengthNumber<=12 && >= minPinLength12Value must be <=12 and >= minPinLength
minPinLengthSpecify minimum PIN lengthNumber>=4 && <= maxPinLength4Value must be >=4 and <= maxPinLength

Tip Cashback Options Object

Property NameDescriptionTypeAcceptable ValuesDefault ValueNotes
timeouttime (in seconds) before operation timeoutNumber1 - 6030
commandTypeTip or Cashback ModeString'tip', 'cashback'N/AcommandType is required
toneChoiceSelect device beep behaviorString'noSound', 'oneBeep', 'twoBeeps''oneBeep'
transactionAmountSubtotal amount for transactionNumber or Array<Numbers>Number or 6 'byte' n12 format representation of numberN/ANo decimal points. Number type has limitations, please plan accordingly
calculatedTaxAmountTotal tax amountNumber or Array<Numbers>Number or 6 'byte' n12 format representation of numberN/ANo decimal points. Number type has limitations, please plan accordingly
taxRateTax percentage rateNumber or Array<Numbers>Number or 4 'byte' (n6 format x 100) representation of number0 - 99This number is for display purposes only - device does not perform tax calculations. taxRate is required
tipSelectionModePreset tip amount typeString'percent', 'amount'N/AThis value is only mandatory in Tip mode. N/A for Cashback Mode
leftAmountFixed Percent or Amount for left displayNumber0-990N/A for Cashback Mode
middleAmountFixed Percent or Amount for middle displayNumber0-990N/A for Cashback Mode
rightAmountFixed Percent or Amount for right displayNumber0-990N/A for Cashback Mode

Display Options Object

Property NameDescriptionTypeAcceptable ValuesDefault ValueNotes
messageIdId for message to displayNumberAcceptable IDs are listed hereN/ANo default value - ID is required
displayTimeHow long the display message will display on screenNumber0 (infinite) - 25515 seconds

Callbacks

User defined callback functions can be as granular as desired. For this purpose - there is only one callback that is mandatory to provide to the scanForDevices method. The remaining callbacks are subscription based. In reference to the return objects for the below callbacks - please see the Return Objects section for object structures.

errorCallback is the only special case. Please see description for behavior. For all other callbacks - if one is not provided - data will be sent to the main callback (transactionCallback). This can sometimes clutter the callback data, and become problematic, so please plan callback structure according to your specific needs.

CallbackReturn objectNotes
transactionCallbackTransaction Result ObjectTransaction data. Object structure will depend on which type of transaction was requested. This is the only mandatory callback, as it serves as the main/default callback.
errorCallbackError ObjectIf provided, all internal errors that cannot be thrown to a caller will be piped to this callback. If not provided, internal errors will log to JavaScript console. All errors pertaining to functions invoked via the deviceInterface will always be thrown back to the caller
displayCallbackDisplay Message ObjectMessage to display directly to the end user. This callback is only used by SCRA devices. PinPad devices will display messages directly on the device
transactionStatusCallbackTransaction Status ObjectStatus, Progress, Messages, and Codes will all be piped to this callback. You can throttle reportVerbosity on SCRA devices
disconnectHandlerDisconnect EventDisconnect Event inherits from Event. Disconnect events are emitted every time a device disconnects (closes)
userSelectionCallbackuserSelectionRequestSCRA devices that have multiple applications, and process a card with multiple applications will send this report. User must select item from the menu items listed in the report and respond using the sendUserSelection function with the menu selection number

Callback Examples

This is the most basic example - using Promises.

let exampleCallback = responseObj => {
    /*
        For a single callback, all responses will be passed to this callback.
        You can filter by properties in the responseObj, if desired.
        For example...
    */

    if ('swipeData' in responseObj) {
        //process swipe data.
    }
}

scanForDevices(exampleCallback)
    .then( device => {
        window.MagTekDevice = device
    })
    .catch( errObj => {
        console.log(errObj)
    });

This is the most basic example - using async/await.

let exampleCallback = responseObj => {
    /*
        For a single callback, all responses will be passed to this callback.
        You can filter by properties in the responseObj, if desired.
        For example...
    */

   const { swipeData } = responseObj;

   if (swipeData) {
       //process swipe data.
   }
}

const connectDevice = async() => {
    try {
        let deviceResp = await scanForDevices(exampleCallback)

        window.MagTekDevice = devicedeviceResp
    }
    catch(error) {
        console.log(error)
    }
}

These are two examples of the most granular way to interact with this library:

Structure callbacks using function property assignment:


const callbacks = (function() {
    const allCallbacks = responseObj => {
        /*
            This will be the main callback, also known as the 'transactionCallback'.
            Since we are using an IIFE to structure callbacks, we don't need to explicitly assign this value.
        */

        if ('swipeData' in responseObj) {
            //Handle swipe data.
        }
    }

    allCallbacks.errorCallback = errObj => {
        /*
            Handle all internal errors that cannot be thrown back to a caller.
            If this callback is not provided - internal errors will be logged to the JavaScript console.
        */
    }

    allCallbacks.transactionStatusCallback = statusObj => {
        /*
            Handle or log all transaction status, progress, codes and messages.
            This callback is great for debugging and device visibility.
        */
    }

    allCallbacks.displayCallback = ({ displayMessage }) => {
        /*
            Handle all user display messages.
            For SCRA devices - EMV standards state this message must be displayed directly to the user.
            PinPad devices will not use this callback, and will instead use the device display.
            The message language is determined by device configuration.
        */
        document.getElementById('display-to-user').innerText = displayMessage;
    }

    allCallbacks.userSelectionCallback = ({ userSelectionRequest }) => {
        /*
            Respond to any User Selection Request Notifications.
            SCRA devices with multiple applications only.
        */
    }

    allCallbacks.disconnectHandler = event => {
        //Handle device disconnect events.
        let message = `Device: ${event.target.name} has disconnected`;
    }

    return allCallbacks;
})();

//Using Promises
scanForDevices(callbacks)
    .then( device => {
        window.MagTekDevice = device
    })
    .catch( errObj => {
        console.error("Caught Error: ", errObj);
    });
    

//Using async/await
const pairDevice = async() => {
    try {
        const deviceResp = await scanForDevices(callbacks);
        window.MagTekDevice = deviceResp;
    }
    catch(error) {
        console.error("Caught Error: ", errObj);
    }
}

Structure callbacks using an Object:

const exampleErrorHandler = errObj => {
    /*
        Handle all internal errors that cannot be thrown back to a caller.
        If this callback is not provided - internal errors will be logged to the JavaScript console.
    */
}

const exampleTransactionHandler = dataObj => {
    //Handle all transaction/card data.
}

const exampleTransactionStatusHandler = statusObj => {
    /*
        Handle or log all transaction status, progress, codes and messages.
        This callback is great for debugging and device visibility.
    */
}

const exampleDisplayMessageHandler = ({ displayMessage }) => {
    /*
        Handle all user display messages.
        For SCRA devices - EMV standards state this message must be displayed directly to the user.
        PinPad devices will not use this callback, and will instead use the device display.
        The message language is determined by device configuration.
    */
    document.getElementById('display-to-user').innerText = displayMessage;
}

const exampleDisconnectHandler = event => {
    //Handle device disconnect events.
    let message = `Device: ${event.target.name} has disconnected`;
}

const exampleUserSelectionCallback = ({ userSelectionRequest }) => {
     /*
        Respond to any User Selection Request Notifications.
        SCRA devices with multiple applications only.
    */
}

//Note that when structuring multiple callbacks in an object - 'transactionCallback' becomes mandatory.

let callBackObject = {
    transactionCallback: exampleTransactionHandler,
    errorCallback: exampleErrorHandler,
    displayCallback: exampleDisplayMessageHandler,
    transactionStatusCallback: exampleTransactionStatusHandler,
    disconnectHandler: exampleDisconnectHandler,
    userSelectionCallback: exampleUserSelectionCallback
}

//Using Promises
scanForDevices(callBackObject)
    .then( device => {
        window.MagTekDevice = device
    })
    .catch( errObj => {
        console.error("Caught Error: ", errObj);
    });
    

//Using async/await
const connectDevice = async() => {
    try {
        const deviceResp = await scanForDevices(callBackObject);
        window.MagTekDevice = deviceResp;
    }
    catch(error) {
        console.error("Caught Error: ", errObj);
    }
}

Return Objects

1. Device Object
{
    id: String,
    name: String,
    deviceType: String,
    deviceInterface: {
        openDevice: Function
        startTransaction: Function
        cancelTransaction: Function
        sendCommand: Function
        clearSession: Function
        closeDevice: Function
        deviceInfo: Function
        requestCardSwipe: Function
        isDeviceOpen: Function
        forceDisconnect: Function
        requestPinEntry: Function
        setDisplayMessage: Function
        sendUserSelection: Function
        sendArpcResponse: Function
        setDeviceDateTime: Function
        requestTipOrCashback: Function
    }
}
2. Transaction Result Object:

arqcData and batchData are hex strings that are unparsed, and contain the same data as the parsed objects.

{
    arqcData: String,
    arqcDataParsed: [
        { tag: String, length: Number, value: String }, 
        { tag: String, length: Number, value: String }
    ],
    batchData: String,
    batchDataParsed: [
        { tag: String, length: Number, value: String },
        { tag: String, length: Number, value: String }
    ],
    swipeData: {
        ksn: String,
        Last4: String,
        encSessionId: String,
        expirationDate: String, // MM/DD format
        magnePrint: String,
        magnePrintStatus: String,
        maskedPAN: String,
        serialNumber: String,
        track1: String,
        track1Masked: String,
        track1DecodeStatus: Number,
        track2: String,
        track2DecodeStatus: Number,
        track2Masked: String,
        track3: String,
        track3DecodeStatus: Number,
        track3Masked: String
    },
    signatureRequired: Boolean
}
3. Display Message Object:
{
    displayMessage: String
}
4. Transaction Status Object:
{
    transactionStatus: {
        statusCode: Number,
        statusMsg: String,
        progressCode: Number,
        progressMsg: String
    }
}
5. Error Object

There are many error objects, depending on what layer threw the error. All errors extend JavaScript's Error. All have the following properties.

{
    Error: {
        code: Number,
        name: String,
        message: String
    }
}
6. Success Object
{
    code: 0,
    message: String
}
7. Device Information
{
    deviceName: String,
    deviceType: String,
    isConnected: Boolean,
    serialNumber: String,
    batteryLevel: Number //Scra devices only - Pin devices display battery level
}
8. Tip Cashback Report
{
    tipCashbackReport: {
        operationStatus: String,
        reportMode: String,
        amount: Array<Number>,
        tax: Array<Number>,
        taxRate: Array<Number>,
        tipOrCashbackAmount: Array<Number>
    }
}
9. Pin Data Report
{
    pinData: {
        operationStatus: String,
        pinKsn: String,
        encryptedPinBlock: String
    }
}
10. User Selection Request
{
    userSelectionRequest: {
        selectionType: String,
        timeRemaining:  Number,
        menuItems: Array<Number>
    }
}

Playground and Additional Information

Please visit our Playground for an interactive demo.

  • The Playground also offers detailed compatibility information, as well as first time pairing instructions for all compatible browsers and operating systems.
  • The Playground source code is also available as an example implementation.

Debug Event

For added visibility during development, this library has a debug event emitter (deviceLog) that will log verbose details for all device interactions.
This can be especially useful when a bad command is sent - or to see the behavior when a device begins to refuse commands.
If you wish to subscribe to the event, you may do so:

const debugLogger = logInfo => console.log(logInfo.detail);

window.addEventListener('deviceLog', debugLogger, { passive: true});
//Be sure to remove it when unmounting to avoid memory leaks:
window.removeEventListener('deviceLog', debugLogger, { passive: true});

WebBluetooth Info

There are some WebBluetooth issues that users of this library should be made aware of:

  • The initial pairing process (wherin the Chromium browser, and the Operating System coincide the Bluetooth Pair) can be a bit challenging at times. To that end, a comprehensive list of pairing instructions, based upon browser choice and operating system, has been put together in our Playground.
    • Select a browser, operating system, expand the panel and click "Specific Details".
    • Most all users that have trouble getting this library started, need to follow the instructions to the letter.
      • Also, following the instructions to the letter, in addition to a device power cycle, will solve most all initial pairing issues.
    • Remember this initial pair is one-time only, and does not need to be repeated to utilize the library (or any WebBluetooth solution) in the future.
  • There is a simple check that can be included in the web application that consumes this library, to see if the client is using a compatible browser. That check is as follows:
        if (navigator && navigator.bluetooth) { 
            //Compatible
        }
        else {
            //Not Compatible browser
        }
    
    • It is important to note that compatible browsers will fail this check if the site is not deployed through secure context (valid https:// domain).
      • localhost will work for development purposes, but it's important to note that 192.168.0.1: and 127.0.0.1 will both fail the secure context check.
        • This is especially important to consider for active mobile development.
      • When a compatible browser fails the secure context check - the bluetooth property is removed from the navigator object. No other error or warning is emitted.

Transaction Amount Limitations

Please be aware that there are limitations on maximum amounts for transactions:
The maximum length of Transaction Amount, Calculated Tax Amount, Tip dollar amount, and Cash Back dollar amount is 10 digits. If the Tip calculated by percentage equals or exceeds $42,949,672.95, the device shows 0.

Device Types

Under very rare circumstances, it is possible this library will fail to identify a valid device type.
In this case, there is a third parameter for scanForDevices function that accepts a deviceType. The available types are:

  • tDynamo
  • eDynamo
  • dynaProGo
  • DynaPro Mini

MagTek® is a registered trademark of MagTek, Inc.
Magensa™ is a trademark of MagTek, Inc.

FAQs

Package last updated on 21 Jul 2020

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc