constructor()

in provisioning/device/src/tpm_registration.ts [24:228]


  constructor(provisioningHost: string, idScope: string, transport: TpmProvisioningTransport, securityClient: TpmSecurityClient) {
    super();
    this._transport = transport;
    this._securityClient = securityClient;
    this._provisioningHost = provisioningHost;
    this._idScope = idScope;
    this._pollingStateMachine = new PollingStateMachine(transport);

    this._fsm = new machina.Fsm({
      namespace: 'tpm-registration',
      initialState: 'notStarted',
      states: {
        notStarted: {
          _onEnter: (err, callback) => {
            if (callback) {
              callback(err);
            } else if (err) {
              this.emit('error', err);
            }
          },
          register: (request, callback) => this._fsm.transition('authenticating', request, callback),
          cancel: (callback) => callback()
        },
        authenticating: {
          _onEnter: (registrationInfo, registerCallback) => {
            /*Codes_SRS_NODE_DPS_TPM_REGISTRATION_16_001: [The `register` method shall get the endorsement key by calling `getEndorsementKey` on the `TpmSecurityClient` object passed to the constructor.]*/
            this._securityClient.getEndorsementKey((err, ek) => {
              if (err) {
                debugErrors('failed to get endorsement key from TPM security client: ' + err);
                /*Codes_SRS_NODE_DPS_TPM_REGISTRATION_16_010: [If any of the calls the the `TpmSecurityClient` or the `TpmProvisioningTransport` fails, the `register` method shall call its callback with the error resulting from the failure.]*/
                this._fsm.transition('notStarted', err, registerCallback);
              } else {
                registrationInfo.endorsementKey = ek;
                this._securityClient.getRegistrationId((err, registrationId) => {
                  if (err) {
                    debugErrors('failed to get registrationId from TPM security client: ' + err.toString());
                    this._fsm.transition('notStarted', err, registerCallback);
                  } else {
                    registrationInfo.request.registrationId = registrationId;
                    this._fsm.handle('getStorageRootKey', registrationInfo, registerCallback);
                  }
                });
              }
            });
          },
          getStorageRootKey: (registrationInfo, registerCallback) => {
            /*Codes_SRS_NODE_DPS_TPM_REGISTRATION_16_002: [The `register` method shall get the storage root key by calling `getStorageRootKey` on the `TpmSecurityClient` object passed to the constructor.]*/
            this._securityClient.getStorageRootKey((err, srk) => {
              if (err) {
                debugErrors('failed to get storage root key from TPM security client: ' + err);
                /*Codes_SRS_NODE_DPS_TPM_REGISTRATION_16_010: [If any of the calls the the `TpmSecurityClient` or the `TpmProvisioningTransport` fails, the `register` method shall call its callback with the error resulting from the failure.]*/
                this._fsm.transition('notStarted', err, registerCallback);
              } else {
                registrationInfo.storageRootKey = srk;
                this._fsm.handle('getTpmChallenge', registrationInfo, registerCallback);
              }
            });
          },
          getTpmChallenge: (registrationInfo, registerCallback) => {

            this._transport.setTpmInformation(registrationInfo.endorsementKey, registrationInfo.storageRootKey);
            /*Codes_SRS_NODE_DPS_TPM_REGISTRATION_16_003: [The `register` method shall initiate the authentication flow with the device provisioning service by calling the `getAuthenticationChallenge` method of the `TpmProvisioningTransport` object passed to the constructor with an object with the following properties:
            - `registrationId`: a unique identifier computed from the endorsement key
            - `provisioningHost`: the host address of the dps instance
            - `idScope`: the `idscope` value obtained from the azure portal for this instance.
            - a callback that will handle either an error or a `Buffer` object containing a session key to be used later in the authentication process.]*/
            this._transport.getAuthenticationChallenge(registrationInfo.request, (err, tpmChallenge) => {
              if (err) {
                debugErrors('failed to get sessionKey from provisioning service: ' + err);
                /*Codes_SRS_NODE_DPS_TPM_REGISTRATION_16_010: [If any of the calls the the `TpmSecurityClient` or the `TpmProvisioningTransport` fails, the `register` method shall call its callback with the error resulting from the failure.]*/
                this._fsm.transition('notStarted', err, registerCallback);
              } else {
                this._fsm.handle('activateSessionKey', tpmChallenge, registrationInfo, registerCallback);
              }
            });
          },
          activateSessionKey: (tpmChallenge, registrationInfo, registerCallback) => {
            /*Codes_SRS_NODE_DPS_TPM_REGISTRATION_16_004: [The `register` method shall store the session key in the TPM by calling the `activateIdentityKey` method of the `TpmSecurityClient` object passed to the constructor with the following arguments:
            - `sessionKey`: the session key returned by the previous call to `TpmProvisioningTransport.getAuthenticationChallenge`
            - a callback that will handle an optional error if the operation fails.]*/
            this._securityClient.activateIdentityKey(tpmChallenge, (err) => {
              if (err) {
                debugErrors('failed to activate the sessionKey: ' + err);
                /*Codes_SRS_NODE_DPS_TPM_REGISTRATION_16_010: [If any of the calls the the `TpmSecurityClient` or the `TpmProvisioningTransport` fails, the `register` method shall call its callback with the error resulting from the failure.]*/
                this._fsm.transition('notStarted', err, registerCallback);
              } else {
                this._fsm.handle('createRegistrationSas', registrationInfo, registerCallback);
              }
            });
          },
          createRegistrationSas: (registrationInfo, registerCallback) => {
            this._createRegistrationSas(registrationInfo, (err, sasToken) => {
              if (err) {
                debugErrors('failed to get sign the initial authentication payload with the sessionKey: ' + err);
                /*Codes_SRS_NODE_DPS_TPM_REGISTRATION_16_010: [If any of the calls the the `TpmSecurityClient` or the `TpmProvisioningTransport` fails, the `register` method shall call its callback with the error resulting from the failure.]*/
                this._fsm.transition('notStarted', err, registerCallback);
              } else {
                this._fsm.transition('respondToAuthenticationChallenge', registrationInfo, sasToken, registerCallback);
              }
            });
          },
          cancel: (callback) => {
            /*Codes_SRS_NODE_DPS_TPM_REGISTRATION_16_011: [The `cancel` method shall interrupt the ongoing registration process.]*/
            this._transport.cancel((err) => {
              if (err) {
                debugErrors('failed to stop provisioning transport: ' + err);
              }
              this._fsm.transition('notStarted', err, callback);
            });
          },
          '*': () => this._fsm.deferUntilTransition()
        },
        respondToAuthenticationChallenge: {
          _onEnter: (registrationInfo, sasToken, registerCallback) => {
            this._transport.respondToAuthenticationChallenge(registrationInfo.request, sasToken, (err) => {
              if (err) {
                // TODO: verify that the transport is disconnected here.  Maybe add SRS in transport
                this._fsm.transition('notStarted', err, registerCallback);
              } else {
                this._fsm.transition('registrationInProgress', registrationInfo, registerCallback);
              }
            });
          },
          cancel: (callback) => {
            /*Codes_SRS_NODE_DPS_TPM_REGISTRATION_16_011: [The `cancel` method shall interrupt the ongoing registration process.]*/
            this._transport.cancel((err) => {
              if (err) {
                debugErrors('failed to stop provisioning transport: ' + err);
              }
              this._fsm.transition('notStarted', err, callback);
            });
          },
          '*': () => this._fsm.deferUntilTransition()
        },
        registrationInProgress: {
          _onEnter: (registrationInfo, registerCallback) => {
            /*Codes_SRS_NODE_DPS_TPM_REGISTRATION_16_007: [The `register` method shall start the actual registration process by calling the `register` method on the `TpmProvisioningTransport` object passed to the constructor with the following parameters:
            - `sasToken`: the SAS token generated according to `SRS_NODE_DPS_TPM_REGISTRATION_16_006`
            - `registrationInfo`: an object with the following properties `endorsementKey`, `storageRootKey`, `registrationId` and their previously set values.
            - a callback that will handle an optional error and a `result` object containing the IoT hub name, device id and symmetric key for this device.]*/
            this._pollingStateMachine.register(registrationInfo.request, (err, result) => {
              if (err) {
                debugErrors('failed to register with provisioning transport: ' + err);
                /*Codes_SRS_NODE_DPS_TPM_REGISTRATION_16_010: [If any of the calls the the `TpmSecurityClient` or the `TpmProvisioningTransport` fails, the `register` method shall call its callback with the error resulting from the failure.]*/
                this._fsm.transition('notStarted', err, registerCallback);
              } else {
                this._fsm.transition('storingSecret', result, registerCallback);
              }
            });
          },
          cancel: (callback) => {
            /*Codes_SRS_NODE_DPS_TPM_REGISTRATION_16_011: [The `cancel` method shall interrupt the ongoing registration process.]*/
            this._transport.cancel((err) => {
              if (err) {
                debugErrors('failed to stop provisioning transport: ' + err);
              }
              this._fsm.transition('notStarted', err, callback);
            });
          },
          '*': () => this._fsm.deferUntilTransition()
        },
        storingSecret: {
          _onEnter: (registrationResult, registerCallback) => {
            /*Codes_SRS_NODE_DPS_TPM_REGISTRATION_16_008: [When the callback for the registration process is called, the `register` method shall store the symmetric key within the TPM by calling the `activateIdentityKey` method of the `TpmSecurityClient` object passed to the constructor with the following arguments:
            - `symmetricKey`: the symmetric key returned by the previous call to `TpmProvisioningTransport.getAuthenticationChallenge`
            - a callback that will handle an optional error if the operation fails.
            ]*/
            this._securityClient.activateIdentityKey(Buffer.from(registrationResult.registrationState.tpm.authenticationKey,'base64'), (err) => {
              if (err) {
                debugErrors('failed to stop provisioning transport: ' + err);
                /*Codes_SRS_NODE_DPS_TPM_REGISTRATION_16_010: [If any of the calls the the `TpmSecurityClient` or the `TpmProvisioningTransport` fails, the `register` method shall call its callback with the error resulting from the failure.]*/
                this._fsm.transition('notStarted', err, registerCallback);
              } else {
                this._fsm.transition('completed', registrationResult, registerCallback);
              }
            });
          },
          cancel: (callback) => {
            /*Codes_SRS_NODE_DPS_TPM_REGISTRATION_16_011: [The `cancel` method shall interrupt the ongoing registration process.]*/
              this._fsm.transition('notStarted', null, callback);
          },
           '*': () => this._fsm.deferUntilTransition()
        },
        completed: {
          _onEnter: (registrationResult, registerCallback) => {
            this._transport.disconnect((err) => {
              if (err) {
                debugErrors('disconnect err.  ignoring. ' + err);
              }
              /*Codes_SRS_NODE_DPS_TPM_REGISTRATION_16_009: [Once the symmetric key has been stored, the `register` method shall call its own callback with a `null` error object and a `TpmRegistrationResult` object containing the information that the `TpmProvisioningTransport` returned once the registration was successful.]*/
              registerCallback(null, registrationResult);
            });
          },
          cancel: (callback) => {
            // TODO: is this weird? also what type of error?
            callback(new Error('cannot cancel - registration was successfully completed'));
          }
        }
      }
    });

    this._fsm.on('transition', (data) => debug('TPM State Machine: ' + data.fromState + ' -> ' + data.toState + ' (' + data.action + ')'));
    this._fsm.on('handling', (data) => debug('TPM State Machine: handling ' + data.inputType));

  }