feat!: Standalone web JS Client (#243)

- Move marine-related part into FJS repo (fixes DXJ-184)
- Move towards component-oriented architecture (fixes DXJ-183)
- Different JS Client distros for node.js and web (fixes DXJ-185)
- Update libp2p to 0.42.2 (fixes DXJ-26)
- Add JS Client API (fixes DXJ-196, fixes DXJ-177, fixes DXJ-60)
- Add Smoke test for JS Client web (fixes DXJ-253)

---------

Co-authored-by: Anatoly Laskaris <github_me@nahsi.dev>
This commit is contained in:
Pavel
2023-02-13 17:41:35 +03:00
committed by GitHub
parent e02c506d7f
commit 9667c4fec6
212 changed files with 16522 additions and 7886 deletions

View File

@ -0,0 +1,94 @@
import { toUint8Array } from 'js-base64';
import * as bs58 from 'bs58';
import { KeyPair } from '../index.js';
// @ts-ignore
const { decode } = bs58.default;
const key = '+cmeYlZKj+MfSa9dpHV+BmLPm6wq4inGlsPlQ1GvtPk=';
const keyBytes = toUint8Array(key);
const testData = Uint8Array.from([1, 2, 3, 4, 5, 6, 7, 9, 10]);
const testDataSig = Uint8Array.from([
224, 104, 245, 206, 140, 248, 27, 72, 68, 133, 111, 10, 164, 197, 242, 132, 107, 77, 224, 67, 99, 106, 76, 29, 144,
121, 122, 169, 36, 173, 58, 80, 170, 102, 137, 253, 157, 247, 168, 87, 162, 223, 188, 214, 203, 220, 52, 246, 29,
86, 77, 71, 224, 248, 16, 213, 254, 75, 78, 239, 243, 222, 241, 15,
]);
// signature produced by KeyPair created from some random KeyPair
describe('KeyPair tests', () => {
it('generate keypair from seed', async function () {
// arrange
const random = await KeyPair.randomEd25519();
const privateKey = random.toEd25519PrivateKey();
// act
const keyPair = await KeyPair.fromEd25519SK(privateKey);
const privateKey2 = keyPair.toEd25519PrivateKey();
// assert
expect(privateKey).toStrictEqual(privateKey2);
});
it('create keypair from ed25519 private key', async function () {
// arrange
const rustSK = 'jDaxLJzYtzgwTMrELJCAqavtmx85ktQNfB2rLcK7MhH';
const sk = decode(rustSK);
// act
const keyPair = await KeyPair.fromEd25519SK(sk);
// assert
const expectedPeerId = '12D3KooWH1W3VznVZ87JH4FwABK4mkntcspTVWJDta6c2xg9Pzbp';
expect(keyPair.getPeerId()).toStrictEqual(expectedPeerId);
});
it('create keypair from a seed phrase', async function () {
// arrange
const seedArray = new Uint8Array(32).fill(1);
// act
const keyPair = await KeyPair.fromEd25519SK(seedArray);
// assert
const expectedPeerId = '12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5';
expect(keyPair.getPeerId()).toStrictEqual(expectedPeerId);
});
it('sign', async function () {
// arrange
const keyPair = await KeyPair.fromEd25519SK(keyBytes);
// act
const res = await keyPair.signBytes(testData);
// assert
expect(res).toStrictEqual(testDataSig);
});
it('verify', async function () {
// arrange
const keyPair = await KeyPair.fromEd25519SK(keyBytes);
// act
const res = await keyPair.verify(testData, testDataSig);
// assert
expect(res).toBe(true);
});
it('sign-verify', async function () {
// arrange
const keyPair = await KeyPair.fromEd25519SK(keyBytes);
// act
const data = new Uint8Array(32).fill(1);
const sig = await keyPair.signBytes(data);
const res = await keyPair.verify(data, sig);
// assert
expect(res).toBe(true);
});
});

View File

@ -0,0 +1,95 @@
/*
* Copyright 2020 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type { PeerId } from '@libp2p/interface-peer-id';
import { generateKeyPairFromSeed, generateKeyPair } from '@libp2p/crypto/keys';
import { createFromPrivKey } from '@libp2p/peer-id-factory';
import type { PrivateKey } from '@libp2p/interface-keys';
import { toUint8Array } from 'js-base64';
import * as bs58 from 'bs58';
import { KeyPairOptions } from '@fluencelabs/interfaces';
// @ts-ignore
const { decode } = bs58.default;
export class KeyPair {
/**
* Key pair in libp2p format. Used for backward compatibility with the current FluencePeer implementation
*/
getLibp2pPeerId() {
return this.libp2pPeerId;
}
constructor(private key: PrivateKey, private libp2pPeerId: PeerId) {}
/**
* Generates new KeyPair from ed25519 private key represented as a 32 byte array
* @param seed - Any sequence of 32 bytes
* @returns - Promise with the created KeyPair
*/
static async fromEd25519SK(seed: Uint8Array): Promise<KeyPair> {
const key = await generateKeyPairFromSeed('Ed25519', seed, 256);
const lib2p2Pid = await createFromPrivKey(key);
return new KeyPair(key, lib2p2Pid);
}
/**
* Generates new KeyPair with a random secret key
* @returns - Promise with the created KeyPair
*/
static async randomEd25519(): Promise<KeyPair> {
const key = await generateKeyPair('Ed25519');
const lib2p2Pid = await createFromPrivKey(key);
return new KeyPair(key, lib2p2Pid);
}
getPeerId(): string {
return this.libp2pPeerId.toString();
}
/**
* @returns 32 byte private key
*/
toEd25519PrivateKey(): Uint8Array {
return this.key.marshal().subarray(0, 32);
}
signBytes(data: Uint8Array): Promise<Uint8Array> {
return this.key.sign(data);
}
verify(data: Uint8Array, signature: Uint8Array): Promise<boolean> {
return this.key.public.verify(data, signature);
}
}
export const fromBase64Sk = (sk: string): Promise<KeyPair> => {
const skArr = toUint8Array(sk);
return KeyPair.fromEd25519SK(skArr);
};
export const fromBase58Sk = (sk: string): Promise<KeyPair> => {
const skArr = decode(sk);
return KeyPair.fromEd25519SK(skArr);
};
export const fromOpts = (opts: KeyPairOptions): Promise<KeyPair> => {
if (opts.source === 'random') {
return KeyPair.randomEd25519();
}
return KeyPair.fromEd25519SK(opts.source);
};