From 51bb7f76b8dfaccdbac9ab0a3d550be52c26a13e Mon Sep 17 00:00:00 2001 From: Markus Tacker Date: Thu, 5 Dec 2019 15:58:56 +0100 Subject: [PATCH] style: enable eslint --- .eslintrc | 3 + arm/resources.ts | 3 +- cli/bifravst.ts | 86 ++++++++++++++++-------- cli/commands/connect.ts | 91 ++++++++++++++++---------- cli/commands/create-ca-intermediate.ts | 47 ++++++++----- cli/commands/create-ca-root.ts | 30 ++++++--- cli/commands/create-device-cert.ts | 29 +++++--- cli/commands/proof-ca-possession.ts | 36 +++++++--- cli/iot/caFileLocations.ts | 6 +- cli/iot/deviceFileLocations.ts | 5 +- cli/iot/deviceTopics.ts | 14 ++-- cli/iot/dpsTopics.ts | 9 +-- cli/iot/generateCAIntermediate.ts | 44 +++++++------ cli/iot/generateCARoot.ts | 37 +++++++---- cli/iot/generateDeviceCertificate.ts | 66 +++++++++++-------- cli/iot/generateProofOfPosession.ts | 39 ++++++----- cli/iot/intermediateRegistry.ts | 52 ++++++++------- cli/iot/pemConfig.ts | 40 +++++------ cli/logging.ts | 6 +- cli/process/run.ts | 4 +- package.json | 5 ++ 21 files changed, 411 insertions(+), 241 deletions(-) create mode 100644 .eslintrc diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..5a80290 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,3 @@ +{ + "extends": "@bifravst/eslint-config-typescript" +} diff --git a/arm/resources.ts b/arm/resources.ts index 9becdfd..b9b2036 100644 --- a/arm/resources.ts +++ b/arm/resources.ts @@ -5,4 +5,5 @@ export const deploymentName = resourceGroupName /** * Returns the name of the Device Provisioning Service */ -export const iotDeviceProvisioningServiceName = () => `${resourceGroupName()}ProvisioningService` \ No newline at end of file +export const iotDeviceProvisioningServiceName = () => + `${resourceGroupName()}ProvisioningService` diff --git a/cli/bifravst.ts b/cli/bifravst.ts index 2c0f346..f8f14be 100644 --- a/cli/bifravst.ts +++ b/cli/bifravst.ts @@ -2,36 +2,59 @@ import * as program from 'commander' import chalk from 'chalk' import * as path from 'path' import { createCARootCommand } from './commands/create-ca-root' -import { IotHubClient } from "@azure/arm-iothub"; +import { IotHubClient } from '@azure/arm-iothub' import { IotDpsClient } from '@azure/arm-deviceprovisioningservices' -import { AzureCliCredentials } from "@azure/ms-rest-nodeauth"; -import { createDeviceCertCommand } from './commands/create-device-cert'; -import { connectCommand } from './commands/connect'; -import { run } from './process/run'; -import { proofCARootPossessionCommand } from './commands/proof-ca-possession'; -import { createCAIntermediateCommand } from './commands/create-ca-intermediate'; -import { iotDeviceProvisioningServiceName, resourceGroupName, deploymentName } from '../arm/resources'; - -const ioTHubDPSConnectionString = ({ deploymentName, resourceGroupName }: { deploymentName: string, resourceGroupName: string }) => async () => (await run({ - command: 'az', - args: [ - 'group', 'deployment', 'show', '-g', resourceGroupName, '-n', deploymentName, '--query', 'properties.outputs.ioTHubDPSConnectionString.value' - ] -})).replace(/"/g, '') +import { AzureCliCredentials } from '@azure/ms-rest-nodeauth' +import { createDeviceCertCommand } from './commands/create-device-cert' +import { connectCommand } from './commands/connect' +import { run } from './process/run' +import { proofCARootPossessionCommand } from './commands/proof-ca-possession' +import { createCAIntermediateCommand } from './commands/create-ca-intermediate' +import { + iotDeviceProvisioningServiceName, + resourceGroupName, + deploymentName, +} from '../arm/resources' + +const ioTHubDPSConnectionString = ({ + deploymentName, + resourceGroupName, +}: { + deploymentName: string + resourceGroupName: string +}) => async () => + ( + await run({ + command: 'az', + args: [ + 'group', + 'deployment', + 'show', + '-g', + resourceGroupName, + '-n', + deploymentName, + '--query', + 'properties.outputs.ioTHubDPSConnectionString.value', + ], + }) + ).replace(/"/g, '') const creds = async () => { - const creds = await AzureCliCredentials.create(); + const creds = await AzureCliCredentials.create() - const { tokenInfo: { subscription } } = creds + const { + tokenInfo: { subscription }, + } = creds console.log(chalk.magenta('Subscription ID:'), chalk.yellow(subscription)) return creds } -let currentCreds: Promise; +let currentCreds: Promise -const getCurrentCreds = () => { +const getCurrentCreds = async () => { if (!currentCreds) currentCreds = creds() return currentCreds } @@ -43,9 +66,18 @@ const bifravstCLI = async () => { const deployment = deploymentName() const dpsName = iotDeviceProvisioningServiceName() - const getIotHubConnectionString = ioTHubDPSConnectionString({ resourceGroupName: resourceGroup, deploymentName: deployment }) - const getIotDpsClient = () => getCurrentCreds().then(creds => new IotDpsClient(creds, creds.tokenInfo.subscription)) - const getIotClient = () => getCurrentCreds().then(creds => new IotHubClient(creds, creds.tokenInfo.subscription)) + const getIotHubConnectionString = ioTHubDPSConnectionString({ + resourceGroupName: resourceGroup, + deploymentName: deployment, + }) + const getIotDpsClient = async () => + getCurrentCreds().then( + creds => new IotDpsClient(creds, creds.tokenInfo.subscription), + ) + const getIotClient = async () => + getCurrentCreds().then( + creds => new IotHubClient(creds, creds.tokenInfo.subscription), + ) program.description('Bifravst Command Line Interface') @@ -54,26 +86,26 @@ const bifravstCLI = async () => { certsDir, iotDpsClient: getIotDpsClient, dpsName, - resourceGroup + resourceGroup, }), proofCARootPossessionCommand({ iotDpsClient: getIotDpsClient, certsDir, dpsName, - resourceGroup + resourceGroup, }), createCAIntermediateCommand({ certsDir, ioTHubDPSConnectionString: getIotHubConnectionString, - iotDpsClient: getIotDpsClient + iotDpsClient: getIotDpsClient, }), createDeviceCertCommand({ iotClient: getIotClient, - certsDir + certsDir, }), connectCommand({ iotDpsClient: getIotDpsClient, - certsDir + certsDir, }), ] diff --git a/cli/commands/connect.ts b/cli/commands/connect.ts index 2383c09..b25ee6e 100644 --- a/cli/commands/connect.ts +++ b/cli/commands/connect.ts @@ -16,23 +16,19 @@ const deviceUiUrl = process.env.DEVICE_UI_LOCATION || '' export const connectCommand = ({ certsDir, - iotDpsClient + iotDpsClient, }: { iotDpsClient: () => Promise certsDir: string }): ComandDefinition => ({ command: 'connect ', action: async (deviceId: string) => { - const deviceFiles = deviceFileLocations({ certsDir, - deviceId + deviceId, }) - const [ - deviceCert, - deviceKey, - ] = await Promise.all([ + const [deviceCert, deviceKey] = await Promise.all([ fs.readFile(deviceFiles.certWithChain, 'utf-8'), fs.readFile(deviceFiles.privateKey, 'utf-8'), ]) @@ -40,16 +36,19 @@ export const connectCommand = ({ let iotHub try { - const registration = JSON.parse(await fs.readFile(deviceFiles.registration, - 'utf-8')) as DeviceRegistrationState + const registration = JSON.parse( + await fs.readFile(deviceFiles.registration, 'utf-8'), + ) as DeviceRegistrationState iotHub = registration.assignedHub } catch { - // Connect to Device Provisioning Service using MQTT // @see https://docs.microsoft.com/en-us/azure/iot-dps/iot-dps-mqtt-support const armDpsClient = await iotDpsClient() - const dps = await armDpsClient.iotDpsResource.get('bifravstProvisioningService', 'bifravst') + const dps = await armDpsClient.iotDpsResource.get( + 'bifravstProvisioningService', + 'bifravst', + ) const dpsHostname = dps.properties.serviceOperationsHostName as string const idScope = dps.properties.idScope as string console.log(chalk.magenta(`Connecting to`), chalk.yellow(dpsHostname)) @@ -74,9 +73,12 @@ export const connectCommand = ({ console.log(chalk.magenta('Connected:'), chalk.yellow(deviceId)) // The device should publish a register message to DPS using $dps/registrations/PUT/iotdps-register/?$rid={request_id} as a Topic Name. The payload should contain the Device Registration object in JSON format. In a successful scenario, the device will receive a response on the $dps/registrations/res/202/?$rid={request_id}&retry-after=x topic name where x is the retry-after value in seconds. The payload of the response will contain the RegistrationOperationStatus object in JSON format. - client.publish(dpsTopics.register(), JSON.stringify({ - registrationId: deviceId - })) + client.publish( + dpsTopics.register(), + JSON.stringify({ + registrationId: deviceId, + }), + ) }) // The device must poll the service periodically to receive the result of the device registration operation. @@ -84,22 +86,28 @@ export const connectCommand = ({ client.on('message', (topic, payload) => { console.debug(chalk.magenta(topic), chalk.yellow(payload.toString())) const message = JSON.parse(payload.toString()) - if (topic.indexOf(dpsTopics.registrationResult(202)) === 0) { + if (topic.startsWith(dpsTopics.registrationResult(202))) { const args = new URLSearchParams(`${parse(topic).query}`) const { operationId, status } = message console.log(chalk.magenta('Status:'), chalk.yellow(status)) - console.log(chalk.magenta('Retry after:'), chalk.yellow(args.get('retry-after') as string)) + console.log( + chalk.magenta('Retry after:'), + chalk.yellow(args.get('retry-after') as string), + ) setTimeout(() => { - // Assuming that the device has already subscribed to the $dps/registrations/res/# topic as indicated above, it can publish a get operationstatus message to the $dps/registrations/GET/iotdps-get-operationstatus/?$rid={request_id}&operationId={operationId} topic name. The operation ID in this message should be the value received in the RegistrationOperationStatus response message in the previous step. + // Assuming that the device has already subscribed to the $dps/registrations/res/# topic as indicated above, it can publish a get operationstatus message to the $dps/registrations/GET/iotdps-get-operationstatus/?$rid={request_id}&operationId={operationId} topic name. The operation ID in this message should be the value received in the RegistrationOperationStatus response message in the previous step. client.publish(dpsTopics.registationStatus(operationId), '') }, parseInt(args.get('retry-after') || '1', 10) * 1000) return } // In the successful case, the service will respond on the $dps/registrations/res/200/?$rid={request_id} topic. The payload of the response will contain the RegistrationOperationStatus object. The device should keep polling the service if the response code is 202 after a delay equal to the retry-after period. The device registration operation is successful if the service returns a 200 status code. - if (topic.indexOf(dpsTopics.registrationResult(200)) === 0) { + if (topic.startsWith(dpsTopics.registrationResult(200))) { const { status, registrationState } = message console.log(chalk.magenta('Status:'), chalk.yellow(status)) - console.log(chalk.magenta('IoT Hub:'), chalk.yellow(registrationState.assignedHub)) + console.log( + chalk.magenta('IoT Hub:'), + chalk.yellow(registrationState.assignedHub), + ) resolve(registrationState) } reject(new Error(`Unexpected message on topic ${topic}!`)) @@ -117,11 +125,17 @@ export const connectCommand = ({ iotHub = registration.assignedHub - console.log(chalk.green(`Device registration succeeded with IotHub`), chalk.blueBright(iotHub)) + console.log( + chalk.green(`Device registration succeeded with IotHub`), + chalk.blueBright(iotHub), + ) - await fs.writeFile(deviceFiles.registration, JSON.stringify(registration, null, 2), 'utf-8') + await fs.writeFile( + deviceFiles.registration, + JSON.stringify(registration, null, 2), + 'utf-8', + ) } finally { - console.log(chalk.magenta(`Connecting to`), chalk.yellow(`${iotHub}`)) const client = connect({ @@ -137,7 +151,7 @@ export const connectCommand = ({ }) let cfg = { - ...defaultConfig + ...defaultConfig, } let wsConnection: WebSocketConnection @@ -159,7 +173,9 @@ export const connectCommand = ({ client.on('connect', async () => { console.log(chalk.green('Connected:'), chalk.blueBright(deviceId)) - const getTwinPropertiesTopic = deviceTopics.getTwinProperties(getTwinPropertiesRequestId) + const getTwinPropertiesTopic = deviceTopics.getTwinProperties( + getTwinPropertiesRequestId, + ) console.log(chalk.magenta('>'), chalk.yellow(getTwinPropertiesTopic)) client.publish(getTwinPropertiesTopic, '') @@ -169,7 +185,10 @@ export const connectCommand = ({ onUpdate: update => { console.log(chalk.magenta('<'), chalk.cyan(JSON.stringify(update))) updateReportedRequestId = v4() - client.publish(deviceTopics.updateTwinReported(updateReportedRequestId), JSON.stringify(update)) + client.publish( + deviceTopics.updateTwinReported(updateReportedRequestId), + JSON.stringify(update), + ) }, onWsConnection: c => { console.log(chalk.magenta('[ws]'), chalk.cyan('connected')) @@ -182,23 +201,30 @@ export const connectCommand = ({ client.on('message', (topic, payload) => { console.log(chalk.magenta('<'), chalk.yellow(topic)) if (payload.length) { - console.log( - chalk.magenta('<'), - chalk.cyan(payload.toString()), - ) + console.log(chalk.magenta('<'), chalk.cyan(payload.toString())) } - if (topic === deviceTopics.twinResponse({ rid: getTwinPropertiesRequestId, status: 200 })) { + if ( + topic === + deviceTopics.twinResponse({ + rid: getTwinPropertiesRequestId, + status: 200, + }) + ) { const p = JSON.parse(payload.toString()) cfg = { ...cfg, - ...p.desired.cfg + ...p.desired.cfg, } console.log(chalk.blue('Config:')) console.log(cfg) sendConfigToUi() return } - if (deviceTopics.updateTwinReportedAccepted(updateReportedRequestId).test(topic)) { + if ( + deviceTopics + .updateTwinReportedAccepted(updateReportedRequestId) + .test(topic) + ) { // pass return } @@ -212,4 +238,3 @@ export const connectCommand = ({ }, help: 'Connect to the IoT Hub', }) - diff --git a/cli/commands/create-ca-intermediate.ts b/cli/commands/create-ca-intermediate.ts index ff2532a..45eb7d5 100644 --- a/cli/commands/create-ca-intermediate.ts +++ b/cli/commands/create-ca-intermediate.ts @@ -17,14 +17,13 @@ export const createCAIntermediateCommand = ({ }): ComandDefinition => ({ command: 'create-ca-intermediate', action: async () => { - const id = v4() const intermediate = await generateCAIntermediate({ id, certsDir, log, - debug + debug, }) console.log(chalk.magenta(`CA intermediate certificate generated.`)) @@ -34,38 +33,56 @@ export const createCAIntermediateCommand = ({ const dpsConnString = await ioTHubDPSConnectionString() - const dpsClient = ProvisioningServiceClient.fromConnectionString(dpsConnString) + const dpsClient = ProvisioningServiceClient.fromConnectionString( + dpsConnString, + ) const enrollmentGroupId = `bifravst-${id}` + // FIXME: Remove undefined, once https://github.com/Azure/azure-iot-sdk-node/pull/663 is released await dpsClient.createOrUpdateEnrollmentGroup({ enrollmentGroupId, attestation: { type: 'x509', - //@ts-ignore x509: { signingCertificates: { primary: { - certificate: intermediate.certificate - } - } - } + certificate: intermediate.certificate, + info: undefined as any, + }, + secondary: undefined as any, + }, + clientCertificates: undefined as any, + caReferences: undefined as any, + }, }, - provisioningStatus: "enabled", + provisioningStatus: 'enabled', reprovisionPolicy: { migrateDeviceData: true, - updateHubAssignment: true - } + updateHubAssignment: true, + }, + initialTwin: undefined as any, + iotHubHostName: undefined as any, + iotHubs: undefined as any, + etag: undefined as any, + createdDateTimeUtc: undefined as any, + lastUpdatedDateTimeUtc: undefined as any, }) console.log( - chalk.magenta(`Created enrollment group for CA intermediate certificiate`), - chalk.yellow(enrollmentGroupId) + chalk.magenta( + `Created enrollment group for CA intermediate certificiate`, + ), + chalk.yellow(enrollmentGroupId), ) console.log() - console.log(chalk.green('You can now generate device certificates using'), chalk.blueBright('node cli generate-device-cert')) + console.log( + chalk.green('You can now generate device certificates using'), + chalk.blueBright('node cli generate-device-cert'), + ) }, - help: 'Creates a CA intermediate certificate registers it with an IoT Device Provisioning Service enrollment group', + help: + 'Creates a CA intermediate certificate registers it with an IoT Device Provisioning Service enrollment group', }) diff --git a/cli/commands/create-ca-root.ts b/cli/commands/create-ca-root.ts index 0bfe0ea..30bc184 100644 --- a/cli/commands/create-ca-root.ts +++ b/cli/commands/create-ca-root.ts @@ -25,7 +25,7 @@ export const createCARootCommand = ({ certsDir, name: certificateName, log, - debug + debug, }) console.log(chalk.magenta(`CA root certificate generated.`)) @@ -38,23 +38,29 @@ export const createCARootCommand = ({ dpsName, certificateName, { - certificate: root.certificate + certificate: root.certificate, }, ) console.log( chalk.magenta(`CA root registered with DPS.`), - chalk.yellow(dpsName) + chalk.yellow(dpsName), ) // Create verification cert - const { etag } = await armDpsClient.dpsCertificate.get(certificateName, resourceGroup, dpsName) - const { properties } = await armDpsClient.dpsCertificate.generateVerificationCode( + const { etag } = await armDpsClient.dpsCertificate.get( + certificateName, + resourceGroup, + dpsName, + ) + const { + properties, + } = await armDpsClient.dpsCertificate.generateVerificationCode( certificateName, etag as string, resourceGroup, - dpsName + dpsName, ) if (!properties?.verificationCode) { @@ -65,17 +71,21 @@ export const createCARootCommand = ({ certsDir, log, debug, - verificationCode: properties.verificationCode + verificationCode: properties.verificationCode, }) console.log( chalk.magenta(`Generated verification certificate for verification code`), - chalk.yellow(properties.verificationCode) + chalk.yellow(properties.verificationCode), ) console.log() - console.log(chalk.green('You can now verify the proof of posession using'), chalk.blueBright('node cli proof-ca-root-possession')) + console.log( + chalk.green('You can now verify the proof of posession using'), + chalk.blueBright('node cli proof-ca-root-possession'), + ) }, - help: 'Creates a CA root certificate and registers it with the IoT Device Provisioning Service', + help: + 'Creates a CA root certificate and registers it with the IoT Device Provisioning Service', }) diff --git a/cli/commands/create-device-cert.ts b/cli/commands/create-device-cert.ts index 95bfc1c..4791244 100644 --- a/cli/commands/create-device-cert.ts +++ b/cli/commands/create-device-cert.ts @@ -2,14 +2,14 @@ import chalk from 'chalk' import { ComandDefinition } from './CommandDefinition' import { randomWords } from '@bifravst/random-words' import { generateDeviceCertificate } from '../iot/generateDeviceCertificate' -import { IotHubClient } from "@azure/arm-iothub"; +import { IotHubClient } from '@azure/arm-iothub' import { log, debug } from '../logging' import { list as listIntermediateCerts } from '../iot/intermediateRegistry' export const createDeviceCertCommand = ({ certsDir, }: { - iotClient: () => Promise, + iotClient: () => Promise certsDir: string }): ComandDefinition => ({ command: 'create-device-cert', @@ -20,10 +20,17 @@ export const createDeviceCertCommand = ({ }, { flags: '-i, --intermediateCertId ', - description: 'ID of the CA intermediate certificate to use, if left blank the first will be used', + description: + 'ID of the CA intermediate certificate to use, if left blank the first will be used', }, ], - action: async ({ deviceId, intermediateCertId }: { deviceId: string, intermediateCertId: string }) => { + action: async ({ + deviceId, + intermediateCertId, + }: { + deviceId: string + intermediateCertId: string + }) => { const id = deviceId || (await randomWords({ numWords: 3 })).join('-') if (!intermediateCertId) { @@ -31,22 +38,26 @@ export const createDeviceCertCommand = ({ intermediateCertId = intermediateCerts[0] } - console.log(chalk.magenta('Intermediate certificate:'), chalk.yellow(intermediateCertId)) + console.log( + chalk.magenta('Intermediate certificate:'), + chalk.yellow(intermediateCertId), + ) await generateDeviceCertificate({ deviceId: id, certsDir, log, debug, - intermediateCertId - + intermediateCertId, }) console.log( chalk.magenta(`Certificate for device ${chalk.yellow(id)} generated.`), ) - console.log(chalk.green('You can now connect to the broker using'), chalk.blueBright(`node cli connect ${id}`)) + console.log( + chalk.green('You can now connect to the broker using'), + chalk.blueBright(`node cli connect ${id}`), + ) }, help: 'Generate a device certificate and register a device in the registry.', }) - diff --git a/cli/commands/proof-ca-possession.ts b/cli/commands/proof-ca-possession.ts index 7f9bece..5cf23e6 100644 --- a/cli/commands/proof-ca-possession.ts +++ b/cli/commands/proof-ca-possession.ts @@ -17,26 +17,44 @@ export const proofCARootPossessionCommand = ({ }): ComandDefinition => ({ command: 'proof-ca-root-possession', action: async () => { - const certLocations = CARootFileLocations(certsDir) - const certificateName = (await fs.readFile(certLocations.name, 'utf-8')).trim() + const certificateName = ( + await fs.readFile(certLocations.name, 'utf-8') + ).trim() const armDpsClient = await iotDpsClient() - const { etag } = await armDpsClient.dpsCertificate.get(certificateName, resourceGroup, dpsName) + const { etag } = await armDpsClient.dpsCertificate.get( + certificateName, + resourceGroup, + dpsName, + ) - const verificationCert = await fs.readFile(certLocations.verificationCert, 'utf-8') + const verificationCert = await fs.readFile( + certLocations.verificationCert, + 'utf-8', + ) console.log(chalk.magenta('Certificate:'), chalk.yellow(certificateName)) - await armDpsClient.dpsCertificate.verifyCertificate(certificateName, etag as string, { - certificate: verificationCert, - }, resourceGroup, dpsName) + await armDpsClient.dpsCertificate.verifyCertificate( + certificateName, + etag as string, + { + certificate: verificationCert, + }, + resourceGroup, + dpsName, + ) console.log(chalk.magenta('Verified root CA certificate.')) console.log() - console.log(chalk.green('You can now create a CA intermediate certificate using'), chalk.blueBright('node cli create-ca-intermediate')) + console.log( + chalk.green('You can now create a CA intermediate certificate using'), + chalk.blueBright('node cli create-ca-intermediate'), + ) }, - help: 'Verifies the root CA certificate which is registered with the Device Provisioning System', + help: + 'Verifies the root CA certificate which is registered with the Device Provisioning System', }) diff --git a/cli/iot/caFileLocations.ts b/cli/iot/caFileLocations.ts index 21c3dc7..63c4ea6 100644 --- a/cli/iot/caFileLocations.ts +++ b/cli/iot/caFileLocations.ts @@ -10,11 +10,11 @@ export const CARootFileLocations = (certsDir: string) => ({ export const CAIntermediateFileLocations = ({ certsDir, - id + id, }: { - certsDir: string, + certsDir: string id: string }) => ({ privateKey: path.resolve(certsDir, `CA.intermediate.${id}.key`), cert: path.resolve(certsDir, `CA.intermediate.${id}.pem`), -}) \ No newline at end of file +}) diff --git a/cli/iot/deviceFileLocations.ts b/cli/iot/deviceFileLocations.ts index 6c9a16b..d25317c 100644 --- a/cli/iot/deviceFileLocations.ts +++ b/cli/iot/deviceFileLocations.ts @@ -11,5 +11,8 @@ export const deviceFileLocations = ({ cert: path.resolve(certsDir, `device-${deviceId}.pem`), certWithChain: path.resolve(certsDir, `device-${deviceId}.bundle.pem`), registration: path.resolve(certsDir, `device-${deviceId}.registration.json`), - intermediateCertId: path.resolve(certsDir, `device-${deviceId}.intermediateCertId`), + intermediateCertId: path.resolve( + certsDir, + `device-${deviceId}.intermediateCertId`, + ), }) diff --git a/cli/iot/deviceTopics.ts b/cli/iot/deviceTopics.ts index 157468a..bf7eec4 100644 --- a/cli/iot/deviceTopics.ts +++ b/cli/iot/deviceTopics.ts @@ -1,8 +1,10 @@ - -export const deviceTopics = ({ +export const deviceTopics = { getTwinProperties: (rid: string) => `$iothub/twin/GET/?$rid=${rid}`, - updateTwinReported: (rid: string) => `$iothub/twin/PATCH/properties/reported/?$rid=${rid}`, - updateTwinReportedAccepted: (rid: string) => new RegExp(`^\\$iothub/twin/res/204/\\?\\$rid=${rid}&\\$version=[0-9]+$`), + updateTwinReported: (rid: string) => + `$iothub/twin/PATCH/properties/reported/?$rid=${rid}`, + updateTwinReportedAccepted: (rid: string) => + new RegExp(`^\\$iothub/twin/res/204/\\?\\$rid=${rid}&\\$version=[0-9]+$`), twinResponses: '$iothub/twin/res/#', - twinResponse: ({ status, rid }: { status: number, rid: string }) => `$iothub/twin/res/${status}/?$rid=${rid}` -}) + twinResponse: ({ status, rid }: { status: number; rid: string }) => + `$iothub/twin/res/${status}/?$rid=${rid}`, +} diff --git a/cli/iot/dpsTopics.ts b/cli/iot/dpsTopics.ts index a754671..c245cbd 100644 --- a/cli/iot/dpsTopics.ts +++ b/cli/iot/dpsTopics.ts @@ -1,8 +1,9 @@ import { v4 } from 'uuid' -export const dpsTopics = ({ +export const dpsTopics = { registrationResponses: '$dps/registrations/res/#', register: () => `$dps/registrations/PUT/iotdps-register/?$rid=${v4()}`, - registationStatus: (operationId: string) => `$dps/registrations/GET/iotdps-get-operationstatus/?$rid=${v4()}&operationId=${operationId}`, - registrationResult: (status: number) => `$dps/registrations/res/${status}` -}) + registationStatus: (operationId: string) => + `$dps/registrations/GET/iotdps-get-operationstatus/?$rid=${v4()}&operationId=${operationId}`, + registrationResult: (status: number) => `$dps/registrations/res/${status}`, +} diff --git a/cli/iot/generateCAIntermediate.ts b/cli/iot/generateCAIntermediate.ts index 6988942..80fe96e 100644 --- a/cli/iot/generateCAIntermediate.ts +++ b/cli/iot/generateCAIntermediate.ts @@ -1,5 +1,8 @@ import { promises as fs } from 'fs' -import { CARootFileLocations, CAIntermediateFileLocations } from './caFileLocations' +import { + CARootFileLocations, + CAIntermediateFileLocations, +} from './caFileLocations' import { createCertificate, CertificateCreationResult } from 'pem' import { caCertConfig } from './pemConfig' @@ -21,36 +24,39 @@ export const generateCAIntermediate = async (args: { const caIntermediateFiles = CAIntermediateFileLocations({ certsDir, - id + id, }) - const [ - rootPrivateKey, - rootCert - ] = await Promise.all([ + const [rootPrivateKey, rootCert] = await Promise.all([ fs.readFile(caRootFiles.privateKey, 'utf-8'), fs.readFile(caRootFiles.cert, 'utf-8'), ]) const intermediateName = `Bifravst Intermediate CA (${id})` - const intermediateCert = await new Promise((resolve, reject) => createCertificate({ - commonName: intermediateName, - serial: Math.floor(Math.random() * 1000000000), - days: 365, - config: caCertConfig(intermediateName), - serviceKey: rootPrivateKey, - serviceCertificate: rootCert - }, (err, cert) => { - if (err) return reject(err) - resolve(cert) - })) + const intermediateCert = await new Promise( + (resolve, reject) => + createCertificate( + { + commonName: intermediateName, + serial: Math.floor(Math.random() * 1000000000), + days: 365, + config: caCertConfig(intermediateName), + serviceKey: rootPrivateKey, + serviceCertificate: rootCert, + }, + (err, cert) => { + if (err) return reject(err) + resolve(cert) + }, + ), + ) log('Intermediate CA Certificate', caIntermediateFiles.cert) debug(intermediateCert.certificate) - await fs.writeFile(caIntermediateFiles.cert, intermediateCert.certificate); - await fs.writeFile(caIntermediateFiles.privateKey, intermediateCert.clientKey); + await fs.writeFile(caIntermediateFiles.cert, intermediateCert.certificate) + await fs.writeFile(caIntermediateFiles.privateKey, intermediateCert.clientKey) return intermediateCert } diff --git a/cli/iot/generateCARoot.ts b/cli/iot/generateCARoot.ts index e2043fe..6f1f108 100644 --- a/cli/iot/generateCARoot.ts +++ b/cli/iot/generateCARoot.ts @@ -5,11 +5,16 @@ import { caCertConfig } from './pemConfig' /** * Generates a CA Root certificate - * + * * @see https://github.com/Azure/azure-iot-sdk-node/blob/5a7cd40145575175b4a100bbc84758f8a87c6d37/provisioning/tools/create_test_cert.js * @see http://busbyland.com/azure-iot-device-provisioning-service-via-rest-part-1/ */ -export const generateCARoot = async ({ certsDir, name, log, debug }: { +export const generateCARoot = async ({ + certsDir, + name, + log, + debug, +}: { certsDir: string name: string log: (...message: any[]) => void @@ -36,21 +41,27 @@ export const generateCARoot = async ({ certsDir, name, log, debug }: { // Create the Root CA Cert - const rootCert = await new Promise((resolve, reject) => createCertificate({ - commonName: name, - serial: Math.floor(Math.random() * 1000000000), - days: 365, - selfSigned: true, - config: caCertConfig(name) - }, (err, cert) => { - if (err) return reject(err) - resolve(cert) - })) + const rootCert = await new Promise( + (resolve, reject) => + createCertificate( + { + commonName: name, + serial: Math.floor(Math.random() * 1000000000), + days: 365, + selfSigned: true, + config: caCertConfig(name), + }, + (err, cert) => { + if (err) return reject(err) + resolve(cert) + }, + ), + ) await Promise.all([ fs.writeFile(caFiles.cert, rootCert.certificate, 'utf-8'), fs.writeFile(caFiles.privateKey, rootCert.clientKey, 'utf-8'), - fs.writeFile(caFiles.name, name, 'utf-8') + fs.writeFile(caFiles.name, name, 'utf-8'), ]) log('Root CA Certificate', caFiles.cert) diff --git a/cli/iot/generateDeviceCertificate.ts b/cli/iot/generateDeviceCertificate.ts index 7591aed..0b06557 100644 --- a/cli/iot/generateDeviceCertificate.ts +++ b/cli/iot/generateDeviceCertificate.ts @@ -1,5 +1,8 @@ import { promises as fs } from 'fs' -import { CARootFileLocations, CAIntermediateFileLocations } from './caFileLocations' +import { + CARootFileLocations, + CAIntermediateFileLocations, +} from './caFileLocations' import { deviceFileLocations } from './deviceFileLocations' import * as os from 'os' import { createCertificate, CertificateCreationResult } from 'pem' @@ -23,7 +26,10 @@ export const generateDeviceCertificate = async ({ }): Promise<{ deviceId: string }> => { log && log(`Generating certificate for device ${deviceId}`) const caRootFiles = CARootFileLocations(certsDir) - const caIntermediateFiles = CAIntermediateFileLocations({ certsDir, id: intermediateCertId }) + const caIntermediateFiles = CAIntermediateFileLocations({ + certsDir, + id: intermediateCertId, + }) const deviceFiles = deviceFileLocations({ certsDir, deviceId, @@ -32,46 +38,54 @@ export const generateDeviceCertificate = async ({ const [ intermediatePrivateKey, intermediateCert, - rootCert + rootCert, ] = await Promise.all([ fs.readFile(caIntermediateFiles.privateKey, 'utf-8'), fs.readFile(caIntermediateFiles.cert, 'utf-8'), - fs.readFile(caRootFiles.cert, 'utf-8') + fs.readFile(caRootFiles.cert, 'utf-8'), ]) - const deviceCert = await new Promise((resolve, reject) => createCertificate({ - commonName: deviceId, - serial: Math.floor(Math.random() * 1000000000), - days: 365, - config: leafCertConfig(deviceId), - serviceKey: intermediatePrivateKey, - serviceCertificate: intermediateCert - }, (err, cert) => { - if (err) return reject(err) - resolve(cert) - })) + const deviceCert = await new Promise( + (resolve, reject) => + createCertificate( + { + commonName: deviceId, + serial: Math.floor(Math.random() * 1000000000), + days: 365, + config: leafCertConfig(deviceId), + serviceKey: intermediatePrivateKey, + serviceCertificate: intermediateCert, + }, + (err, cert) => { + if (err) return reject(err) + resolve(cert) + }, + ), + ) debug && debug(deviceCert.certificate) - const certWithChain = (await Promise.all([ - deviceCert.certificate, - intermediateCert, - rootCert, - ])).join(os.EOL) + const certWithChain = ( + await Promise.all([deviceCert.certificate, intermediateCert, rootCert]) + ).join(os.EOL) await Promise.all([ fs.writeFile(deviceFiles.certWithChain, certWithChain, 'utf-8').then(() => { debug && debug(`${deviceFiles.certWithChain} written`) }), - fs.writeFile(deviceFiles.privateKey, deviceCert.clientKey, 'utf-8').then(() => { - debug && debug(`${deviceFiles.privateKey} written`) - }), + fs + .writeFile(deviceFiles.privateKey, deviceCert.clientKey, 'utf-8') + .then(() => { + debug && debug(`${deviceFiles.privateKey} written`) + }), fs.writeFile(deviceFiles.cert, deviceCert.certificate, 'utf-8').then(() => { debug && debug(`${deviceFiles.cert} written`) }), - fs.writeFile(deviceFiles.intermediateCertId, intermediateCertId, 'utf-8').then(() => { - debug && debug(`${deviceFiles.intermediateCertId} written`) - }), + fs + .writeFile(deviceFiles.intermediateCertId, intermediateCertId, 'utf-8') + .then(() => { + debug && debug(`${deviceFiles.intermediateCertId} written`) + }), ]) return { deviceId } diff --git a/cli/iot/generateProofOfPosession.ts b/cli/iot/generateProofOfPosession.ts index 713716b..fc0149f 100644 --- a/cli/iot/generateProofOfPosession.ts +++ b/cli/iot/generateProofOfPosession.ts @@ -13,35 +13,38 @@ export const generateProofOfPosession = async (args: { verificationCode: string log: (...message: any[]) => void debug: (...message: any[]) => void -}): Promise<{ verification: CertificateCreationResult, }> => { +}): Promise<{ verification: CertificateCreationResult }> => { const { certsDir, log, debug, verificationCode } = args const caFiles = CARootFileLocations(certsDir) - const [ - rootKey, - rootCert - ] = await Promise.all([ + const [rootKey, rootCert] = await Promise.all([ fs.readFile(caFiles.privateKey, 'utf-8'), fs.readFile(caFiles.cert, 'utf-8'), ]) - const verificationCert = await new Promise((resolve, reject) => createCertificate({ - commonName: verificationCode, - serial: Math.floor(Math.random() * 1000000000), - days: 1, - config: leafCertConfig(verificationCode), - serviceKey: rootKey, - serviceCertificate: rootCert - }, (err, cert) => { - if (err) return reject(err) - resolve(cert) - })) + const verificationCert = await new Promise( + (resolve, reject) => + createCertificate( + { + commonName: verificationCode, + serial: Math.floor(Math.random() * 1000000000), + days: 1, + config: leafCertConfig(verificationCode), + serviceKey: rootKey, + serviceCertificate: rootCert, + }, + (err, cert) => { + if (err) return reject(err) + resolve(cert) + }, + ), + ) log('Verification cert', caFiles.verificationCert) debug(verificationCert.certificate) - await fs.writeFile(caFiles.verificationCert, verificationCert.certificate); - await fs.writeFile(caFiles.verificationKey, verificationCert.clientKey); + await fs.writeFile(caFiles.verificationCert, verificationCert.certificate) + await fs.writeFile(caFiles.verificationKey, verificationCert.clientKey) return { verification: verificationCert, diff --git a/cli/iot/intermediateRegistry.ts b/cli/iot/intermediateRegistry.ts index 0f39b4f..31a3a03 100644 --- a/cli/iot/intermediateRegistry.ts +++ b/cli/iot/intermediateRegistry.ts @@ -2,31 +2,37 @@ import { promises as fs } from 'fs' import * as path from 'path' export const CAIntermediateRegistryLocation = (certsDir: string) => ({ - registry: path.resolve(certsDir, 'intermediate.json'), + registry: path.resolve(certsDir, 'intermediate.json'), }) -export const add = async ({ certsDir, id }: { certsDir: string, id: string }) => { - const intermediateRegistry = CAIntermediateRegistryLocation(certsDir).registry - let registry = [] as string[] - - try { - registry = [ - id, - ...(await list({ certsDir })) - ] - } catch { - registry = [id] - } finally { - await fs.writeFile(intermediateRegistry, JSON.stringify(registry), 'utf-8') - } +export const list = async ({ + certsDir, +}: { + certsDir: string +}): Promise => { + const intermediateRegistry = CAIntermediateRegistryLocation(certsDir).registry + try { + return JSON.parse(await fs.readFile(intermediateRegistry, 'utf-8')) + } catch { + return [] + } } -export const list = async ({ certsDir }: { certsDir: string }): Promise => { - const intermediateRegistry = CAIntermediateRegistryLocation(certsDir).registry - try { - return JSON.parse(await fs.readFile(intermediateRegistry, 'utf-8')) - } catch { - return [] - } -} +export const add = async ({ + certsDir, + id, +}: { + certsDir: string + id: string +}) => { + const intermediateRegistry = CAIntermediateRegistryLocation(certsDir).registry + let registry = [] as string[] + try { + registry = [id, ...(await list({ certsDir }))] + } catch { + registry = [id] + } finally { + await fs.writeFile(intermediateRegistry, JSON.stringify(registry), 'utf-8') + } +} diff --git a/cli/iot/pemConfig.ts b/cli/iot/pemConfig.ts index daf3472..eb91d03 100644 --- a/cli/iot/pemConfig.ts +++ b/cli/iot/pemConfig.ts @@ -1,20 +1,22 @@ -export const caCertConfig = (commonName: string) => [ - '[req]', - 'req_extensions = v3_req', - 'distinguished_name = req_distinguished_name', - 'x509_extensions = v3_ca', - '[req_distinguished_name]', - 'commonName = ' + commonName, - '[v3_req]', - 'basicConstraints = critical,CA:true' -].join('\n') +export const caCertConfig = (commonName: string) => + [ + '[req]', + 'req_extensions = v3_req', + 'distinguished_name = req_distinguished_name', + 'x509_extensions = v3_ca', + '[req_distinguished_name]', + 'commonName = ' + commonName, + '[v3_req]', + 'basicConstraints = critical,CA:true', + ].join('\n') -export const leafCertConfig = (commonName: string) => [ - '[req]', - 'req_extensions = v3_req', - 'distinguished_name = req_distinguished_name', - '[req_distinguished_name]', - 'commonName = ' + commonName, - '[v3_req]', - 'extendedKeyUsage = critical,clientAuth' -].join('\n') \ No newline at end of file +export const leafCertConfig = (commonName: string) => + [ + '[req]', + 'req_extensions = v3_req', + 'distinguished_name = req_distinguished_name', + '[req_distinguished_name]', + 'commonName = ' + commonName, + '[v3_req]', + 'extendedKeyUsage = critical,clientAuth', + ].join('\n') diff --git a/cli/logging.ts b/cli/logging.ts index 0fcb332..86e0695 100644 --- a/cli/logging.ts +++ b/cli/logging.ts @@ -1,9 +1,9 @@ import chalk from 'chalk' export const log = (...message: any[]) => { - console.log(...message.map(m => chalk.magenta(m))) + console.log(...message.map(m => chalk.magenta(m))) } export const debug = (...message: any[]) => { - console.log(...message.map(m => chalk.cyan(m))) -} \ No newline at end of file + console.log(...message.map(m => chalk.cyan(m))) +} diff --git a/cli/process/run.ts b/cli/process/run.ts index ede796a..535235b 100644 --- a/cli/process/run.ts +++ b/cli/process/run.ts @@ -11,7 +11,7 @@ export const run = async (args: { args.log && args.log(`${args.command} ${args.args && args.args.join(' ')}`) const p = spawn(args.command, args.args, { env: process.env, - cwd: process.cwd() + cwd: process.cwd(), }) const result = [] as string[] const errors = [] as string[] @@ -23,7 +23,7 @@ export const run = async (args: { return reject( new Error( `${args.command} ${args.args && - args.args.join(' ')} failed: ${errors.join(os.EOL)}`, + args.args.join(' ')} failed: ${errors.join(os.EOL)}`, ), ) } diff --git a/package.json b/package.json index 4d33ebd..1f3626a 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,11 @@ "*.{md,json,yaml,yml}": [ "prettier --write", "git add" + ], + "*.{ts,tsx}": [ + "prettier --write", + "eslint --ext .js,.ts", + "git add" ] }, "engines": {