UNPKG

@iotize/tap

Version:

IoTize Device client for Javascript

686 lines 60.3 kB
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
// tslint:disable: no-implicit-dependencies
import { hexStringToBuffer } from '@iotize/common/byte-converter';
import { isCodeError } from '@iotize/common/error';
import { StepOperations } from '@iotize/common/task-manager';
import { deepCopy, sleep } from '@iotize/common/utility';
import '@iotize/tap';
import { AppPathType, SpecialFeature, TapError, } from '@iotize/tap';
import { DEFAULT_SCRAM_SALT_GENERATOR, hashLoginPassword, ScramAuth, } from '@iotize/tap/auth';
import { ResultCode, TapRequestFrame } from '@iotize/tap/client/api';
import { NumberConverter, TapStreamWriter } from '@iotize/tap/client/impl';
import { getConverterFromVariableType, variableDataTypeToByteSize, } from '@iotize/tap/data';
import '@iotize/tap/service/all';
import { converters, FirmwareState, VariableType, } from '@iotize/tap/service/all';
import { VariableMetaConfigConverter } from '@iotize/tap/service/impl/variable';
import { ADMIN_USER, DEFAULT_HASH_ITERATION_COUNT, SPECIAL_USERS, SUPERVISOR_USER, } from './default-config';
import { TapConfiguratorError } from './errors';
import { enumKeyToEnumValue, getProfileIdFromConfig, isSpecialProfileId, } from './util';
import { validateTapConfiguratorConfig } from './validate-tap-config';
import { WRITE_CONFIGURATOR_CONFIG, } from './write-configurator-config';
const variableMetaConverter = new VariableMetaConfigConverter();
const IGNORE_KEYS = ['version', 'tap.security'];
const USER_CREATE_KEY = 'data.profiles[]';
const CREATE_VARIABLE_CONFIG_KEY = 'data.variables[]';
function isHexString(input) {
    if (typeof input !== 'string') {
        return false;
    }
    return !!input.match(/^(0x)?([a-fA-F0-9])*$/);
}
export function tapConfigToServiceCalls(config, options) {
    var _a;
    function addCalls(calls, newCalls) {
        if (Array.isArray(newCalls)) {
            calls.push(...newCalls);
        }
        else {
            calls.push(newCalls);
        }
    }
    function createWriteConfigCall(key, callContext) {
        if (!(key in WRITE_CONFIGURATOR_CONFIG)) {
            throw new Error(`Invalid API configuration. Configuration key "${key}" does not exist`);
        }
        const callFactory = WRITE_CONFIGURATOR_CONFIG[key];
        return callFactory(callContext);
    }
    function baseConfigObjectToCalls(entry, configKey, pathParameter) {
        const calls = [];
        if (entry === undefined) {
            return calls;
        }
        else if (Array.isArray(entry)) {
            const newConfigKey = configKey + '[]';
            for (const itemValue of entry) {
                if (itemValue.id || itemValue.id === 0) {
                    pathParameter = itemValue.id;
                }
                if (pathParameter === undefined) {
                    throw new Error(`Item must have an id for key "${newConfigKey}`);
                    // TODO we need to know parent profile ?
                }
                // If there is a create instance function
                if (newConfigKey in WRITE_CONFIGURATOR_CONFIG) {
                    if (newConfigKey === USER_CREATE_KEY &&
                        isSpecialProfileId(pathParameter)) {
                        // If it's a special user profile, we dont need the create call
                    }
                    else {
                        // throw new Error(`Missing create method for config key "${newConfigKey}"`);
                        let createBody;
                        if (newConfigKey === CREATE_VARIABLE_CONFIG_KEY) {
                            if (itemValue.metaDataLength) {
                                createBody = itemValue.metaDataLength;
                            }
                            else if (itemValue.rawMeta) {
                                createBody = itemValue.rawMeta.length;
                            }
                        }
                        const createCallParam = {
                            firmwareVersion: options.firmwareVersion,
                            service: options.service,
                            value: createBody,
                            param: pathParameter,
                        };
                        if (createBody === undefined) {
                            delete createCallParam.value;
                        }
                        try {
                            const newCalls = WRITE_CONFIGURATOR_CONFIG[newConfigKey](createCallParam);
                            addCalls(calls, newCalls);
                        }
                        catch (err) {
                            const error = err;
                            throw TapConfiguratorError.internalError(`Cannot generate configuration requests from configuration key ${newConfigKey}. Cause: ${error.message}`, error);
                        }
                    }
                }
                calls.push(...baseConfigObjectToCalls(itemValue, newConfigKey, pathParameter));
            }
        }
        else {
            if (`${configKey}.$` in WRITE_CONFIGURATOR_CONFIG) {
                try {
                    addCalls(calls, createWriteConfigCall(`${configKey}.$`, {
                        firmwareVersion: options.firmwareVersion,
                        service: options.service,
                        value: entry,
                        param: pathParameter,
                        config,
                    }));
                }
                catch (err) {
                    const error = err;
                    throw TapConfiguratorError.internalError(`Cannot generate create resource request for configuration key ${configKey} for identifier "${pathParameter}". Cause: ${error.message}`, error);
                }
            }
            else {
                for (const subKey in entry) {
                    const newConfigKey = configKey ? `${configKey}.${subKey}` : subKey;
                    if (newConfigKey === `${CREATE_VARIABLE_CONFIG_KEY}.metaDataLength`) {
                        continue;
                    }
                    const value = entry[subKey];
                    // We skip version key as it's a special key
                    if (value === undefined) {
                        continue;
                    }
                    else if (IGNORE_KEYS.indexOf(newConfigKey) >= 0) {
                        continue;
                    }
                    else if (pathParameter !== undefined &&
                        subKey === 'id' &&
                        value === pathParameter) {
                        // Skip id field
                        continue;
                    }
                    else if (newConfigKey in WRITE_CONFIGURATOR_CONFIG) {
                        const callContext = {
                            firmwareVersion: options.firmwareVersion,
                            service: options.service,
                            value: value,
                            param: pathParameter,
                        };
                        addCalls(calls, createWriteConfigCall(newConfigKey, callContext));
                    }
                    else if (typeof value === 'object') {
                        calls.push(...baseConfigObjectToCalls(value, newConfigKey, pathParameter));
                    }
                    else {
                        throw new Error(`Invalid config key "${newConfigKey}" with value ${value}. ${pathParameter ? `Current path parameter: ${pathParameter}` : ''}`);
                    }
                }
            }
        }
        return calls;
    }
    const flattenConfig = toFlatTapConfig(config, options);
    const { service } = options;
    const calls = [
        service.interface.putConfigVersionCall('255.255.65535'),
    ];
    const security = ((_a = config.tap) === null || _a === void 0 ? void 0 : _a.security) || {};
    if (security.scramActivated) {
        // Usually security options are encoded on 2 bytes
        // However to enable scram during configuration, we must give 0x10 value
        // Don't know why
        calls.push({
            method: TapRequestFrame.MethodType.PUT,
            path: '/1024//6',
            body: Uint8Array.from([0x10]),
        });
    }
    calls.push(...baseConfigObjectToCalls(flattenConfig, '', undefined));
    if (security.scramActivated) {
        security.hashPassword = true;
    }
    calls.push(service.interface.putSecurityOptionsCall(security));
    calls.push(service.interface.putConfigVersionCall(config.version || '1.0.0'));
    return calls;
}
function arrayPadEnd(data, length, padValue = 0) {
    if (data.length >= length) {
        return data;
    }
    else {
        return TapStreamWriter.create(length)
            .writeBytes(data)
            .writeBytes(new Uint8Array(length - data.length).fill(padValue, 0, length - data.length)).toBytes;
    }
}
function arrayPadStart(data, length, padValue = 0) {
    if (data.length >= length) {
        return data;
    }
    else {
        return TapStreamWriter.create(length)
            .writeBytes(new Uint8Array(length - data.length).fill(padValue, 0, length - data.length))
            .writeBytes(data).toBytes;
    }
}
function invalidVariableValueError(bundle, variable, msg) {
    return TapConfiguratorError.invalidConfiguration(`data.bundle[${bundle.id}].variable[${variable.id}].value ${msg}`);
}
export function encodeInitialVariableValue(variable, bundle) {
    const variableLength = variable.length || 1;
    const variableDataType = variable.dataType === undefined
        ? VariableType.Data.UINT8
        : VariableType.Data[variable.dataType];
    const itemByteSize = variableDataTypeToByteSize(variableDataType);
    function _encodeItem(value, index = 0) {
        let result;
        if (value instanceof Uint8Array) {
            result = value;
        }
        else if (isHexString(value)) {
            result = hexStringToBuffer(value);
        }
        else if (typeof value === 'number') {
            const converter = getConverterFromVariableType(variableDataType, 1);
            if (!converter) {
                throw invalidVariableValueError(bundle, variable, `cannot be converted to a buffer. No registered converter exist for this variable type.`);
            }
            result = converter.encode(value);
        }
        else {
            throw invalidVariableValueError(bundle, variable, `has type ${typeof value} which is not supported by the configurator`);
        }
        if (result.length > itemByteSize) {
            throw invalidVariableValueError(bundle, variable, `at index ${index} is on ${result.length} bytes but expecting a maximum length of ${itemByteSize} byte(s)`);
        }
        else {
            result = arrayPadStart(result, itemByteSize);
        }
        return result;
    }
    let encodedValue;
    if (typeof variable.value === 'string' &&
        variableDataType === VariableType.Data.ASCII) {
        encodedValue = converters.ascii.encode(variable.value);
    }
    else if (Array.isArray(variable.value)) {
        const buffers = variable.value.map((v, index) => {
            return _encodeItem(v, index);
        });
        encodedValue = TapStreamWriter.mergeArrays(...buffers);
    }
    else {
        encodedValue = _encodeItem(variable.value);
    }
    const byteLength = variableLength * itemByteSize;
    if (encodedValue.length > byteLength) {
        throw invalidVariableValueError(bundle, variable, `is encoded on ${encodedValue.length} byte(s) but you have declared a maximum length of ${byteLength} byte(s)`);
    }
    return arrayPadEnd(encodedValue, byteLength);
}
export function toVariableFlatConfig(variable, bundle) {
    const variableCopy = deepCopy(variable);
    if (variableCopy.length === undefined) {
        variableCopy.length = 1;
    }
    const variableFlatConfig = variableCopy;
    delete variableCopy.dataType;
    delete variableCopy.domain;
    variableFlatConfig.bundleId = bundle.id;
    if (variableFlatConfig.rawMeta !== undefined) {
        variableFlatConfig.rawMeta =
            typeof variableFlatConfig.rawMeta === 'string'
                ? hexStringToBuffer(variableFlatConfig.rawMeta)
                : variableFlatConfig.rawMeta;
    }
    else if (variableCopy.meta) {
        variableFlatConfig.rawMeta = variableMetaConverter.encode(variableCopy.meta);
        delete variableCopy.meta;
    }
    variableFlatConfig.type = {
        domain: variable.domain !== undefined ? variable.domain : 'TARGET',
        data: variable.dataType !== undefined ? variable.dataType : 'UINT8',
    };
    if (variable.value !== undefined && variable.value !== null) {
        variableFlatConfig.value = encodeInitialVariableValue(variable, bundle);
    }
    return variableFlatConfig;
}
export function toFlatTapConfig(config, options) {
    var _a, _b, _c, _d, _e, _f, _g;
    const configCopy = deepCopy(config);
    const flatProfiles = [];
    if (configCopy.target) {
        delete configCopy.target.type;
    }
    if (configCopy.data) {
        // Flaten profiles
        if (configCopy.data.profiles) {
            for (const profile of (_a = configCopy.data) === null || _a === void 0 ? void 0 : _a.profiles) {
                const flatenProfile = profile;
                if (flatenProfile.id === undefined) {
                    flatenProfile.id = getProfileIdFromConfig(flatenProfile);
                }
                if (isSpecialProfileId(flatenProfile.id)) {
                    delete flatenProfile.username;
                }
                const subProfiles = flatenProfile.users || [];
                delete flatenProfile.users;
                flatProfiles.push(flatenProfile);
                for (const subProfile of subProfiles) {
                    subProfile.alias = flatenProfile.id;
                    flatProfiles.push(subProfile);
                    if (isSpecialProfileId(subProfile.id)) {
                        delete subProfile.username;
                    }
                }
            }
        }
        // Flaten acls and special features
        const flatSpecialFeatures = [];
        const flatVariables = [];
        if (configCopy.data.bundles) {
            for (const bundle of configCopy.data.bundles) {
                const acls = bundle.acls || {};
                delete bundle.acls;
                const flatAcls = [];
                for (const username in acls) {
                    const acl = acls[username];
                    let profile = flatProfiles.find((p) => p.username === username);
                    if (!profile) {
                        profile = SPECIAL_USERS.find((p) => p.username === username);
                        if (!profile) {
                            throw new Error(`Cannot find profile with username "${username}"`); // TODO proper error
                        }
                    }
                    flatAcls.push({
                        groupId: profile.id,
                        read: acl.read,
                        write: acl.write,
                    });
                }
                if (flatAcls.length > 0) {
                    bundle.acl = flatAcls;
                }
                const variables = bundle.variables || [];
                delete bundle.variables;
                for (const variable of variables) {
                    flatVariables.push(toVariableFlatConfig(variable, bundle));
                }
                const features = bundle.features || [];
                delete bundle.features;
                for (const featureKey of features) {
                    const featureId = enumKeyToEnumValue(featureKey, SpecialFeature);
                    if (flatSpecialFeatures.find((f) => f.id === featureId)) {
                        throw new Error(`Special feature "${featureId}" has already be given to another bundle`);
                    }
                    flatSpecialFeatures.push({
                        id: featureId,
                        bundleId: bundle.id,
                    });
                }
            }
        }
        if (flatSpecialFeatures.length > 0) {
            configCopy.data.features = flatSpecialFeatures;
        }
        if (flatVariables.length > 0) {
            configCopy.data.variables = flatVariables;
        }
    }
    if ((_c = (_b = config.tap) === null || _b === void 0 ? void 0 : _b.security) === null || _c === void 0 ? void 0 : _c.scramActivated) {
        if (!configCopy.tap) {
            configCopy.tap = {};
        }
        if (!configCopy.tap.scram) {
            configCopy.tap.scram = {};
        }
        if (!configCopy.tap.scram.hashIteration) {
            configCopy.tap.scram.hashIteration = DEFAULT_HASH_ITERATION_COUNT;
        }
    }
    const hashIteration = (_e = (_d = configCopy.tap) === null || _d === void 0 ? void 0 : _d.scram) === null || _e === void 0 ? void 0 : _e.hashIteration;
    for (const specialProfile of [ADMIN_USER, SUPERVISOR_USER]) {
        if (!flatProfiles.find((p) => p.id === specialProfile.id)) {
            flatProfiles.push({
                id: specialProfile.id,
                password: specialProfile.password || specialProfile.username,
                lifeTime: specialProfile.lifeTime || 30,
            });
        }
    }
    for (const profile of flatProfiles) {
        prepareUserPassword(profile, ((_f = configCopy === null || configCopy === void 0 ? void 0 : configCopy.tap) === null || _f === void 0 ? void 0 : _f.security) || {}, (input) => {
            if (!hashIteration) {
                throw TapConfiguratorError.internalError(`Hash iteration value must be set`);
            }
            const salt = (options === null || options === void 0 ? void 0 : options.saltGenerator)
                ? options.saltGenerator()
                : DEFAULT_SCRAM_SALT_GENERATOR();
            return ScramAuth.createScramPasswordKey(input, {
                salt,
                iterationNumber: hashIteration,
            });
        });
    }
    if (!configCopy.data) {
        configCopy.data = {};
    }
    configCopy.data.profiles = flatProfiles;
    if ((_g = configCopy.application) === null || _g === void 0 ? void 0 : _g.uri) {
        if (typeof configCopy.application.uri === 'object') {
            const appUri = configCopy.application.uri;
            configCopy.application.uri = `${AppPathType[appUri.type]}${appUri.value}`;
        }
    }
    // We must set codeSize as Tap will change where JVM code is stored according to the code size
    if (configCopy.jvm && configCopy.jvm.code) {
        const codeSize = configCopy.jvm.codeSize === undefined
            ? computeJvmCodeByteSize(configCopy.jvm.code)
            : configCopy.jvm.codeSize;
        delete configCopy.jvm.codeSize;
        configCopy.jvm = Object.assign({ 
            // to make sure that code size request is done first
            codeSize }, configCopy.jvm);
    }
    return configCopy;
}
function computeJvmCodeByteSize(input) {
    if (!input) {
        return 0;
    }
    if (typeof input === 'string') {
        let length = input.length / 2;
        if (input.startsWith('0x')) {
            length -= 1;
        }
        return length;
    }
    else {
        return input.length;
    }
}
function prepareUserPassword(profile, securityConfig, scramPasswordGenerator) {
    if (profile.password) {
        if (profile.key) {
            throw TapConfiguratorError.invalidConfiguration(`You cannot specify both password and passwordKey for profile configuration. Specify only one of those two options.`);
        }
        if (securityConfig.scramActivated) {
            const passwordBytes = scramPasswordGenerator(profile.password);
            // debug(
            //     `Writing SCRAM password for user id ${userId} with hash: ${bufferToHexString(passwordBytes)}`
            // );
            delete profile.password;
            profile.key = passwordBytes;
        }
        else if (securityConfig.hashPassword) {
            const passwordBytes = hashLoginPassword(profile.password);
            // debug(
            //     `Writing password for user id ${userId} with hash: ${bufferToHexString(
            //         passwordBytes
            //     )}`
            // );
            delete profile.password;
            profile.key = passwordBytes;
        }
        else {
            // debug(
            //     `Writing password for user id ${userId} without hash: ${password}`
            // );
            // OK nothing to do
        }
    }
    // console.log('profile.passwordKey', typeof profile.passwordKey, profile.passwordKey?.constructor?.name);
}
function stepEvent(observer, step, context, extraData) {
    observer.next(Object.assign({ step, progress: {
            loaded: context.index + 1,
            total: context.total,
        } }, (extraData || {})));
}
/**
 * Configure tap from a configuration file schema
 *
 */
