Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: ECDSAKeyIdentity #591

Merged
merged 54 commits into from Jul 22, 2022
Merged
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
eb509f6
wip
krpeacock Jun 28, 2022
60dc610
feat: jwk support for ecdsa
krpeacock Jun 29, 2022
20b28dd
wip
krpeacock Jul 1, 2022
eb41716
supports DER-encoding
krpeacock Jul 6, 2022
2e91698
ECDSAKeyIdentity
krpeacock Jul 6, 2022
b5a0441
upgrading packages
krpeacock Jul 6, 2022
409c5ce
working e2e call
krpeacock Jul 7, 2022
e8e7bea
allow providing a SubtleCrypto interface
krpeacock Jul 11, 2022
1564116
tests passing
krpeacock Jul 11, 2022
1e3328b
fixing authclient tests after jest update
krpeacock Jul 11, 2022
20da536
Merge branch 'main' into SDK-554-ecdsakeyidentity
krpeacock Jul 11, 2022
bd05f9b
changelog and readme
krpeacock Jul 11, 2022
cfbb6bb
ECDSAPublicKey docs
krpeacock Jul 11, 2022
2f0f37a
docs for ECDSAKeyIdentity
krpeacock Jul 11, 2022
f322446
pulling lint out to separate job
krpeacock Jul 12, 2022
9d427ef
remove todo
krpeacock Jul 12, 2022
587739b
tweaking lint job
krpeacock Jul 12, 2022
23c0e28
fixing package.json
krpeacock Jul 12, 2022
508e3e5
switching to isomomorphic-fetch
krpeacock Jul 12, 2022
97f9352
switch over to miracl_core (#590)
Daniel-Bloom-dfinity Jul 12, 2022
968530c
chore: aggregate test results for required statuses (#592)
ericswanson-dfinity Jul 12, 2022
32027b3
feat: enables inline sourcemaps for packages for developer experience…
krpeacock Jul 13, 2022
05e12ec
chore: release 0.12.1 (#594)
krpeacock Jul 13, 2022
2d7e126
wip
krpeacock Jun 28, 2022
94b673f
feat: jwk support for ecdsa
krpeacock Jun 29, 2022
25fb4eb
wip
krpeacock Jul 1, 2022
87e70fb
supports DER-encoding
krpeacock Jul 6, 2022
8e1b800
ECDSAKeyIdentity
krpeacock Jul 6, 2022
af86e13
upgrading packages
krpeacock Jul 6, 2022
fa207f5
working e2e call
krpeacock Jul 7, 2022
dac0f8a
allow providing a SubtleCrypto interface
krpeacock Jul 11, 2022
6efbe94
tests passing
krpeacock Jul 11, 2022
44907fb
fixing authclient tests after jest update
krpeacock Jul 11, 2022
6c9c445
changelog and readme
krpeacock Jul 11, 2022
b0966ce
ECDSAPublicKey docs
krpeacock Jul 11, 2022
d8461f3
docs for ECDSAKeyIdentity
krpeacock Jul 11, 2022
d79f352
pulling lint out to separate job
krpeacock Jul 12, 2022
e4c1c80
remove todo
krpeacock Jul 12, 2022
7337365
tweaking lint job
krpeacock Jul 12, 2022
a6edab0
switching to isomomorphic-fetch
krpeacock Jul 12, 2022
d1e08e4
Merge branch 'SDK-554-ecdsakeyidentity' of https://github.com/dfinity…
krpeacock Jul 14, 2022
1539e15
resolving merge conflicts
krpeacock Jul 14, 2022
b8c732f
using spki encoding for DER-encoding
krpeacock Jul 18, 2022
21c6d08
using spki encoding for DER-encoding
krpeacock Jul 18, 2022
f8339c2
Merge branch 'SDK-554-ecdsakeyidentity' of https://github.com/dfinity…
krpeacock Jul 18, 2022
2e7e7b5
clarifies that public keys are always extractable
krpeacock Jul 18, 2022
84f1070
updating snapshots
krpeacock Jul 18, 2022
d6b9d89
e2e browser tests for identity
krpeacock Jul 20, 2022
b666291
updating browser scripts
krpeacock Jul 20, 2022
d24668f
e2e tests exit code
krpeacock Jul 20, 2022
66b2f42
fixing lint
krpeacock Jul 20, 2022
bdf6cc6
backgorund task
krpeacock Jul 20, 2022
9223271
refactoring out redundant publickey
krpeacock Jul 22, 2022
b47d05c
removes references to ECDSAKeyIdentity
krpeacock Jul 22, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 10 additions & 1 deletion .github/workflows/e2e-tests.yml
Expand Up @@ -31,7 +31,6 @@ jobs:
- run: npm install -g npm

- run: npm install
- run: npm run lint --workspaces --if-present

# build monorepo incl. each subpackage
- run: npm run build --workspaces --if-present
Expand All @@ -47,3 +46,13 @@ jobs:
env:
CI: true
REPLICA_PORT: 8000

aggregate:
name: e2e:required
if: ${{ always() }}
needs: [ test ]
runs-on: ubuntu-latest
steps:
- name: check e2e test result
if: ${{ needs.test.result != 'success' }}
run: exit 1
30 changes: 30 additions & 0 deletions .github/workflows/lint.yml
@@ -0,0 +1,30 @@
name: Check Lint
on:
pull_request:
types:
- opened
- reopened
- edited
- synchronize

jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: true
matrix:
os: [ubuntu-18.04]
ghc: ['8.8.4']
spec:
- release-0.16 # https://github.com/dfinity-lab/ic-ref/tree/release-0.16
node:
- 14
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node }}
- run: npm install -g npm
- run: npm install
- run: npm run lint --workspaces --if-present
10 changes: 10 additions & 0 deletions .github/workflows/mitm.yml
Expand Up @@ -63,3 +63,13 @@ jobs:
REPLICA_PORT: 8888
MITM: true
run: npm run mitm --workspaces --if-present

aggregate:
name: mitm:required
if: ${{ always() }}
needs: [ test ]
runs-on: ubuntu-latest
steps:
- name: check e2e test result
if: ${{ needs.test.result != 'success' }}
run: exit 1
10 changes: 10 additions & 0 deletions .github/workflows/prettier.yml
Expand Up @@ -28,3 +28,13 @@ jobs:
- run: npm install -g npm
- run: npm install prettier pretty-quick
- run: npm run prettier:check

aggregate:
name: format:required
if: ${{ always() }}
needs: [ test ]
runs-on: ubuntu-latest
steps:
- name: check e2e test result
if: ${{ needs.test.result != 'success' }}
run: exit 1
11 changes: 10 additions & 1 deletion .github/workflows/unit-tests.yml
Expand Up @@ -33,7 +33,6 @@ jobs:
- run: npm install -g npm

- run: npm install
- run: npm run lint --workspaces --if-present

# build monorepo incl. each subpackage
- run: npm run build --workspaces --if-present
Expand All @@ -42,3 +41,13 @@ jobs:
- run: npm run test
env:
CI: true

aggregate:
name: unit:required
if: ${{ always() }}
needs: [ test ]
runs-on: ubuntu-latest
steps:
- name: check e2e test result
if: ${{ needs.test.result != 'success' }}
run: exit 1
13 changes: 7 additions & 6 deletions demos/ledgerhq/package.json
Expand Up @@ -2,18 +2,19 @@
"name": "ic-agent-ledgerhq-app",
"private": true,
"dependencies": {
"@dfinity/agent": "^0.12.0",
"@dfinity/authentication": "^0.12.0",
"@dfinity/identity": "^0.12.0",
"@dfinity/identity-ledgerhq": "^0.12.0",
"@dfinity/principal": "^0.12.0",
"@dfinity/agent": "^0.12.1",
"@dfinity/authentication": "^0.12.1",
"@dfinity/identity": "^0.12.1",
"@dfinity/identity-ledgerhq": "^0.12.1",
"@dfinity/principal": "^0.12.1",
"assert": "^2.0.0",
"buffer": "^6.0.3",
"events": "^3.2.0",
"html-webpack-plugin": "^5.1.0",
"process": "^0.11.10",
"protobufjs": "^6.10.2",
"stream-browserify": "^3.0.0",
"ts-node": "^10.8.2",
"util": "^0.12.3",
"webpack": "^5.24.1",
"webpack-cli": "^4.5.0",
Expand All @@ -27,5 +28,5 @@
"test:coverage": "",
"test": ""
},
"version": "0.12.0"
"version": "0.12.1"
}
11 changes: 6 additions & 5 deletions demos/sample-javascript/package.json
Expand Up @@ -2,15 +2,16 @@
"name": "ic-agent-sample-javascript-app",
"private": true,
"dependencies": {
"@dfinity/agent": "^0.12.0",
"@dfinity/authentication": "^0.12.0",
"@dfinity/identity": "^0.12.0",
"@dfinity/principal": "^0.12.0",
"@dfinity/agent": "^0.12.1",
"@dfinity/authentication": "^0.12.1",
"@dfinity/identity": "^0.12.1",
"@dfinity/principal": "^0.12.1",
"assert": "^2.0.0",
"events": "^3.2.0",
"html-webpack-plugin": "^5.1.0",
"process": "^0.11.10",
"stream-browserify": "^3.0.0",
"ts-node": "^10.8.2",
"util": "^0.12.3",
"webpack": "^5.24.1",
"webpack-cli": "^4.5.0",
Expand All @@ -24,5 +25,5 @@
"test:coverage": "",
"test": ""
},
"version": "0.12.0"
"version": "0.12.1"
}
11 changes: 11 additions & 0 deletions docs/generated/changelog.html
Expand Up @@ -10,8 +10,19 @@
<h1>Agent-JS Changelog</h1>

