Private fields via # (#249)

* Private fields via #

* Edgewae type overrides
This commit is contained in:
Jaco Greeff 2020-02-23 06:40:39 +01:00 committed by GitHub
parent 01203ccb83
commit 0a9e9f3bed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 682 additions and 428 deletions

View File

@ -12,13 +12,13 @@
"yarn": "^1.10.1"
},
"resolutions": {
"@polkadot/api": "^1.3.0-beta.8",
"@polkadot/keyring": "^2.4.0-beta.0",
"@polkadot/types": "^1.3.0-beta.8",
"@polkadot/util": "^2.4.0-beta.0",
"@polkadot/util-crypto": "^2.4.0-beta.0",
"@polkadot/api": "^1.4.0-beta.30",
"@polkadot/keyring": "^2.5.1",
"@polkadot/types": "^1.4.0-beta.30",
"@polkadot/util": "^2.5.1",
"@polkadot/util-crypto": "^2.5.1",
"babel-core": "^7.0.0-bridge.0",
"typescript": "^3.7.5"
"typescript": "^3.8.2"
},
"scripts": {
"build": "NODE_ENV=production polkadot-dev-build-ts",
@ -32,7 +32,7 @@
},
"devDependencies": {
"@babel/core": "^7.8.4",
"@polkadot/dev": "^0.40.17",
"@polkadot/dev": "^0.41.3",
"@polkadot/ts": "^0.2.3",
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.2",

View File

@ -0,0 +1,90 @@
/* eslint-disable comma-dangle */
/* eslint-disable lines-between-class-members */
/* eslint-disable @typescript-eslint/camelcase */
import { Bytes, Text, u32, Null } from '@polkadot/types';
import { Option, Struct, Enum } from '@polkadot/types/codec';
import { AccountId } from '@polkadot/types/interfaces';
import { Registry } from '@polkadot/types/types';
export class MetadataRecord extends Struct {
constructor (registry: Registry, value: any) {
super(registry, {
avatar: Text,
display_name: Text,
tagline: Text,
}, value);
}
get avatar (): Text {
return this.get('avatar') as Text;
}
get display_name (): Text {
return this.get('display_name') as Text;
}
get tagline (): Text {
return this.get('tagline') as Text;
}
}
export class Registered extends Null { }
export class Attested extends Null { }
export class Verified extends Null { }
export class IdentityStage extends Enum {
constructor (registry: Registry, value?: string, index?: number) {
super(registry, {
registered: Registered,
attested: Attested,
verified: Verified,
}, value, index);
}
}
export class IdentityRecord extends Struct {
constructor (registry: Registry, value: any) {
super(registry, {
account: 'AccountId',
identity_type: Text,
identity: Bytes,
stage: IdentityStage,
expiration_time: u32,
proof: Option.with(Text),
metadata: Option.with(MetadataRecord),
}, value);
}
get account (): AccountId {
return this.get('account') as AccountId;
}
get identity (): Bytes {
return this.get('identity') as Bytes;
}
get stage (): IdentityStage {
return this.get('stage') as IdentityStage;
}
get expiration_time (): u32 {
return this.get('expiration_time') as u32;
}
get proof (): Option<Text> {
return this.get('proof') as Option<Text>;
}
get metadata (): Option<MetadataRecord> {
return this.get('metadata') as Option<MetadataRecord>;
}
}
// Old types that aren't used anymore (kept for backwards compatability)
const ArchivedTypes = {
IdentityIndex: u32,
Claim: Bytes,
};
// Current types
const CurrentTypes = {
IdentityStage,
IdentityRecord,
MetadataRecord,
IdentityType: Text,
Attestation: Bytes,
Identity: Bytes,
};
export const IdentityTypes = { ...ArchivedTypes, ...CurrentTypes };

View File

@ -0,0 +1,11 @@
import { IdentityTypes } from './identity';
import { SignalingTypes } from './signaling';
import { TreasuryRewardTypes } from './treasuryReward';
import { VotingTypes } from './voting';
export const EdgewareTypes = {
...IdentityTypes,
...SignalingTypes,
...TreasuryRewardTypes,
...VotingTypes
};

View File

@ -0,0 +1,54 @@
/* eslint-disable comma-dangle */
/* eslint-disable lines-between-class-members */
/* eslint-disable @typescript-eslint/camelcase */
import { u32, Text, u64, Bytes } from '@polkadot/types';
import { Struct } from '@polkadot/types/codec';
import { AccountId } from '@polkadot/types/interfaces';
import { Registry } from '@polkadot/types/types';
import { VotingTypes, VoteStage } from './voting';
export class ProposalRecord extends Struct {
constructor (registry: Registry, value: any) {
super(registry, {
index: u32,
author: 'AccountId',
stage: VoteStage,
transition_time: u32,
title: Text,
contents: Text,
vote_id: u64,
}, value);
}
get index (): u32 {
return this.get('index') as u32;
}
get author (): AccountId {
return this.get('author') as AccountId;
}
get stage (): VoteStage {
return this.get('stage') as VoteStage;
}
get transition_time (): u32 {
return this.get('transition_time') as u32;
}
get title (): Text {
return this.get('title') as Text;
}
get contents (): Text {
return this.get('contents') as Text;
}
get vote_id (): u64 {
return this.get('vote_id') as u64;
}
}
export const SignalingTypes = {
PreVoting: VotingTypes.PreVoting,
Voting: VotingTypes.Voting,
Completed: VotingTypes.Completed,
Commit: VotingTypes.Commit,
VoteStage,
ProposalRecord,
ProposalContents: Bytes,
ProposalTitle: Bytes,
};

View File

@ -0,0 +1,7 @@
import { u128 } from '@polkadot/types';
export class Balance2 extends u128 { }
export const TreasuryRewardTypes = {
Balance2
};

View File

@ -0,0 +1,134 @@
/* eslint-disable comma-dangle */
/* eslint-disable lines-between-class-members */
/* eslint-disable @typescript-eslint/camelcase */
import { Null, bool, u64, Enum, Struct, Vec, Tuple, Option, u128 } from '@polkadot/types';
import U8aFixed from '@polkadot/types/codec/U8aFixed';
import { AccountId } from '@polkadot/types/interfaces';
import { AnyU8a, Registry } from '@polkadot/types/types';
export class PreVoting extends Null { }
export class Commit extends Null { }
export class Voting extends Null { }
export class Completed extends Null { }
export class VoteStage extends Enum {
constructor (registry: Registry, value?: string, index?: number) {
super(registry, {
prevoting: PreVoting,
commit: Commit,
voting: Voting,
completed: Completed,
}, value, index);
}
}
export class Binary extends Null { }
export class MultiOption extends Null { }
export class RankedChoice extends Null { }
export class VoteType extends Enum {
constructor (registry: Registry, value?: string, index?: number) {
super(registry, {
binary: Binary,
multioption: MultiOption,
rankedchoice: RankedChoice,
}, value, index);
}
}
export class OnePerson extends Null { }
export class OneCoin extends Null { }
export class TallyType extends Enum {
constructor (registry: Registry, value?: string, index?: number) {
super(registry, {
oneperson: OnePerson,
onecoin: OneCoin,
}, value, index);
}
}
export class VoteOutcome extends U8aFixed {
constructor (registry: Registry, value?: AnyU8a) {
super(registry, value, 256);
}
}
export class Tally extends Option.with(Vec.with(Tuple.with([VoteOutcome, u128]))) { }
export class VoteData extends Struct {
constructor (registry: Registry, value: any) {
super(registry, {
initiator: 'AccountId',
stage: VoteStage,
vote_type: VoteType,
tally_type: TallyType,
is_commit_reveal: bool,
}, value);
}
get initiator (): AccountId {
return this.get('initiator') as AccountId;
}
get stage (): VoteStage {
return this.get('stage') as VoteStage;
}
get vote_type (): VoteType {
return this.get('vote_type') as VoteType;
}
get tally_type (): TallyType {
return this.get('tally_type') as TallyType;
}
get is_commit_reveal (): bool {
return this.get('is_commit_reveal') as bool;
}
}
export class Commitments extends Vec.with(Tuple.with(['AccountId', VoteOutcome])) { }
export class Reveals extends Vec.with(Tuple.with(['AccountId', Vec.with(VoteOutcome)])) { }
export class VoteRecord extends Struct {
constructor (registry: Registry, value: any) {
super(registry, {
id: u64,
commitments: Commitments,
reveals: Reveals,
data: VoteData,
outcomes: Vec.with(VoteOutcome),
}, value);
}
get id (): u64 {
return this.get('id') as u64;
}
get commitments (): Commitments {
return this.get('commits') as Commitments;
}
get reveals (): Reveals {
return this.get('reveals') as Reveals;
}
get data (): VoteData {
return this.get('data') as VoteData;
}
get outcomes (): Vec<VoteOutcome> {
return this.get('outcomes') as Vec<VoteOutcome>;
}
}
export const VotingTypes = {
PreVoting,
Commit,
Voting,
Completed,
VoteStage,
Binary,
MultiOption,
VoteType,
OnePerson,
OneCoin,
TallyType,
VoteOutcome,
Tally,
VoteData,
VoteRecord,
'voting::VoteType': VoteType,
'voting::TallyType': TallyType,
};

View File

@ -4,7 +4,8 @@
// Generated via (in api) `yarn chain:info --ws wss://mainnet1.edgewa.re`
import { EdgewareTypes } from 'edgeware-node-types/dist';
// import { EdgewareTypes } from 'edgeware-node-types/dist';
import { EdgewareTypes } from './edgeware-node-types';
export default {
chain: 'Edgeware',

View File

@ -6,10 +6,10 @@
"license": "Apache-2",
"dependencies": {
"@babel/runtime": "^7.8.4",
"@polkadot/keyring": "^2.4.0-beta.0",
"@polkadot/react-identicon": "^0.50.1",
"@polkadot/react-qr": "^0.50.1",
"@polkadot/util-crypto": "^2.4.0-beta.0",
"@polkadot/keyring": "^2.5.1",
"@polkadot/react-identicon": "^0.52.0-beta.2",
"@polkadot/react-qr": "^0.52.0-beta.2",
"@polkadot/util-crypto": "^2.5.1",
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react-is": "^16.12.0",

View File

@ -5,10 +5,10 @@
"author": "Jaco Greeff <jacogr@gmail.com>",
"license": "Apache-2",
"dependencies": {
"@polkadot/api": "^1.3.0-beta.8",
"@polkadot/api": "^1.4.0-beta.30",
"@polkadot/extension-ui": "^0.22.0-beta.4",
"@polkadot/keyring": "^2.4.0-beta.0",
"@polkadot/ui-keyring": "^0.50.1"
"@polkadot/keyring": "^2.5.1",
"@polkadot/ui-keyring": "^0.52.0-beta.2"
},
"devDependencies": {
"@babel/runtime": "^7.8.4",

View File

@ -9,7 +9,7 @@ import { u8aToHex, hexToU8a } from '@polkadot/util';
import { TypeRegistry } from '@polkadot/types';
export default class RequestBytesSign implements RequestSign {
inner: SignerPayloadJSON | SignerPayloadRaw;
public readonly inner: SignerPayloadJSON | SignerPayloadRaw;
constructor (inner: SignerPayloadRaw) {
this.inner = inner;
@ -18,6 +18,9 @@ export default class RequestBytesSign implements RequestSign {
sign (_registry: TypeRegistry, pair: KeyringPair): { signature: string } {
const inner = this.inner as SignerPayloadRaw;
const signedBytes = pair.sign(hexToU8a(inner.data));
return { signature: u8aToHex(signedBytes) };
return {
signature: u8aToHex(signedBytes)
};
}
}

View File

@ -8,7 +8,7 @@ import { RequestSign } from './types';
import { SignerPayloadJSON, SignerPayloadRaw } from '@polkadot/types/types';
export default class RequestExtrinsicSign implements RequestSign {
inner: SignerPayloadJSON | SignerPayloadRaw;
public readonly inner: SignerPayloadJSON | SignerPayloadRaw;
constructor (inner: SignerPayloadJSON) {
this.inner = inner;
@ -17,6 +17,7 @@ export default class RequestExtrinsicSign implements RequestSign {
sign (registry: TypeRegistry, pair: KeyringPair): { signature: string } {
const inner = this.inner as SignerPayloadJSON;
const extrinsic = createType(registry, 'ExtrinsicPayload', this.inner, { version: inner.version });
return extrinsic.sign(pair);
}
}

View File

@ -29,10 +29,10 @@ function transformAccounts (accounts: SubjectInfo): AccountJson[] {
}
export default class Extension {
private state: State;
readonly #state: State;
constructor (state: State) {
this.state = state;
this.#state = state;
}
private accountsCreateExternal ({ address, genesisHash, name }: RequestAccountCreateExternal): boolean {
@ -83,7 +83,7 @@ export default class Extension {
}
private authorizeApprove ({ id }: RequestAuthorizeApprove): boolean {
const queued = this.state.getAuthRequest(id);
const queued = this.#state.getAuthRequest(id);
assert(queued, 'Unable to find request');
@ -95,7 +95,7 @@ export default class Extension {
}
private authorizeReject ({ id }: RequestAuthorizeReject): boolean {
const queued = this.state.getAuthRequest(id);
const queued = this.#state.getAuthRequest(id);
assert(queued, 'Unable to find request');
@ -109,7 +109,7 @@ export default class Extension {
// FIXME This looks very much like what we have in accounts
private authorizeSubscribe (id: string, port: chrome.runtime.Port): boolean {
const cb = createSubscription<'pri(authorize.subscribe)'>(id, port);
const subscription = this.state.authSubject.subscribe((requests: AuthorizeRequest[]): void =>
const subscription = this.#state.authSubject.subscribe((requests: AuthorizeRequest[]): void =>
cb(requests)
);
@ -148,7 +148,7 @@ export default class Extension {
}
private signingApprovePassword ({ id, password }: RequestSigningApprovePassword): boolean {
const queued = this.state.getSignRequest(id);
const queued = this.#state.getSignRequest(id);
assert(queued, 'Unable to find request');
@ -174,7 +174,7 @@ export default class Extension {
}
private signingApproveSignature ({ id, signature }: RequestSigningApproveSignature): boolean {
const queued = this.state.getSignRequest(id);
const queued = this.#state.getSignRequest(id);
assert(queued, 'Unable to find request');
@ -186,7 +186,7 @@ export default class Extension {
}
private signingCancel ({ id }: RequestSigningCancel): boolean {
const queued = this.state.getSignRequest(id);
const queued = this.#state.getSignRequest(id);
assert(queued, 'Unable to find request');
@ -200,7 +200,7 @@ export default class Extension {
// FIXME This looks very much like what we have in authorization
private signingSubscribe (id: string, port: chrome.runtime.Port): boolean {
const cb = createSubscription<'pri(signing.subscribe)'>(id, port);
const subscription = this.state.signSubject.subscribe((requests: SigningRequest[]): void =>
const subscription = this.#state.signSubject.subscribe((requests: SigningRequest[]): void =>
cb(requests)
);

View File

@ -36,18 +36,29 @@ interface SignRequest {
let idCounter = 0;
const WINDOW_OPTS = {
// This is not allowed on FF, only on Chrome - disable completely
// focused: true,
height: 621,
left: 150,
top: 150,
type: 'popup',
url: extension.extension.getURL('index.html'),
width: 480
};
function getId (): string {
return `${Date.now()}.${++idCounter}`;
}
export default class State {
private _authUrls: AuthUrls = {};
readonly #authUrls: AuthUrls = {};
private _authRequests: Record<string, AuthRequest> = {};
readonly #authRequests: Record<string, AuthRequest> = {};
private _signRequests: Record<string, SignRequest> = {};
readonly #signRequests: Record<string, SignRequest> = {};
private _windows: number[] = [];
#windows: number[] = [];
public readonly authSubject: BehaviorSubject<AuthorizeRequest[]> = new BehaviorSubject([] as AuthorizeRequest[]);
@ -62,45 +73,36 @@ export default class State {
}
public get numAuthRequests (): number {
return Object.keys(this._authRequests).length;
return Object.keys(this.#authRequests).length;
}
public get numSignRequests (): number {
return Object.keys(this._signRequests).length;
return Object.keys(this.#signRequests).length;
}
public get allAuthRequests (): AuthorizeRequest[] {
return Object
.values(this._authRequests)
.values(this.#authRequests)
.map(({ id, request, url }): AuthorizeRequest => ({ id, request, url }));
}
public get allSignRequests (): SigningRequest[] {
return Object
.values(this._signRequests)
.values(this.#signRequests)
.map(({ account, id, request, url }): SigningRequest => ({ account, id, request, url }));
}
private popupClose (): void {
this._windows.forEach((id: number): void =>
this.#windows.forEach((id: number): void =>
extension.windows.remove(id)
);
this._windows = [];
this.#windows = [];
}
private popupOpen (): void {
extension.windows.create({
// This is not allowed on FF, only on Chrome - disable completely
// focused: true,
height: 621,
left: 150,
top: 150,
type: 'popup',
url: extension.extension.getURL('index.html'),
width: 480
}, (window?: chrome.windows.Window): void => {
extension.windows.create({ ...WINDOW_OPTS }, (window?: chrome.windows.Window): void => {
if (window) {
this._windows.push(window.id);
this.#windows.push(window.id);
}
});
}
@ -108,9 +110,9 @@ export default class State {
private authComplete = (id: string, fn: Function): (result: boolean | Error) => void => {
return (result: boolean | Error): void => {
const isAllowed = result === true;
const { idStr, request: { origin }, url } = this._authRequests[id];
const { idStr, request: { origin }, url } = this.#authRequests[id];
this._authUrls[this.stripUrl(url)] = {
this.#authUrls[this.stripUrl(url)] = {
count: 0,
id: idStr,
isAllowed,
@ -118,7 +120,7 @@ export default class State {
url
};
delete this._authRequests[id];
delete this.#authRequests[id];
this.updateIconAuth(true);
fn(result);
@ -127,7 +129,7 @@ export default class State {
private signComplete = (id: string, fn: Function): (result: ResponseSigning | Error) => void => {
return (result: ResponseSigning | Error): void => {
delete this._signRequests[id];
delete this.#signRequests[id];
this.updateIconSign(true);
fn(result);
@ -171,8 +173,8 @@ export default class State {
public async authorizeUrl (url: string, request: RequestAuthorizeTab): Promise<boolean> {
const idStr = this.stripUrl(url);
if (this._authUrls[idStr]) {
assert(this._authUrls[idStr].isAllowed, `The source ${url} is not allowed to interact with this extension`);
if (this.#authUrls[idStr]) {
assert(this.#authUrls[idStr].isAllowed, `The source ${url} is not allowed to interact with this extension`);
return true;
}
@ -180,7 +182,7 @@ export default class State {
return new Promise((resolve, reject): void => {
const id = getId();
this._authRequests[id] = {
this.#authRequests[id] = {
id,
idStr,
request,
@ -195,7 +197,7 @@ export default class State {
}
public ensureUrlAuthorized (url: string): boolean {
const entry = this._authUrls[this.stripUrl(url)];
const entry = this.#authUrls[this.stripUrl(url)];
assert(entry, `The source ${url} has not been enabled yet`);
assert(entry.isAllowed, `The source ${url} is not allowed to interact with this extension`);
@ -204,18 +206,18 @@ export default class State {
}
public getAuthRequest (id: string): AuthRequest {
return this._authRequests[id];
return this.#authRequests[id];
}
public getSignRequest (id: string): SignRequest {
return this._signRequests[id];
return this.#signRequests[id];
}
public sign (url: string, request: RequestSign, account: AccountJson): Promise<ResponseSigning> {
const id = getId();
return new Promise((resolve, reject): void => {
this._signRequests[id] = {
this.#signRequests[id] = {
account,
id,
request,

View File

@ -24,14 +24,14 @@ function transformAccounts (accounts: SubjectInfo): InjectedAccount[] {
}
export default class Tabs {
private state: State;
readonly #state: State;
constructor (state: State) {
this.state = state;
this.#state = state;
}
private authorize (url: string, request: RequestAuthorizeTab): Promise<boolean> {
return this.state.authorizeUrl(url, request);
return this.#state.authorizeUrl(url, request);
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
@ -63,18 +63,18 @@ export default class Tabs {
private bytesSign (url: string, request: SignerPayloadRaw): Promise<ResponseSigning> {
const address = request.address;
const pair = this.getSigningPair(address);
return this.state.sign(url, new RequestBytesSign(request), { address, ...pair.meta });
return this.#state.sign(url, new RequestBytesSign(request), { address, ...pair.meta });
}
private extrinsicSign (url: string, request: SignerPayloadJSON): Promise<ResponseSigning> {
const address = request.address;
const pair = this.getSigningPair(address);
return this.state.sign(url, new RequestExtrinsicSign(request), { address, ...pair.meta });
return this.#state.sign(url, new RequestExtrinsicSign(request), { address, ...pair.meta });
}
public async handle<TMessageType extends MessageTypes> (id: string, type: TMessageType, request: RequestTypes[TMessageType], url: string, port: chrome.runtime.Port): Promise<ResponseTypes[keyof ResponseTypes]> {
if (type !== 'pub(authorize.tab)') {
this.state.ensureUrlAuthorized(url);
this.#state.ensureUrlAuthorized(url);
}
switch (type) {

View File

@ -214,6 +214,7 @@ export type MessageTypesWithSubscriptions = keyof SubscriptionMessageTypes;
export type MessageTypesWithNoSubscriptions = Exclude<MessageTypes, keyof SubscriptionMessageTypes>
export interface RequestSign {
inner: SignerPayloadJSON | SignerPayloadRaw;
sign(registry: TypeRegistry, pair: KeyringPair): { signature: string };
readonly inner: SignerPayloadJSON | SignerPayloadRaw;
sign (registry: TypeRegistry, pair: KeyringPair): { signature: string };
}

672
yarn.lock

File diff suppressed because it is too large Load Diff