diff --git a/packages/keyring/src/index.spec.ts b/packages/keyring/src/index.spec.ts index 2ff56620e..954138c60 100644 --- a/packages/keyring/src/index.spec.ts +++ b/packages/keyring/src/index.spec.ts @@ -1,9 +1,12 @@ // Copyright 2017-2021 @polkadot/keyring authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { hexToU8a, stringToU8a } from '@polkadot/util'; -import { cryptoWaitReady, encodeAddress, randomAsU8a, setSS58Format } from '@polkadot/util-crypto'; +import type { KeyringPair$Json } from './types'; +import { hexToU8a, stringToU8a } from '@polkadot/util'; +import { base64Decode, cryptoWaitReady, encodeAddress, randomAsU8a, setSS58Format } from '@polkadot/util-crypto'; + +import { decodePair } from './pair/decode'; import Keyring from '.'; describe('keypair', (): void => { @@ -429,6 +432,30 @@ describe('keypair', (): void => { }); }); + describe('raw pair add/create', (): void => { + const json = JSON.parse('{"address":"5PjeoaQzCoYbSi42aQRKB3Sx18StCaEAzCbGEEbWbZyfKS3H","encoded":"JQUl8ZpoXv2OMkL9TPylLmcIye2cYhaS9INICbFgZTsAgAAAAQAAAAgAAAAr/0hJOOzokIdBG71TstigLABX9D5xGD7L37ySxtjDrVRg26LL90jLQ47quT9o3bq6ppXMVL6USk7Q4p3WU66bojTFuCDyhpYRhNbUqU6s0rD3S4bhv9lG+pG9vQ4eD5PVQUvxdANmJpYuDg45nrTmsMC5AHGdFGkHW/LHnkmbFid1cvPYkdiBoef5CIEdoly512pxMupVxnJWF1NT","encoding":{"content":["pkcs8","sr25519"],"type":["scrypt","xsalsa20-poly1305"],"version":"3"},"meta":{"name":"hello"}}') as KeyringPair$Json; + const decoded = decodePair('1', base64Decode(json.encoded), json.encoding.type); + const keyring = new Keyring({ ss58Format: 44 }); + + it('creates a pair from a private/public combo', (): void => { + const pair = keyring.createFromPair(decoded, json.meta, 'sr25519'); + + expect(pair.address).toEqual('5PjeoaQzCoYbSi42aQRKB3Sx18StCaEAzCbGEEbWbZyfKS3H'); + expect(pair.isLocked).toEqual(false); + expect(pair.meta.name).toEqual('hello'); + }); + + it('adds a pair from a private/public combo', (): void => { + keyring.addFromPair(decoded, json.meta, 'sr25519'); + + const pair = keyring.getPairs()[0]; + + expect(pair.address).toEqual('5PjeoaQzCoYbSi42aQRKB3Sx18StCaEAzCbGEEbWbZyfKS3H'); + expect(pair.isLocked).toEqual(false); + expect(pair.meta.name).toEqual('hello'); + }); + }); + describe('util', (): void => { let keyring: Keyring; diff --git a/packages/keyring/src/keyring.ts b/packages/keyring/src/keyring.ts index b0968c866..b7b38907f 100644 --- a/packages/keyring/src/keyring.ts +++ b/packages/keyring/src/keyring.ts @@ -120,6 +120,16 @@ export class Keyring implements KeyringInstance { return this.addFromUri(mnemonic, meta, type); } + /** + * @name addFromPair + * @summary Stores an account created from an explicit publicKey/secreteKey combination + */ + public addFromPair (pair: Keypair, meta: KeyringPair$Meta = {}, type: KeypairType = this.type): KeyringPair { + return this.addPair( + this.createFromPair(pair, meta, type) + ); + } + /** * @name addFromSeed * @summary Stores an account, given seed data, as a Key/Value (public key, pair) in Keyring Pair Dictionary @@ -128,7 +138,9 @@ export class Keyring implements KeyringInstance { * `addPair` to store in a keyring pair dictionary the public key of the generated pair as a key and the pair as the associated value. */ public addFromSeed (seed: Uint8Array, meta: KeyringPair$Meta = {}, type: KeypairType = this.type): KeyringPair { - return this.addPair(createPair({ toSS58: this.encodeAddress, type }, keypairFromSeed[type](seed), meta, null)); + return this.addPair( + createPair({ toSS58: this.encodeAddress, type }, keypairFromSeed[type](seed), meta, null) + ); } /** @@ -169,6 +181,14 @@ export class Keyring implements KeyringInstance { return createPair({ toSS58: this.encodeAddress, type: cryptoType as KeypairType }, { publicKey, secretKey: new Uint8Array() }, meta, decoded, encType); } + /** + * @name createFromPair + * @summary Creates a pair from an explicit publicKey/secreteKey combination + */ + public createFromPair (pair: Keypair, meta: KeyringPair$Meta = {}, type: KeypairType = this.type): KeyringPair { + return createPair({ toSS58: this.encodeAddress, type }, pair, meta, null); + } + /** * @name createFromUri * @summary Creates a Keypair from an suri diff --git a/packages/keyring/src/pair/decode.ts b/packages/keyring/src/pair/decode.ts index e2f85a38e..184c3cb99 100644 --- a/packages/keyring/src/pair/decode.ts +++ b/packages/keyring/src/pair/decode.ts @@ -4,7 +4,7 @@ import type { EncryptedJsonEncoding } from '@polkadot/util-crypto/json/types'; import type { PairInfo } from './types'; -import { assert, u8aEq } from '@polkadot/util'; +import { assert, isUndefined, u8aEq } from '@polkadot/util'; import { jsonDecryptData } from '@polkadot/util-crypto'; import { PKCS8_DIVIDER, PKCS8_HEADER, PUB_LENGTH, SEC_LENGTH, SEED_LENGTH } from './defaults'; @@ -15,7 +15,10 @@ type DecodeResult = PairInfo & { secretKey: Uint8Array; }; -export function decodePair (passphrase?: string, encrypted?: Uint8Array | null, encType?: EncryptedJsonEncoding[]): DecodeResult { +export function decodePair (passphrase?: string, encrypted?: Uint8Array | null, _encType?: EncryptedJsonEncoding | EncryptedJsonEncoding[]): DecodeResult { + const encType = Array.isArray(_encType) || isUndefined(_encType) + ? _encType + : [_encType]; const decrypted = jsonDecryptData(encrypted, passphrase, encType); const header = decrypted.subarray(0, PKCS8_HEADER.length); diff --git a/packages/keyring/src/types.ts b/packages/keyring/src/types.ts index 98a716466..30c09fac4 100644 --- a/packages/keyring/src/types.ts +++ b/packages/keyring/src/types.ts @@ -3,7 +3,7 @@ import type { Prefix } from '@polkadot/util-crypto/address/types'; import type { EncryptedJson } from '@polkadot/util-crypto/json/types'; -import type { KeypairType } from '@polkadot/util-crypto/types'; +import type { Keypair, KeypairType } from '@polkadot/util-crypto/types'; export interface KeyringOptions { ss58Format?: Prefix; @@ -62,9 +62,11 @@ export interface KeyringInstance { addFromAddress (address: string | Uint8Array, meta?: KeyringPair$Meta, encoded?: Uint8Array | null, type?: KeypairType, ignoreChecksum?: boolean): KeyringPair; addFromJson (pair: KeyringPair$Json, ignoreChecksum?: boolean): KeyringPair; addFromMnemonic (mnemonic: string, meta?: KeyringPair$Meta, type?: KeypairType): KeyringPair; + addFromPair (pair: Keypair, meta?: KeyringPair$Meta, type?: KeypairType): KeyringPair addFromSeed (seed: Uint8Array, meta?: KeyringPair$Meta, type?: KeypairType): KeyringPair; addFromUri (suri: string, meta?: KeyringPair$Meta, type?: KeypairType): KeyringPair; createFromJson (json: KeyringPair$Json, ignoreChecksum?: boolean): KeyringPair; + createFromPair (pair: Keypair, meta: KeyringPair$Meta, type: KeypairType): KeyringPair createFromUri (suri: string, meta?: KeyringPair$Meta, type?: KeypairType): KeyringPair; getPair (address: string | Uint8Array): KeyringPair; getPairs (): KeyringPair[];