<section>
<h2>Version 0.12.2</h2>
<ul>
<li>
Support for the SubtleCrypto interface in @dfinity/identity using the new ECDSAKeyIdentity
</li>
</ul>
<h2>Version 0.12.1</h2>
<ul>
<li>Adds inline sourcemaps to packages</li>
<li>
Pulls lint out to a separate job now that Node 12 is failing with latest eslint
dependencies
</li>
<li>Adds UTF-8 as an encoding option for CanisterStatus custom paths</li>
<li>
Adds a public method "createReadStateRequest" that creates the request for "readState".
Expand Down
78 changes: 78 additions & 0 deletions e2e/node/basic/identity.test.ts
Expand Up @@ -10,6 +10,7 @@ import {
DelegationIdentity,
Ed25519KeyIdentity,
Secp256k1KeyIdentity,
ECDSAKeyIdentity,
} from '@dfinity/identity';
import agent from '../utils/agent';
import identityCanister from '../canisters/identity';
Expand All @@ -26,6 +27,54 @@ function createSecpIdentity(seed: number): SignIdentity {
return Secp256k1KeyIdentity.generate(new Uint8Array(seed1));
}

async function createEcdsaIdentity(): Promise<ECDSAKeyIdentity> {
const goldenSeed = {
key_ops: [],
ext: true,
kty: 'EC',
x: 'EaSQG1HdU7pMzMXaIjZmDGZCa2wit-JX95cuLjZXsZI',
y: '-z31VJQ1dNFRkg-eFdet9SPatYph0OPz5vbju0eeT6o',
crv: 'P-256',
};

const goldenPrivateKey = {
key_ops: [],
ext: true,
kty: 'EC',
x: 'wUmIVyFHanPKCknjOWlMFFr9OKSahY7p5yT1vn4D-kw',
y: 'KhYIS2VFq98PU08q1KGYidRfEJ2qV-EUrfaRQ4XbV_4',
crv: 'P-256',
};

const getTestKeyPair = async (): Promise<CryptoKeyPair> => {
krpeacock marked this conversation as resolved.
Show resolved Hide resolved
const privateKey = await crypto.subtle.importKey(
'jwk',
goldenPrivateKey,
{
name: 'ECDSA',
namedCurve: 'P-256',
},
true,
[],
);
const publicKey = await crypto.subtle.importKey(
'jwk',
goldenSeed,
{
name: 'ECDSA',
namedCurve: 'P-256',
},
true,
[],
);
return {
privateKey,
publicKey,
};
};
return await ECDSAKeyIdentity.fromKeyPair(await getTestKeyPair());
}