export class TapConfiguratorWriter {
    constructor(options = {
        delayMs: 400,
        throwOnNotImplementedConfigKey: false,
    }, host) {
        this.options = options;
        this.host = host;
    }
    createConfiguratorForTap(tap, config, options) {
        return __awaiter(this, void 0, void 0, function* () {
            const firmwareVersion = (yield tap.service.device.getFirmwareVersion()).body();
            return this.configure(tap, firmwareVersion, config, options);
        });
    }
    configure(tap, firmwareVersion, config, options) {
        var _a, _b;
        const configureContext = {
            tap,
            options: config.meta || {},
            tapConfig: config.config,
        };
        const operations = [];
        config = this._adaptConfigurationToCurrentVersion(config);
        if (!(options === null || options === void 0 ? void 0 : options.skipSchemaValidation)) {
            operations.push((observer, context) => __awaiter(this, void 0, void 0, function* () {
                stepEvent(observer, TapConfiguratorWriter.Step.validatesConfig, context);
                validateTapConfiguratorConfig(config);
            }));
        }
        if (!configureContext.options.skipFactoryReset) {
            operations.push((observer, context) => __awaiter(this, void 0, void 0, function* () {
                stepEvent(observer, TapConfiguratorWriter.Step.factoryReset, context);
                (yield tap.service.device.factoryReset()).successful();
            }));
        }
        const useScram = !!((_b = (_a = configureContext.tapConfig.tap) === null || _a === void 0 ? void 0 : _a.security) === null || _b === void 0 ? void 0 : _b.scramActivated);
        if (useScram) {
            operations.push((observer, context) => __awaiter(this, void 0, void 0, function* () {
                stepEvent(observer, TapConfiguratorWriter.Step.enableSecureCom, context);
                if (useScram) {
                    yield tap.encryption.start();
                }
            }));
        }
        const calls = tapConfigToServiceCalls(configureContext.tapConfig, {
            firmwareVersion,
            service: tap.service,
        });
        // operations.push(async (observer, context) => {
        //     observer.next({
        //         step: TapConfigurator.Step.
        //     } as TapConfigurator.Event);
        //     const firmwareVersion = (await context.tap.service.device.getFirmwareVersion()).body();
        // });
        // operations.push(
        //     async (observer, context) => {
        //         stepEvent(observer, TapConfiguratorWriter.Step.setupConfigurationState, context);
        //         await this.setupConfigState(configureContext.tap);
        //     }
        // );
        // if (useScram) {
        //     operations.push(async (observer, context) => {
        //         // To write user password keys, we need to put scram configuration first
        //         stepEvent(observer, TapConfiguratorWriter.Step.writeSecurityOptions, context);
        //         tap.encryption.pause();
        //         (await tap.service.interface.putSecurityOptions({
        //             scramActivated: true
        //         } as SecurityOptions)).successful();
        //         tap.encryption.resume();
        //     });
        // }
        this.addConfigurCalls(configureContext, calls, operations);
        // operations.push(
        //     async (observer, context) => {
        //         stepEvent(observer, TapConfiguratorWriter.Step.applyConfig, context);
        //         await this.applyConfig(configureContext.tap, configureContext.tapConfig.version || '1.0.0');
        //     }
        // );
        operations.push((observer, context) => __awaiter(this, void 0, void 0, function* () {
            stepEvent(observer, TapConfiguratorWriter.Step.logout, context);
            yield configureContext.tap.auth.logout();
            tap.auth.clearCache();
        }));
        return StepOperations.sequential(operations);
    }
    setupConfigState(tap) {
        return __awaiter(this, void 0, void 0, function* () {
            const state = (yield tap.service.firmware.getState()).body();
            if (state !== FirmwareState.NORMAL && state !== FirmwareState.LEGACY) {
                throw TapConfiguratorError.unexpectedFirmwareState(state);
            }
            (yield tap.service.interface.putConfigVersion('255.255.65535')).successful();
        });
    }
    // TODO move from here
    isConfigured(tap) {
        return __awaiter(this, void 0, void 0, function* () {
            const configVersionCalled = yield tap.service.interface.getConfigVersion();
            configVersionCalled.successful();
            const intValue = configVersionCalled.body(NumberConverter.uint32());
            return intValue !== 0;
        });
    }
    /***
     *
     */
    applyConfig(tap, newVersion = '1.0.0') {
        return __awaiter(this, void 0, void 0, function* () {
            yield this.sleep(this.options.delayMs);
            (yield tap.service.interface.putConfigVersion(newVersion)).successful();
            yield this.sleep(this.options.delayMs);
            (yield tap.service.interface.reloadConfig()).successful();
            yield this.sleep(this.options.delayMs);
        });
    }
    addConfigurCalls(configureContext, calls, operations) {
        calls.forEach((callOrError, index) => {
            operations.push((observer, context) => __awaiter(this, void 0, void 0, function* () {
                const stepProgress = {
                    total: calls.length,
                    loaded: index + 1,
                };
                if (callOrError instanceof Error) {
                    stepEvent(observer, TapConfiguratorWriter.Step.executeCall, context, {
                        error: callOrError,
                        stepProgress,
                    });
                }
                else {
                    stepEvent(observer, TapConfiguratorWriter.Step.executeCall, context, {
                        stepProgress,
                        call: callOrError,
                    });
                    try {
                        (yield configureContext.tap.lwm2m.execute(callOrError)).successful();
                    }
                    catch (err) {
                        if (!this.options.throwOnNotImplementedConfigKey &&
                            isCodeError(TapError.Code.ResponseStatusError, err)) {
                            const responseStatusError = err;
                            if (responseStatusError.response.status ===
                                ResultCode.NOT_IMPLEMENTED) {
                                stepEvent(observer, TapConfiguratorWriter.Step.executeCall, context, {
                                    error: err,
                                    stepProgress,
                                });
                                return;
                            }
                        }
                        throw err;
                    }
                }
            }));
        });
    }
    sleep(delayMs) {
        return sleep(delayMs);
    }
    _adaptConfigurationToCurrentVersion(config) {
        var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
        if (config.config.wireless) {
            let blePairing = undefined;
            let nfcPairingMode;
            if (((_c = (_b = (_a = config.config.wireless) === null || _a === void 0 ? void 0 : _a.protocols) === null || _b === void 0 ? void 0 : _b.nfc) === null || _c === void 0 ? void 0 : _c.pairingMode) !== undefined) {
                nfcPairingMode = config.config.wireless.protocols.nfc.pairingMode;
                delete config.config.wireless.protocols.nfc.pairingMode;
            }
            if (((_f = (_e = (_d = config.config.wireless) === null || _d === void 0 ? void 0 : _d.protocols) === null || _e === void 0 ? void 0 : _e.ble) === null || _f === void 0 ? void 0 : _f.pairing) !== undefined) {
                blePairing = (_j = (_h = (_g = config.config.wireless) === null || _g === void 0 ? void 0 : _g.protocols) === null || _h === void 0 ? void 0 : _h.ble) === null || _j === void 0 ? void 0 : _j.pairing;
                (_k = config.config.wireless.protocols.ble) === null || _k === void 0 ? true : delete _k.pairing;
            }
            if (!config.config.wireless.options) {
                config.config.wireless.options = {};
            }
            if (blePairing !== undefined || nfcPairingMode !== undefined) {
                config.config.wireless.options.pairing = {
                    nfcPairingMode,
                    blePairing,
                };
            }
        }
        return config;
    }
}
(function (TapConfiguratorWriter) {
    let Step;
    (function (Step) {
        Step["validatesConfig"] = "TapConfiguratorStepValidatesConfig";
        Step["enableSecureCom"] = "TapConfiguratorStepenableSecureCommunication";
        Step["factoryReset"] = "TapConfiguratorStepFactoryReset";
        Step["setupConfigurationState"] = "TapConfiguratorStepSetupConfigurationState";
        Step["executeCall"] = "TapConfiguratorStepExecuteCall";
        Step["logout"] = "TapConfiguratorSteplogout";
        Step["applyConfig"] = "TapConfiguratorStepApplyConfig";
        Step["writeSecurityOptions"] = "TapConfiguratorStepWriteSecurityOptions";
    })(Step = TapConfiguratorWriter.Step || (TapConfiguratorWriter.Step = {}));
})(TapConfiguratorWriter || (TapConfiguratorWriter = {}));
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFwLWNvbmZpZ3VyYXRvci13cml0ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9jb25maWd1cmF0b3Ivc3JjL2xpYi90YXAtY29uZmlndXJhdG9yLXdyaXRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7QUFBQSwyQ0FBMkM7QUFDM0MsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFDbEUsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ25ELE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUM3RCxPQUFPLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ3pELE9BQU8sYUFBYSxDQUFDO0FBQ3JCLE9BQU8sRUFDTCxXQUFXLEVBR1gsY0FBYyxFQUVkLFFBQVEsR0FFVCxNQUFNLGFBQWEsQ0FBQztBQUNyQixPQUFPLEVBQ0wsNEJBQTRCLEVBQzVCLGlCQUFpQixFQUNqQixTQUFTLEdBQ1YsTUFBTSxrQkFBa0IsQ0FBQztBQUMxQixPQUFPLEVBQUUsVUFBVSxFQUFFLGVBQWUsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ3JFLE9BQU8sRUFBRSxlQUFlLEVBQUUsZUFBZSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFXM0UsT0FBTyxFQUNMLDRCQUE0QixFQUM1QiwwQkFBMEIsR0FDM0IsTUFBTSxrQkFBa0IsQ0FBQztBQUMxQixPQUFPLHlCQUF5QixDQUFDO0FBQ2pDLE9BQU8sRUFDTCxVQUFVLEVBQ1YsYUFBYSxFQUdiLFlBQVksR0FDYixNQUFNLHlCQUF5QixDQUFDO0FBQ2pDLE9BQU8sRUFBRSwyQkFBMkIsRUFBRSxNQUFNLG1DQUFtQyxDQUFDO0FBRWhGLE9BQU8sRUFDTCxVQUFVLEVBQ1YsNEJBQTRCLEVBQzVCLGFBQWEsRUFDYixlQUFlLEdBQ2hCLE1BQU0sa0JBQWtCLENBQUM7QUFF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