implement private key import and export

This commit is contained in:
liamcottle 2025-02-21 16:58:17 +13:00
parent a95402c68b
commit a04a3a9b19
3 changed files with 148 additions and 0 deletions

View file

@ -104,6 +104,12 @@
<button @click="getBatteryVoltage" class="border border-gray-500 px-2 bg-gray-100 hover:bg-gray-200 rounded">
GetBatteryVoltage
</button>
<button @click="exportPrivateKey" class="border border-gray-500 px-2 bg-gray-100 hover:bg-gray-200 rounded">
ExportPrivateKey
</button>
<button @click="importPrivateKey" class="border border-gray-500 px-2 bg-gray-100 hover:bg-gray-200 rounded">
ImportPrivateKey
</button>
</div>
</div>
@ -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();

View file

@ -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;

View file

@ -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 = {