async function createIdentityActor(
seed: number,
canisterId: Principal,
Expand Down Expand Up @@ -58,6 +107,24 @@ async function createSecp256k1IdentityActor(
}) as any;
}

async function createEcdsaIdentityActor(
canisterId: Principal,
idl: IDL.InterfaceFactory,
identity?: SignIdentity,
): Promise<any> {
let effectiveIdentity: SignIdentity;
if (identity) {
effectiveIdentity = identity;
} else {
effectiveIdentity = await Ed25519KeyIdentity.generate();
krpeacock marked this conversation as resolved.
Show resolved Hide resolved
}
const agent1 = new HttpAgent({ source: await agent, identity: effectiveIdentity });
return Actor.createActor(idl, {
canisterId,
agent: agent1,
}) as any;
}

async function installIdentityCanister(): Promise<{
canisterId: Principal;
idl: IDL.InterfaceFactory;
Expand Down Expand Up @@ -105,6 +172,17 @@ test('identity: two different Secp256k1 keys should have a different principal',
expect(principal1).not.toEqual(principal2);
});

jest.setTimeout(30000);
test('identity: two different Ecdsa keys should have a different principal', async () => {
const { canisterId, idl } = await installIdentityCanister();
const identity1 = await createEcdsaIdentityActor(canisterId, idl);
const identity2 = await createEcdsaIdentityActor(canisterId, idl);

const principal1 = await identity1.whoami_query();
const principal2 = await identity2.whoami_query();
expect(principal1).not.toEqual(principal2);
});

