Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate from CommonJS to ESM #87

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 29 additions & 30 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
#!/usr/bin/env node

const minApiVersion = '1.2.7'

const { logger, getSymbol } = require('./lib/logger')
const config = require('./lib/args')
if (!config) {
import { logger, getSymbol } from './lib/logger.js'
import { options, configValid } from './lib/args.js'
if (!configValid) {
logger.end()
return
process.exit(1)
}
const auth = require('./lib/auth')
const api = require('./lib/api')
const {serializeError} = require('serialize-error')
import { startFsEventWatcher } from './lib/events.js'
import { getOpenIDConfiguration, getToken } from './lib/auth.js'
import { getDefinition, getCollection, getCollectionAssets, getInstalledStigs, getScapBenchmarkMap, getUser } from './lib/api.js'
import { serializeError } from 'serialize-error'
import { startScanner } from './lib/scan.js'
import semverGte from 'semver/functions/gte.js'

const minApiVersion = '1.2.7'

run()

Expand All @@ -19,17 +21,15 @@ async function run() {
logger.info({
component: 'main',
message: 'running',
config: getObfuscatedConfig(config)
options: getObfuscatedConfig(options)
})

await preflightServices()
if (config.mode === 'events') {
const watcher = require('./lib/events')
watcher.startFsEventWatcher()
if (options.mode === 'events') {
startFsEventWatcher()
}
else if (config.mode === 'scan') {
const scanner = require('./lib/scan')
scanner.startScanner()
else if (options.mode === 'scan') {
startScanner()
}
}
catch (e) {
Expand Down Expand Up @@ -63,8 +63,7 @@ function logError(e) {
}

async function hasMinApiVersion () {
const semverGte = require('semver/functions/gte')
const [remoteApiVersion] = await api.getDefinition('$.info.version')
const [remoteApiVersion] = await getDefinition('$.info.version')
logger.info({ component: 'main', message: `preflight API version`, minApiVersion, remoteApiVersion})
if (semverGte(remoteApiVersion, minApiVersion)) {
return true
Expand All @@ -76,22 +75,22 @@ async function hasMinApiVersion () {

async function preflightServices () {
await hasMinApiVersion()
await auth.getOpenIDConfiguration()
await auth.getToken()
await getOpenIDConfiguration()
await getToken()
logger.info({ component: 'main', message: `preflight token request suceeded`})
const promises = [
api.getCollection(config.collectionId),
api.getCollectionAssets(config.collectionId),
api.getInstalledStigs(),
api.getScapBenchmarkMap()
getCollection(options.collectionId),
getCollectionAssets(options.collectionId),
getInstalledStigs(),
getScapBenchmarkMap()
]
await Promise.all(promises)
setInterval(refreshCollection, 10 * 60000)

// OAuth scope 'stig-manager:user:read' was not required for early versions of Watcher
// For now, fail gracefully if we are blocked from calling /user
try {
await api.getUser()
await getUser()
setInterval(refreshUser, 10 * 60000)
}
catch (e) {
Expand All @@ -100,8 +99,8 @@ async function preflightServices () {
logger.info({ component: 'main', message: `prefilght api requests suceeded`})
}

function getObfuscatedConfig (config) {
const securedConfig = {...config}
function getObfuscatedConfig (options) {
const securedConfig = {...options}
if (securedConfig.clientSecret) {
securedConfig.clientSecret = '[hidden]'
}
Expand All @@ -110,7 +109,7 @@ function getObfuscatedConfig (config) {

async function refreshUser() {
try {
await api.getUser()
await getUser()
}
catch (e) {
logError(e)
Expand All @@ -119,7 +118,7 @@ async function refreshUser() {

async function refreshCollection() {
try {
await api.getCollection(config.collectionId)
await getCollection(options.collectionId)
}
catch (e) {
logError(e)
Expand Down
62 changes: 30 additions & 32 deletions lib/api.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@

const got = require('got')
const config = require('./args')
const auth = require('./auth')
const { logger, getSymbol } = require('./logger')
const { serializeError } = require('serialize-error')
import got from 'got'
import { options } from './args.js'
import { getToken, tokens } from './auth.js'
import { logger, getSymbol } from './logger.js'

const cache = {
collection: null,
Expand All @@ -13,21 +11,21 @@ const cache = {
scapBenchmarkMap: null,
stigs: null
}

module.exports.cache = cache
const _cache = cache
export { _cache as cache }

async function apiGet(endpoint, authenticate = true) {
try {
const options = {
const requestOptions = {
responseType: 'json'
}
if (authenticate) {
await auth.getToken()
options.headers = {
Authorization: `Bearer ${auth.tokens.access_token}`
await getToken()
requestOptions.headers = {
Authorization: `Bearer ${tokens.access_token}`
}
}
const response = await got.get(`${config.api}${endpoint}`, options)
const response = await got.get(`${options.api}${endpoint}`, requestOptions)
logResponse (response )
return response.body
}
Expand All @@ -38,38 +36,38 @@ async function apiGet(endpoint, authenticate = true) {
}
}

module.exports.getScapBenchmarkMap = async function () {
export async function getScapBenchmarkMap() {
const response = await apiGet('/stigs/scap-maps')
cache.scapBenchmarkMap = new Map(response.map(apiScapMap => [apiScapMap.scapBenchmarkId, apiScapMap.benchmarkId]))
return cache.scapBenchmarkMap
}

module.exports.getDefinition = async function (jsonPath) {
export async function getDefinition(jsonPath) {
cache.definition = await apiGet(`/op/definition${jsonPath ? '?jsonpath=' + encodeURIComponent(jsonPath) : ''}`, false)
return cache.definition
}

module.exports.getCollection = async function (collectionId) {
export async function getCollection(collectionId) {
cache.collection = await apiGet(`/collections/${collectionId}`)
return cache.collection
}

module.exports.getCollectionAssets = async function (collectionId) {
export async function getCollectionAssets(collectionId) {
cache.assets = await apiGet(`/assets?collectionId=${collectionId}&projection=stigs`)
return cache.assets
}

module.exports.getInstalledStigs = async function () {
export async function getInstalledStigs() {
cache.stigs = await apiGet('/stigs')
return cache.stigs
}

module.exports.createOrGetAsset = async function (asset) {
export async function createOrGetAsset(asset) {
try {
await auth.getToken()
const response = await got.post(`${config.api}/assets?projection=stigs`, {
await getToken()
const response = await got.post(`${options.api}/assets?projection=stigs`, {
headers: {
Authorization: `Bearer ${auth.tokens.access_token}`
Authorization: `Bearer ${tokens.access_token}`
},
json: asset,
responseType: 'json'
Expand All @@ -87,12 +85,12 @@ module.exports.createOrGetAsset = async function (asset) {
}
}

module.exports.patchAsset = async function (assetId, body) {
export async function patchAsset(assetId, body) {
try {
await auth.getToken()
const response = await got.patch(`${config.api}/assets/${assetId}?projection=stigs`, {
await getToken()
const response = await got.patch(`${options.api}/assets/${assetId}?projection=stigs`, {
headers: {
Authorization: `Bearer ${auth.tokens.access_token}`
Authorization: `Bearer ${tokens.access_token}`
},
json: body,
responseType: 'json'
Expand All @@ -106,12 +104,12 @@ module.exports.patchAsset = async function (assetId, body) {
}
}

module.exports.postReviews = async function (collectionId, assetId, reviews) {
export async function postReviews(collectionId, assetId, reviews) {
try {
await auth.getToken()
const response = await got.post(`${config.api}/collections/${collectionId}/reviews/${assetId}`, {
await getToken()
const response = await got.post(`${options.api}/collections/${collectionId}/reviews/${assetId}`, {
headers: {
Authorization: `Bearer ${auth.tokens.access_token}`
Authorization: `Bearer ${tokens.access_token}`
},
json: reviews,
responseType: 'json'
Expand All @@ -125,12 +123,12 @@ module.exports.postReviews = async function (collectionId, assetId, reviews) {
}
}

module.exports.getUser = async function () {
export async function getUser() {
cache.user = await apiGet('/user')
return cache.user
}

module.exports.canUserAccept = function () {
export function canUserAccept() {
const curUser = cache.user
const apiCollection = cache.collection
const userGrant = curUser.collectionGrants.find( i => i.collection.collectionId === apiCollection.collectionId )?.accessLevel
Expand Down
60 changes: 36 additions & 24 deletions lib/args.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,35 @@
const { Command, Option, InvalidOptionArgumentError } = require ('commander')
// set up a custom help for commander
require('./help')()

import help_default from './help.js'
help_default()

import { Command, Option, InvalidOptionArgumentError } from 'commander'
import { readFileSync } from 'fs'
import { logger, addConsoleTransport, addFileTransport } from './logger.js'
import { config } from 'dotenv'
import { resolve, sep, posix } from 'path'
import promptSync from 'prompt-sync'
import { createPrivateKey } from 'crypto'
import { fileURLToPath } from 'url';

const prompt = promptSync({ sigint:true })
const component = 'args'
const version = require("../package.json").version
const fs = require('fs')
const { logger, addConsoleTransport, addFileTransport } = require('./logger')
const dotenv = require('dotenv')
const Path = require('path')

function getVersion() {
try {
const packageJsonPath = fileURLToPath(new URL('../package.json', import.meta.url));
const packageJsonText = readFileSync(packageJsonPath, 'utf8');
return JSON.parse(packageJsonText).version;
} catch (error) {
console.error('Error reading package.json:', error);
}
}

let configValid = true

const version = getVersion();

// Use .env, if present, to setup the environment
dotenv.config()
config()

const pe = process.env //shorthand variable

Expand Down Expand Up @@ -112,8 +131,8 @@ options.version = version

// Set path variations
options._originalPath = options.path
options._resolvedPath = Path.resolve(options.path)
options.path = options.path.split(Path.sep).join(Path.posix.sep)
options._resolvedPath = resolve(options.path)
options.path = options.path.split(sep).join(posix.sep)

// Set dependent options
if (options.oneShot) {
Expand All @@ -131,7 +150,6 @@ if (options.logFile) {
}

// Validate we can perform the requested client authentication
const prompt = require('prompt-sync')({ sigint:true })
if (options.clientKey) {
try {
// Transform the path into a crypto private key object
Expand All @@ -146,9 +164,7 @@ if (options.clientKey) {
file: options.clientKey,
error: e
})
// Bail with no export object
module.exports = false
return
configValid = false
}
}
else {
Expand All @@ -163,9 +179,7 @@ else {
component: component,
message: 'Missing client secret'
})
// Bail with no export object
module.exports = false
return
configValid = false
}
}

Expand All @@ -177,22 +191,20 @@ logger.log({
})

function getPrivateKey( pemFile, passphrase, canPrompt) {
const prompt = require('prompt-sync')({ sigint:true })
const crypto = require('crypto')
let pemKey
try {
pemKey = fs.readFileSync(pemFile)
pemKey = readFileSync(pemFile)
}
finally {}
try {
return crypto.createPrivateKey({ key: pemKey, passphrase: passphrase })
return createPrivateKey({ key: pemKey, passphrase: passphrase })
}
catch (e) {
let clientKeyPassphrase
if (e.code === 'ERR_MISSING_PASSPHRASE' && canPrompt) {
clientKeyPassphrase = prompt(`Provide passphrase for the client private key: `, { echo: "*" })
try {
return crypto.createPrivateKey({ key: pemKey, passphrase: clientKeyPassphrase })
return createPrivateKey({ key: pemKey, passphrase: clientKeyPassphrase })
}
finally {}
}
Expand All @@ -202,5 +214,5 @@ function getPrivateKey( pemFile, passphrase, canPrompt) {
}
}

module.exports = options
export { options, configValid }

Loading
Loading