UNPKG

wmt-marketplace-auth-canada

Version:

Generate the authentication headers required by Walmart Marketplace API.

264 lines (247 loc) 7.13 kB
import * as Util from './util'; import * as uuid from 'uuid'; import { createSign, Signer } from 'crypto'; /** * WM_SVC Authentication header namespace. */ export interface WMService { /** * Walmart Service Name. * * Header WM_SVC.NAME. */ Name: string; } /** * WM_QOS Authentication header namespace. */ export interface WMQOS { /** * A unique ID to correlate a vendor's calls with the Walmart system. * * Header WM_QOS.CORRELATION_ID. */ CorrelationId: string; } /** * WM_SEC Authentication header namespace. */ export interface WMSecurity { /** * The Epoch timestamp. * * Header WM_SEC.TIMESTAMP. */ Timestamp: number; /** * The vendor's digital signature. * * Header WM_SEC.AUTH_SIGNATURE. */ AuthSignature: string; } /** * WM_CONSUMER.CHANNEL Authentication header namespace. */ export interface Channel { /** * A unique ID to track the consumer request by channel. Use the Consumer Channel * Type received during onboarding. * * Header WM_CONSUMER.CHANNEL.TYPE. */ Type: string; } /** * WM_CONSUMER Authentication header namespace. */ export interface WMConsumer { /** * WM_CONSUMER.CHANNEL Authentication header namespace. */ Channel: Channel; /** * The Walmart Consumer ID from Developer Center required to access the API. * * Header WM_CONSUMER.ID. */ ConsumerId: string; } /** * Walmart authentication headers. Use the custom class to set custom values to the * headers before adding to the request. * * @see {@link https://developer.walmart.com/#/apicenter/marketPlace/latest#apiAuthentication} */ export class Custom { /** * WM_SVC Authentication headers. */ WMService: WMService; /** * WM_QOS Authentication headers. */ WMQOS: WMQOS; /** * WM_SEC Authentication headers. */ WMSecurity: WMSecurity; /** * WM_CONSUMER Authentication headers. */ WMConsumer: WMConsumer; /** * The desired returned data format of the response. May override the default to * 'application/xml' if an XML response is preferred instead of JSON. */ Accept: string; /** * The data format used in the request. May override the default to * 'application/xml' if an XML response is preferred instead of JSON. */ ContentType: string; constructor() { this.WMQOS = { CorrelationId: uuid()}; this.WMService = { Name: 'Walmart Marketplace' }; this.Accept = 'application/json'; this.ContentType = 'application/json'; } /** * Set the vendor's Correlation ID. * * @param correlationId A unique ID to correlate a vendor's calls with the Walmart * system. */ setCorrelationId(correlationId: string): void { this.WMQOS = { CorrelationId: correlationId }; } /** * Set the Consumer ID. * * @param consumer The Walmart Consumer ID from Developer Center required to access * the API. */ setConsumer(consumer: WMConsumer): void { this.WMConsumer = consumer; } /** * Set the request Timestamp. Note: Resets the AuthSignature to empty string. This * method is primarily used by tests. Timestamp is automatically set by sign() * method if not otherwise set. * * @param timestamp Epoch timestamp in milliseconds. */ setTimestamp(timestamp: number): void { this.WMSecurity = { Timestamp: timestamp, AuthSignature: '' } } } /** * The API request headers compiled according to the API spec, including the required * digital signature. */ export interface Signed { 'WM_SVC.NAME': string; 'WM_QOS.CORRELATION_ID': string; 'WM_SEC.TIMESTAMP': number; 'WM_SEC.AUTH_SIGNATURE': string; 'WM_CONSUMER.CHANNEL.TYPE': string; 'WM_CONSUMER.ID': string; 'Accept': string; 'Content-Type': string; } /** * The request properties required to generate the digital signature. */ export interface DigitalSignatureRequest { /** * The full URL to call, including path and query parameters. */ RequestUrl: string; /** * The vendor's Base-64-encoded, PKCS#8 stored Private Key. */ PrivateKey: string; /** * The HTTP request method used, in capital letters (i.e. GET, POST). */ RequestMethod: string; } /** * Returns the signed headers required for the API request. * * @param custom Walmart authentication headers. Use the custom class to set custom * values to the headers before adding to the request. * @param request The request properties required to generate the digital signature. */ export function sign(custom: Custom, request: DigitalSignatureRequest): Signed { /** * An Epoch timestamp is required for the digital signature. */ let epoch: number = Util.epochInMilliseconds(); /** * Override the generated Epoch timestamp if a timestamp was included in the * custom headers. */ if (custom.WMSecurity && custom.WMSecurity.Timestamp) { epoch = custom.WMSecurity.Timestamp; } /** * The generated digital signature. */ let signature: string = digitalSignature(custom, request, epoch); /** * Override the generated digital signature if a signature was included in the * custom headers. */ if (custom.WMSecurity && custom.WMSecurity.AuthSignature) { signature = custom.WMSecurity.AuthSignature; } /** * The signed request headers according to Walmart API spec. */ let signedHeaders: Signed = { 'WM_SVC.NAME': custom.WMService.Name, 'WM_QOS.CORRELATION_ID': custom.WMQOS.CorrelationId, 'WM_SEC.TIMESTAMP': epoch, 'WM_SEC.AUTH_SIGNATURE': signature, 'WM_CONSUMER.CHANNEL.TYPE': custom.WMConsumer.Channel.Type, 'WM_CONSUMER.ID': custom.WMConsumer.ConsumerId, 'Accept': custom.Accept, 'Content-Type': custom.Accept } return signedHeaders; } /** * Generates the digital signature required for the API request. * * @param custom Walmart authentication headers. Use the custom class to set custom * values to the headers before adding to the request. * @param request The request properties required to generate the digital signature. * @param epoch An Epoch timestamp is required for the digital signature. */ function digitalSignature(custom: Custom, request: DigitalSignatureRequest, epoch: number): string { /** * Node Crypto Sign object that uses the given algorithm. * * @see {@link https://nodejs.org/api/crypto.html#crypto_class_sign} */ const signer: Signer = createSign('RSA-SHA256'); /** * Walmart API request string to be signed. */ let stringToSign: string = custom.WMConsumer.ConsumerId + "\n" + request.RequestUrl + "\n" + request.RequestMethod.toUpperCase() + "\n" + epoch + "\n"; /** * Updates the Sign content with the given data. * @see {@link https://nodejs.org/api/crypto.html#crypto_sign_update_data_inputencoding} */ signer.update(stringToSign); /** * Private key wrapped in key header and footer. */ let privateKey: string = "-----BEGIN PRIVATE KEY-----\n" + request.PrivateKey + "\n-----END PRIVATE KEY-----"; return signer.sign(privateKey, 'base64'); }