Skip to content
This repository has been archived by the owner on Oct 7, 2024. It is now read-only.

Add method for OneKey device analysis #136

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,36 @@ const TREZOR_CONNECT_MANIFEST = {
appUrl: 'https://metamask.io',
};

const oneKeySpecialVersion = 99;
const oneKeyVendor = 'onekey.so';

/**
* get the vendor name of the hardware wallet
* @param {object} features
* @returns {'onekey' | 'trezor' | undefined}
*/
function getVendorName(features) {
// If the value of features is null, set vendor to the default value
if (!features) {
return undefined;
}

// No special field, default is trezor device
if (!features.minor_version || !features.patch_version) {
return 'trezor';
}

if (
features.vendor === oneKeyVendor ||
(features.minor_version === oneKeySpecialVersion &&
features.patch_version === oneKeySpecialVersion)
) {
return 'onekey';
}

return 'trezor';
}

function wait(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
Expand Down Expand Up @@ -58,6 +88,7 @@ class TrezorKeyring extends EventEmitter {
this.perPage = 5;
this.unlockedAccount = 0;
this.paths = {};
this.vendor = undefined;
this.deserialize(opts);

TrezorConnect.on('DEVICE_EVENT', (event) => {
Expand All @@ -78,6 +109,34 @@ class TrezorKeyring extends EventEmitter {
return this.model;
}

/**
* Gets the vendor, if known.
*
* @returns {"trezor" | "onekey" | null}
*/
async getVendor() {
return this.vendor || (this.vendor = await this.fetchVendor());
originalix marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* fetch vendor by call getFeatures
* @private
* @param {object} features
* @returns {'onekey' | 'trezor' | null}
*/
async fetchVendor() {
try {
const response = await TrezorConnect.getFeatures();
if (!response.success) {
return null;
}
const vendor = getVendorName(response.payload);
return vendor;
} catch (err) {
return null;
}
}

dispose() {
// This removes the Trezor Connect iframe from the DOM
// This method is not well documented, but the code it calls can be seen
Expand Down
97 changes: 97 additions & 0 deletions test/test-eth-trezor-keyring.js
Original file line number Diff line number Diff line change
Expand Up @@ -694,4 +694,101 @@ describe('TrezorKeyring', function () {
}
});
});

describe('getVendor', function () {
it('should call TrezorConnect.getFeatures if we dont have vendor name', async function () {
sinon
.stub(TrezorConnect, 'getFeatures')
.callsFake(() => Promise.resolve({}));

await keyring.getVendor();
assert(TrezorConnect.getFeatures.calledOnce);
});

it('should return null when TrezorConnect.getFeatures resolves with an object that does not have a success property', async function () {
sinon
.stub(TrezorConnect, 'getFeatures')
.callsFake(() => Promise.resolve({}));

const vendor = await keyring.getVendor();
assert.equal(vendor, null);
});

it('should return trezor when getFeatures does not have minor_version or patch_version', async function () {
originalix marked this conversation as resolved.
Show resolved Hide resolved
sinon.stub(TrezorConnect, 'getFeatures').callsFake(() =>
Promise.resolve({
success: true,
payload: {
vendor: 'trezor.io',
},
}),
);

const vendor = await keyring.getVendor();
assert.equal(vendor, 'trezor');
});

it('should return onekey when minor_version and patch_version is a special version', async function () {
sinon.stub(TrezorConnect, 'getFeatures').callsFake(() =>
Promise.resolve({
success: true,
payload: {
minor_version: 99,
patch_version: 99,
vendor: 'trezor.io',
},
}),
);

const vendor = await keyring.getVendor();
assert.equal(vendor, 'onekey');
});

it('should return onekey when vendor field is onekey.so', async function () {
sinon.stub(TrezorConnect, 'getFeatures').callsFake(() =>
Promise.resolve({
success: true,
payload: {
minor_version: 1,
patch_version: 1,
vendor: 'onekey.so',
},
}),
);

const vendor = await keyring.getVendor();
assert.equal(vendor, 'onekey');
});
originalix marked this conversation as resolved.
Show resolved Hide resolved

it('should return null when TrezorConnect.getFeatures rejects with an error', async function () {
sinon.stub(TrezorConnect, 'getFeatures').callsFake(() =>
// eslint-disable-next-line prefer-promise-reject-errors
Promise.reject({
success: false,
payload: { error: 'mock error', code: 'mock error code' },
}),
);

const vendor = await keyring.getVendor();
assert.equal(vendor, null);
});

it('should called once TrezorConnect.getFeatures function when getVendor called more then once', async function () {
sinon.stub(TrezorConnect, 'getFeatures').callsFake(() =>
Promise.resolve({
success: true,
payload: {
minor_version: 1,
patch_version: 1,
vendor: 'onekey.so',
},
}),
);

for (let i = 0; i < 10; i++) {
await keyring.getVendor();
}
assert(TrezorConnect.getFeatures.calledOnce);
});
});
});