diff --git a/index.html b/index.html index 30019e4..bf4c1e1 100644 --- a/index.html +++ b/index.html @@ -104,6 +104,12 @@ + + @@ -388,6 +394,31 @@ 0xd2, ]); }, + async exportPrivateKey() { + try { + const response = await this.connection.exportPrivateKey(); + console.log(response); + console.log(this.bytesToHex(response.privateKey)); + } catch(e) { + alert(`Failed to export private key: ${e}`); + } + }, + async importPrivateKey() { + + const privateKeyHex = prompt("Enter private key encoded in hex"); + if(!privateKeyHex){ + return; + } + + try { + const privateKey = this.hexToBytes(privateKeyHex); + await this.connection.importPrivateKey(privateKey); + alert("Private key imported!") + } catch(e) { + alert(`Failed to export private key: ${e}`); + } + + }, async reboot() { try { await this.connection.reboot(); diff --git a/src/connection/connection.js b/src/connection/connection.js index 86d8d5b..7129cc4 100644 --- a/src/connection/connection.js +++ b/src/connection/connection.js @@ -192,6 +192,19 @@ class Connection extends EventEmitter { await this.sendToRadioFrame(data.toBytes()); } + async sendCommandExportPrivateKey() { + const data = new BufferWriter(); + data.writeByte(Constants.CommandCodes.ExportPrivateKey); + await this.sendToRadioFrame(data.toBytes()); + } + + async sendCommandImportPrivateKey(privateKey) { + const data = new BufferWriter(); + data.writeByte(Constants.CommandCodes.ImportPrivateKey); + data.writeBytes(privateKey); + await this.sendToRadioFrame(data.toBytes()); + } + onFrameReceived(frame) { // emit received frame @@ -228,6 +241,10 @@ class Connection extends EventEmitter { this.onBatteryVoltageResponse(bufferReader); } else if(responseCode === Constants.ResponseCodes.DeviceInfo){ this.onDeviceInfoResponse(bufferReader); + } else if(responseCode === Constants.ResponseCodes.PrivateKey){ + this.onPrivateKeyResponse(bufferReader); + } else if(responseCode === Constants.ResponseCodes.Disabled){ + this.onDisabledResponse(bufferReader); } else if(responseCode === Constants.PushCodes.Advert){ this.onAdvertPush(bufferReader); } else if(responseCode === Constants.PushCodes.PathUpdated){ @@ -335,6 +352,18 @@ class Connection extends EventEmitter { }); } + onPrivateKeyResponse(bufferReader) { + this.emit(Constants.ResponseCodes.PrivateKey, { + privateKey: bufferReader.readBytes(64), + }); + } + + onDisabledResponse(bufferReader) { + this.emit(Constants.ResponseCodes.Disabled, { + + }); + } + onSelfInfoResponse(bufferReader) { this.emit(Constants.ResponseCodes.SelfInfo, { type: bufferReader.readByte(), @@ -1067,6 +1096,90 @@ class Connection extends EventEmitter { }); } + exportPrivateKey() { + return new Promise(async (resolve, reject) => { + try { + + // resolve promise when we receive private Key + const onPrivateKey = (response) => { + this.off(Constants.ResponseCodes.PrivateKey, onPrivateKey); + this.off(Constants.ResponseCodes.Err, onErr); + this.off(Constants.ResponseCodes.Disabled, onDisabled); + resolve(response); + } + + // reject promise when we receive err + const onErr = () => { + this.off(Constants.ResponseCodes.PrivateKey, onPrivateKey); + this.off(Constants.ResponseCodes.Err, onErr); + this.off(Constants.ResponseCodes.Disabled, onDisabled); + reject(); + } + + // reject promise when we receive disabled + const onDisabled = () => { + this.off(Constants.ResponseCodes.PrivateKey, onPrivateKey); + this.off(Constants.ResponseCodes.Err, onErr); + this.off(Constants.ResponseCodes.Disabled, onDisabled); + reject("disabled"); + } + + // listen for events + this.once(Constants.ResponseCodes.PrivateKey, onPrivateKey); + this.once(Constants.ResponseCodes.Err, onErr); + this.once(Constants.ResponseCodes.Disabled, onDisabled); + + // export private key + await this.sendCommandExportPrivateKey(); + + } catch(e) { + reject(e); + } + }); + } + + importPrivateKey(privateKey) { + return new Promise(async (resolve, reject) => { + try { + + // resolve promise when we receive ok + const onOk = (response) => { + this.off(Constants.ResponseCodes.Ok, onOk); + this.off(Constants.ResponseCodes.Err, onErr); + this.off(Constants.ResponseCodes.Disabled, onDisabled); + resolve(response); + } + + // reject promise when we receive err + const onErr = () => { + this.off(Constants.ResponseCodes.Ok, onOk); + this.off(Constants.ResponseCodes.Err, onErr); + this.off(Constants.ResponseCodes.Disabled, onDisabled); + reject(); + } + + // reject promise when we receive disabled + const onDisabled = () => { + this.off(Constants.ResponseCodes.Ok, onOk); + this.off(Constants.ResponseCodes.Err, onErr); + this.off(Constants.ResponseCodes.Disabled, onDisabled); + reject("disabled"); + } + + // listen for events + this.once(Constants.ResponseCodes.Ok, onOk); + this.once(Constants.ResponseCodes.Err, onErr); + this.once(Constants.ResponseCodes.Disabled, onDisabled); + + // import private key + await this.sendCommandImportPrivateKey(privateKey); + + } catch(e) { + reject(e); + } + }); + } + } export default Connection; diff --git a/src/constants.js b/src/constants.js index 9c45460..567aa02 100644 --- a/src/constants.js +++ b/src/constants.js @@ -34,6 +34,8 @@ class Constants { GetBatteryVoltage: 20, SetTuningParams: 21, // todo DeviceQuery: 22, + ExportPrivateKey: 23, + ImportPrivateKey: 24, } static ResponseCodes = { @@ -51,6 +53,8 @@ class Constants { ExportContact: 11, BatteryVoltage: 12, DeviceInfo: 13, + PrivateKey: 14, + Disabled: 15, } static PushCodes = {