diff --git a/.eslintrc b/.eslintrc index 81c2f577..8c3eae3d 100644 --- a/.eslintrc +++ b/.eslintrc @@ -3,6 +3,9 @@ "env": { "es6": true }, + "parserOptions": { + "sourceType": "module" + }, "rules": { "no-var": 2, "no-const-assign": 2, diff --git a/package.json b/package.json index 2181cff4..76069102 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,8 @@ "name": "web-push", "version": "3.6.6", "description": "Web Push library for Node.js", - "main": "src/index.js", + "type": "module", + "exports": "./src/index.js", "bin": { "web-push": "src/cli.js" }, diff --git a/src/cli.js b/src/cli.js index fc644b05..ccae65df 100755 --- a/src/cli.js +++ b/src/cli.js @@ -1,9 +1,7 @@ #! /usr/bin/env node /* eslint consistent-return:0 */ - -'use strict'; - -const webPush = require('../src/index.js'); +import * as webPush from '../src/index.js'; +import minimist from 'minimist'; const printUsageDetails = () => { const actions = [ @@ -80,7 +78,7 @@ const sendNotification = args => { options.TTL = args.ttl; } - if (argv['vapid-subject'] || argv['vapid-pubkey'] || argv['vapid-pvtkey']) { + if (args['vapid-subject'] || args['vapid-pubkey'] || args['vapid-pvtkey']) { options.vapidDetails = { subject: args['vapid-subject'] || null, publicKey: args['vapid-pubkey'] || null, @@ -112,20 +110,24 @@ const sendNotification = args => { }); }; -const action = process.argv[2]; -const argv = require('minimist')(process.argv.slice(3)); -switch (action) { - case 'send-notification': - if (!argv.endpoint) { - return printUsageDetails(); - } +const executeCliAction = () => { + const action = process.argv[2]; + const argv = minimist(process.argv.slice(3)); + switch (action) { + case 'send-notification': + if (!argv.endpoint) { + return printUsageDetails(); + } + + sendNotification(argv); + break; + case 'generate-vapid-keys': + generateVapidKeys(argv.json || false); + break; + default: + printUsageDetails(); + break; + } +}; - sendNotification(argv); - break; - case 'generate-vapid-keys': - generateVapidKeys(argv.json || false); - break; - default: - printUsageDetails(); - break; -} +executeCliAction(); diff --git a/src/encryption-helper.js b/src/encryption-helper.js index 779e2ad0..6f8e1b2e 100644 --- a/src/encryption-helper.js +++ b/src/encryption-helper.js @@ -1,9 +1,7 @@ -'use strict'; +import crypto from 'crypto'; +import ece from 'http_ece'; -const crypto = require('crypto'); -const ece = require('http_ece'); - -const encrypt = function(userPublicKey, userAuth, payload, contentEncoding) { +export function encrypt(userPublicKey, userAuth, payload, contentEncoding) { if (!userPublicKey) { throw new Error('No user public key provided for encryption.'); } @@ -55,8 +53,4 @@ const encrypt = function(userPublicKey, userAuth, payload, contentEncoding) { salt: salt, cipherText: cipherText }; -}; - -module.exports = { - encrypt: encrypt -}; +} diff --git a/src/index.js b/src/index.js index f7b36741..f737b56a 100644 --- a/src/index.js +++ b/src/index.js @@ -1,21 +1,23 @@ -'use strict'; - -const vapidHelper = require('./vapid-helper.js'); -const encryptionHelper = require('./encryption-helper.js'); -const WebPushLib = require('./web-push-lib.js'); -const WebPushError = require('./web-push-error.js'); -const WebPushConstants = require('./web-push-constants.js'); +import { getVapidHeaders, generateVAPIDKeys } from './vapid-helper.js'; +import { encrypt } from './encryption-helper.js'; +import { WebPushLib } from './web-push-lib.js'; +import WebPushError from './web-push-error.js'; +import WebPushConstants from './web-push-constants.js'; const webPush = new WebPushLib(); -module.exports = { - WebPushError: WebPushError, - supportedContentEncodings: WebPushConstants.supportedContentEncodings, - encrypt: encryptionHelper.encrypt, - getVapidHeaders: vapidHelper.getVapidHeaders, - generateVAPIDKeys: vapidHelper.generateVAPIDKeys, - setGCMAPIKey: webPush.setGCMAPIKey, - setVapidDetails: webPush.setVapidDetails, - generateRequestDetails: webPush.generateRequestDetails, - sendNotification: webPush.sendNotification.bind(webPush) +const { supportedContentEncodings } = WebPushConstants; +const { setGCMAPIKey, setVapidDetails, generateRequestDetails } = webPush; +const sendNotification = webPush.sendNotification.bind(webPush); + +export { + WebPushError, + supportedContentEncodings, + encrypt, + getVapidHeaders, + generateVAPIDKeys, + setGCMAPIKey, + setVapidDetails, + generateRequestDetails, + sendNotification }; diff --git a/src/urlsafe-base64-helper.js b/src/urlsafe-base64-helper.js index 30650fa2..645b934a 100644 --- a/src/urlsafe-base64-helper.js +++ b/src/urlsafe-base64-helper.js @@ -1,13 +1,7 @@ -'use strict'; - /** * @param {string} base64 * @returns {boolean} */ -function validate(base64) { +export function validate(base64) { return /^[A-Za-z0-9\-_]+$/.test(base64); } - -module.exports = { - validate: validate -}; diff --git a/src/vapid-helper.js b/src/vapid-helper.js index c0305bdd..06b463c3 100644 --- a/src/vapid-helper.js +++ b/src/vapid-helper.js @@ -1,12 +1,10 @@ -'use strict'; +import crypto from 'crypto'; +import asn1 from 'asn1.js'; +import jws from 'jws'; +import { URL } from 'url'; -const crypto = require('crypto'); -const asn1 = require('asn1.js'); -const jws = require('jws'); -const { URL } = require('url'); - -const WebPushConstants = require('./web-push-constants.js'); -const urlBase64Helper = require('./urlsafe-base64-helper'); +import WebPushConstants from './web-push-constants.js'; +import * as urlBase64Helper from './urlsafe-base64-helper.js'; /** * DEFAULT_EXPIRATION is set to seconds in 12 hours @@ -37,7 +35,7 @@ function toPEM(key) { }); } -function generateVAPIDKeys() { +export function generateVAPIDKeys() { const curve = crypto.createECDH('prime256v1'); curve.generateKeys(); @@ -65,7 +63,7 @@ function generateVAPIDKeys() { }; } -function validateSubject(subject) { +export function validateSubject(subject) { if (!subject) { throw new Error('No subject set in vapidDetails.subject.'); } @@ -91,7 +89,7 @@ function validateSubject(subject) { } } -function validatePublicKey(publicKey) { +export function validatePublicKey(publicKey) { if (!publicKey) { throw new Error('No key set vapidDetails.publicKey'); } @@ -112,7 +110,7 @@ function validatePublicKey(publicKey) { } } -function validatePrivateKey(privateKey) { +export function validatePrivateKey(privateKey) { if (!privateKey) { throw new Error('No key set in vapidDetails.privateKey'); } @@ -141,7 +139,7 @@ function validatePrivateKey(privateKey) { * @param {Number} numSeconds Number of seconds to be added * @return {Number} Future expiration in seconds */ -function getFutureExpirationTimestamp(numSeconds) { +export function getFutureExpirationTimestamp(numSeconds) { const futureExp = new Date(); futureExp.setSeconds(futureExp.getSeconds() + numSeconds); return Math.floor(futureExp.getTime() / 1000); @@ -153,7 +151,7 @@ function getFutureExpirationTimestamp(numSeconds) { * * @param {Number} expiration Expiration seconds from Epoch to be validated */ -function validateExpiration(expiration) { +export function validateExpiration(expiration) { if (!Number.isInteger(expiration)) { throw new Error('`expiration` value must be a number'); } @@ -184,7 +182,7 @@ function validateExpiration(expiration) { * @return {Object} Returns an Object with the Authorization and * 'Crypto-Key' values to be used as headers. */ -function getVapidHeaders(audience, subject, publicKey, privateKey, contentEncoding, expiration) { +export function getVapidHeaders(audience, subject, publicKey, privateKey, contentEncoding, expiration) { if (!audience) { throw new Error('No audience could be generated for VAPID.'); } @@ -243,13 +241,3 @@ function getVapidHeaders(audience, subject, publicKey, privateKey, contentEncodi throw new Error('Unsupported encoding type specified.'); } - -module.exports = { - generateVAPIDKeys: generateVAPIDKeys, - getFutureExpirationTimestamp: getFutureExpirationTimestamp, - getVapidHeaders: getVapidHeaders, - validateSubject: validateSubject, - validatePublicKey: validatePublicKey, - validatePrivateKey: validatePrivateKey, - validateExpiration: validateExpiration -}; diff --git a/src/web-push-constants.js b/src/web-push-constants.js index 0d0a8b74..a2d0f10d 100644 --- a/src/web-push-constants.js +++ b/src/web-push-constants.js @@ -1,5 +1,3 @@ -'use strict'; - const WebPushConstants = {}; WebPushConstants.supportedContentEncodings = { @@ -14,4 +12,4 @@ WebPushConstants.supportedUrgency = { HIGH: 'high' }; -module.exports = WebPushConstants; +export default WebPushConstants; diff --git a/src/web-push-error.js b/src/web-push-error.js index 94a1cda2..b0ff72eb 100644 --- a/src/web-push-error.js +++ b/src/web-push-error.js @@ -1,6 +1,6 @@ -'use strict'; +import util from 'util'; -function WebPushError(message, statusCode, headers, body, endpoint) { +export default function WebPushError(message, statusCode, headers, body, endpoint) { Error.captureStackTrace(this, this.constructor); this.name = this.constructor.name; @@ -11,6 +11,4 @@ function WebPushError(message, statusCode, headers, body, endpoint) { this.endpoint = endpoint; } -require('util').inherits(WebPushError, Error); - -module.exports = WebPushError; +util.inherits(WebPushError, Error); diff --git a/src/web-push-lib.js b/src/web-push-lib.js index a47df054..c7f300cd 100644 --- a/src/web-push-lib.js +++ b/src/web-push-lib.js @@ -1,13 +1,11 @@ -'use strict'; +import url from 'url'; +import https from 'https'; -const url = require('url'); -const https = require('https'); - -const WebPushError = require('./web-push-error.js'); -const vapidHelper = require('./vapid-helper.js'); -const encryptionHelper = require('./encryption-helper.js'); -const webPushConstants = require('./web-push-constants.js'); -const urlBase64Helper = require('./urlsafe-base64-helper'); +import WebPushError from './web-push-error.js'; +import * as vapidHelper from './vapid-helper.js'; +import * as encryptionHelper from './encryption-helper.js'; +import webPushConstants from './web-push-constants.js'; +import * as urlBase64Helper from './urlsafe-base64-helper.js'; // Default TTL is four weeks. const DEFAULT_TTL = 2419200; @@ -15,7 +13,7 @@ const DEFAULT_TTL = 2419200; let gcmAPIKey = ''; let vapidDetails; -function WebPushLib() { +export function WebPushLib() { } @@ -405,9 +403,5 @@ WebPushLib.prototype.sendNotification = function(subscription, payload, options) if (requestDetails.body) { pushRequest.write(requestDetails.body); } - - pushRequest.end(); - }); - }; - -module.exports = WebPushLib; + }); +}; diff --git a/test/.eslintrc b/test/.eslintrc index 48924543..51fb1f3e 100644 --- a/test/.eslintrc +++ b/test/.eslintrc @@ -5,5 +5,8 @@ "rules": { "max-len": 0, "global-require": 0 + }, + "parserOptions": { + "sourceType": "module" } } diff --git a/test/data/demo/service-worker.js b/test/data/demo/service-worker.js index 99702fa2..86ce3c7d 100644 --- a/test/data/demo/service-worker.js +++ b/test/data/demo/service-worker.js @@ -1,8 +1,6 @@ /* Needed because of https://github.com/airbnb/javascript/issues/1632 */ /* eslint no-restricted-globals: 0 */ -'use strict'; - let port; let pushMessage; diff --git a/test/helpers/create-server.js b/test/helpers/create-server.js index eded6891..d81059a8 100644 --- a/test/helpers/create-server.js +++ b/test/helpers/create-server.js @@ -1,11 +1,9 @@ -'use strict'; +import http from 'http'; +import portfinder from 'portfinder'; +import fs from 'fs'; +import path from 'path'; -const http = require('http'); -const portfinder = require('portfinder'); -const fs = require('fs'); -const path = require('path'); - -function createServer() { +export function createServer() { const demoPath = 'test/data/demo'; const server = http.createServer(function(req, res) { @@ -55,5 +53,3 @@ function createServer() { }); }); } - -module.exports = createServer; diff --git a/test/helpers/download-test-browsers.js b/test/helpers/download-test-browsers.js index f34e11d6..4ac16cb4 100644 --- a/test/helpers/download-test-browsers.js +++ b/test/helpers/download-test-browsers.js @@ -1,7 +1,5 @@ -'use strict'; - -const os = require('os'); -const seleniumAssistant = require('selenium-assistant'); +import os from 'os'; +import seleniumAssistant from 'selenium-assistant'; const MAX_RETRIES = 3; let expiration; diff --git a/test/test-cli.js b/test/test-cli.js index 471b13af..d119a24f 100644 --- a/test/test-cli.js +++ b/test/test-cli.js @@ -1,4 +1,5 @@ -'use strict'; +import assert from 'assert'; +import { spawn } from 'child_process'; (function() { const invalidNodeVersions = /0.(10|12).(\d+)/; @@ -7,9 +8,6 @@ return; } - const assert = require('assert'); - const spawn = require('child_process').spawn; - const cliPath = 'src/cli.js'; suite('Test CLI', function() { diff --git a/test/test-encryption-helper.js b/test/test-encryption-helper.js index 364d3b5f..a4e0f256 100644 --- a/test/test-encryption-helper.js +++ b/test/test-encryption-helper.js @@ -1,9 +1,7 @@ -'use strict'; - -const assert = require('assert'); -const crypto = require('crypto'); -const webPush = require('../src/index'); -const ece = require('http_ece'); +import assert from 'assert'; +import crypto from 'crypto'; +import * as webPush from '../src/index.js'; +import ece from 'http_ece'; const userCurve = crypto.createECDH('prime256v1'); const VALID_PUBLIC_KEY = userCurve.generateKeys().toString('base64url'); diff --git a/test/test-generate-request-details.js b/test/test-generate-request-details.js index 007de665..458a1d12 100644 --- a/test/test-generate-request-details.js +++ b/test/test-generate-request-details.js @@ -1,11 +1,10 @@ -'use strict'; - -const assert = require('assert'); -const { generateRequestDetails } = require('../src/index'); -const crypto = require('crypto'); -const jws = require('jws'); -const urlParse = require('url').parse; -const https = require('https'); +import assert from 'assert'; +import { generateRequestDetails } from '../src/index.js'; +import crypto from 'crypto'; +import jws from 'jws'; +import { parse as urlParse } from 'url'; +import https from 'https'; +import { generateVAPIDKeys } from '../src/vapid-helper.js'; suite('Test Generate Request Details', function() { test('is defined', function() { @@ -15,7 +14,7 @@ suite('Test Generate Request Details', function() { const userCurve = crypto.createECDH('prime256v1'); const userPublicKey = userCurve.generateKeys(); const userAuth = crypto.randomBytes(16); - const vapidKeys = require('../src/vapid-helper').generateVAPIDKeys(); + const vapidKeys = generateVAPIDKeys(); const VALID_KEYS = { p256dh: userPublicKey.toString('base64url'), diff --git a/test/test-set-vapid-details.js b/test/test-set-vapid-details.js index 657017d8..f327032c 100644 --- a/test/test-set-vapid-details.js +++ b/test/test-set-vapid-details.js @@ -1,7 +1,5 @@ -'use strict'; - -const assert = require('assert'); -const { setVapidDetails } = require('../src/index'); +import assert from 'assert'; +import { setVapidDetails } from '../src/index.js'; const VALID_SUBJECT_MAILTO = 'mailto: example@example.com'; const VALID_SUBJECT_URL = 'https://exampe.com/contact'; diff --git a/test/test-vapid-helper.js b/test/test-vapid-helper.js index 949a352d..e62b136b 100644 --- a/test/test-vapid-helper.js +++ b/test/test-vapid-helper.js @@ -1,11 +1,9 @@ -'use strict'; - -const assert = require('assert'); -const sinon = require('sinon'); -const crypto = require('crypto'); -const mocha = require('mocha'); -const webPush = require('../src/index'); -const vapidHelper = require('../src/vapid-helper'); +import assert from 'assert'; +import sinon from 'sinon'; +import crypto from 'crypto'; +import mocha from 'mocha'; +import * as webPush from '../src/index.js'; +import * as vapidHelper from '../src/vapid-helper.js'; const VALID_AUDIENCE = 'https://example.com'; const VALID_SUBJECT_MAILTO = 'mailto:example@example.com'; diff --git a/test/testSelenium.js b/test/testSelenium.js index 17380edf..55044cfb 100644 --- a/test/testSelenium.js +++ b/test/testSelenium.js @@ -1,18 +1,16 @@ -'use strict'; - -const seleniumAssistant = require('selenium-assistant'); -const webdriver = require('selenium-webdriver'); -const seleniumFirefox = require('selenium-webdriver/firefox'); -const assert = require('assert'); -const mkdirp = require('mkdirp'); -const fs = require('fs'); -const del = require('del'); -const webPush = require('../src/index'); -const createServer = require('./helpers/create-server'); +import seleniumAssistant from 'selenium-assistant'; +import webdriver from 'selenium-webdriver'; +import seleniumFirefox from 'selenium-webdriver/firefox/index.js'; +import assert from 'assert'; +import * as mkdirp from 'mkdirp'; +import fs from 'fs'; +import del from 'del'; +import * as webPush from '../src/index.js'; +import { createServer } from './helpers/create-server.js'; // We need geckodriver on the path -require('geckodriver'); -require('chromedriver'); +import 'geckodriver'; +import 'chromedriver'; const vapidKeys = webPush.generateVAPIDKeys(); diff --git a/test/testSendNotification.js b/test/testSendNotification.js index 429235c2..ba2259e4 100644 --- a/test/testSendNotification.js +++ b/test/testSendNotification.js @@ -1,26 +1,22 @@ -'use strict'; - -const assert = require('assert'); -const crypto = require('crypto'); -const https = require('https'); -const fs = require('fs'); -const path = require('path'); -const ece = require('http_ece'); -const portfinder = require('portfinder'); -const jws = require('jws'); -const mocha = require('mocha'); -const WebPushConstants = require('../src/web-push-constants.js'); - -suite('sendNotification', function() { - let sendNotification; - let setGCMAPIKey; - let setVapidDetails; - - mocha.beforeEach(function () { - ({ sendNotification, setGCMAPIKey, setVapidDetails } = require('../src/index')); - }); - - test('is defined', function() { +import assert from 'assert'; +import crypto from 'crypto'; +import https from 'https'; +import fs from 'fs'; +// import path from 'path'; +import ece from 'http_ece'; +import portfinder from 'portfinder'; +import jws from 'jws'; +import mocha from 'mocha'; +import WebPushConstants from '../src/web-push-constants.js'; +import { generateVAPIDKeys } from '../src/vapid-helper.js'; +import { + sendNotification, + setGCMAPIKey, + setVapidDetails +} from '../src/index.js'; + +suite('sendNotification', function () { + test('is defined', function () { assert(sendNotification); }); @@ -44,8 +40,8 @@ suite('sendNotification', function() { requestDetails = null; // Delete caches of web push libs to start clean between test runs - delete require.cache[path.join(__dirname, '..', 'src', 'index.js')]; - delete require.cache[path.join(__dirname, '..', 'src', 'web-push-lib.js')]; + // delete require.cache[path.join(__dirname, '..', 'src', 'index.js')]; + // delete require.cache[path.join(__dirname, '..', 'src', 'web-push-lib.js')]; // Reset https request mock https.request = certHTTPSRequest; @@ -72,7 +68,7 @@ suite('sendNotification', function() { auth: userAuth.toString('base64url') }; - const vapidKeys = require('../src/vapid-helper').generateVAPIDKeys(); + const vapidKeys = generateVAPIDKeys(); function startServer() { const options = { diff --git a/test/testSetGCMAPIKey.js b/test/testSetGCMAPIKey.js index 30fb1e52..200b2fdc 100644 --- a/test/testSetGCMAPIKey.js +++ b/test/testSetGCMAPIKey.js @@ -1,7 +1,5 @@ -'use strict'; - -const assert = require('assert'); -const { setGCMAPIKey } = require('../src/index'); +import assert from 'assert'; +import { setGCMAPIKey } from '../src/index.js'; suite('setGCMAPIKey', function() { test('is defined', function() {