jest.setTimeout(30000);
test('delegation: principal is the same between delegated keys with secp256k1', async () => {
const { canisterId, idl } = await installIdentityCanister();
Expand Down
2 changes: 1 addition & 1 deletion e2e/node/jest.config.ts
@@ -1,6 +1,7 @@
import type { Config } from '@jest/types';
const config: Config.InitialOptions = {
verbose: true,
testEnvironment: 'jsdom',
testPathIgnorePatterns: ['/node_modules/', '/lib/', '/dist/', '/docs/'],
testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)'],
roots: [`<rootDir>/e2e/node`],
Expand All @@ -12,7 +13,6 @@ const config: Config.InitialOptions = {
'^.+\\.ts$': 'ts-jest',
},
collectCoverageFrom: ['**/*.{ts,tsx}'],
name: 'e2e/node',
displayName: 'e2e-node',
rootDir: '../..',
};
Expand Down
49 changes: 29 additions & 20 deletions e2e/node/package.json
@@ -1,7 +1,7 @@
{
"private": true,
"name": "@do-not-publish/ic-node-e2e-tests",
"version": "0.12.0",
"version": "0.12.1",
"scripts": {
"ci": "npm run e2e",
"e2e": "jest --verbose",
Expand All @@ -16,27 +16,36 @@
"test": ""
},
"dependencies": {
"@dfinity/agent": "^0.12.0",
"@dfinity/authentication": "^0.12.0",
"@dfinity/identity": "^0.12.0",
"@dfinity/principal": "^0.12.0",
"@dfinity/agent": "^0.12.1",
"@dfinity/authentication": "^0.12.1",
"@dfinity/identity": "^0.12.1",
"@dfinity/principal": "^0.12.1",
"@trust/webcrypto": "^0.9.2",
"@types/base64-js": "^1.2.5",
"@types/jest": "^26.0.23",
"@types/node": "^13.7.7",
"@typescript-eslint/eslint-plugin": "^4.14.2",
"@typescript-eslint/parser": "^4.14.2",
"eslint": "^7.19.0",
"eslint-plugin-jsdoc": "^31.6.0",
"jest": "^27.3.1",
"node-fetch": "^2.6.7",
"@types/base64-js": "^1.3.0",
"@types/jest": "^28.1.4",
"@typescript-eslint/eslint-plugin": "^5.30.5",
"@typescript-eslint/parser": "^5.30.5",
"eslint": "^8.19.0",
"eslint-plugin-jsdoc": "^39.3.3",
"jest": "^28.1.2",
"text-encoding": "^0.7.0",
"ts-jest": "^27.0.7",
"ts-node": "^9.1.1",
"typescript": "^3.6.3",
"whatwg-fetch": "^3.0.0"
"ts-jest": "^28.0.5",
"ts-node": "^10.8.2",
"typescript": "^4.7.4",
"whatwg-fetch": "^3.6.2"
},
"jest": {
"preset": "ts-jest"
"devDependencies": {
"@babel/preset-env": "^7.18.6",
"@babel/preset-typescript": "^7.18.6",
"@peculiar/webcrypto": "^1.4.0",
"@tsconfig/node16": "^1.0.3",
"@tsconfig/node17": "^1.0.1",
"@types/isomorphic-fetch": "^0.0.36",
"@types/text-encoding": "^0.0.36",
"isomorphic-fetch": "^3.0.0",
"jest-environment-jsdom": "^28.1.3",
"locus": "^2.0.4",
"node-webcrypto-p11": "^2.5.0",
"webcrypto-core": "^1.7.5"
}
}
20 changes: 16 additions & 4 deletions e2e/node/test-setup.ts
Expand Up @@ -5,9 +5,21 @@
// a feature that JSDom doesn't.
//
// Note that we can use webpack configuration to make some features available to

// Node.js in a similar way.
// import { TextEncoder, TextDecoder } from 'text-encoding'; // eslint-disable-line
// import fetch from 'isomorphic-fetch';
// global.crypto = crypto as unknown as Crypto;
// console.log('subtle', crypto['subtle']); // eslint-disable-line
// global.TextDecoder = TextDecoder; // eslint-disable-line
// global.TextEncoder = TextEncoder;

// global.TextDecoder = TextDecoder; // eslint-disable-line
// (global.fetch as any) = fetch;
import fetch from 'isomorphic-fetch';
global.fetch = fetch;
import * as crypto from 'crypto';

global.crypto = require('@trust/webcrypto');
global.TextEncoder = require('text-encoding').TextEncoder; // eslint-disable-line
global.TextDecoder = require('text-encoding').TextDecoder; // eslint-disable-line
global.fetch = require('node-fetch');
(global as any).crypto = {
subtle: (crypto.webcrypto as any).subtle,
};