mirror of
https://github.com/logos-messaging/js-rln.git
synced 2026-01-05 23:23:12 +00:00
provide ability to use Keystore as a seed for credentials
This commit is contained in:
parent
c8f50ea916
commit
a545530e29
@ -1,5 +1,5 @@
|
|||||||
import { Keystore } from "./keystore.js";
|
import { Keystore } from "./keystore.js";
|
||||||
import type { KeystoreEntity } from "./types.js";
|
import type { DecryptedCredentials, EncryptedCredentials } from "./types.js";
|
||||||
|
|
||||||
export { Keystore };
|
export { Keystore };
|
||||||
export type { KeystoreEntity };
|
export type { EncryptedCredentials, DecryptedCredentials };
|
||||||
|
|||||||
@ -76,7 +76,9 @@ export class Keystore {
|
|||||||
return new Keystore(options);
|
return new Keystore(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static fromString(str: string): Keystore | null {
|
// should be valid JSON string that contains Keystore file
|
||||||
|
// https://github.com/waku-org/nwaku/blob/f05528d4be3d3c876a8b07f9bb7dfaae8aa8ec6e/waku/waku_keystore/keyfile.nim#L376
|
||||||
|
public static fromString(str: string): undefined | Keystore {
|
||||||
try {
|
try {
|
||||||
const obj = JSON.parse(str);
|
const obj = JSON.parse(str);
|
||||||
|
|
||||||
@ -87,7 +89,7 @@ export class Keystore {
|
|||||||
return new Keystore(obj);
|
return new Keystore(obj);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Cannot create Keystore from string:", err);
|
console.error("Cannot create Keystore from string:", err);
|
||||||
return null;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,11 +135,11 @@ export class Keystore {
|
|||||||
public async readCredential(
|
public async readCredential(
|
||||||
membershipHash: MembershipHash,
|
membershipHash: MembershipHash,
|
||||||
password: Password
|
password: Password
|
||||||
): Promise<null | KeystoreEntity> {
|
): Promise<undefined | KeystoreEntity> {
|
||||||
const nwakuCredential = this.data.credentials[membershipHash];
|
const nwakuCredential = this.data.credentials[membershipHash];
|
||||||
|
|
||||||
if (!nwakuCredential) {
|
if (!nwakuCredential) {
|
||||||
return null;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const eipKeystore = Keystore.fromCredentialToEip(nwakuCredential);
|
const eipKeystore = Keystore.fromCredentialToEip(nwakuCredential);
|
||||||
@ -230,7 +232,9 @@ export class Keystore {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static fromBytesToIdentity(bytes: Uint8Array): null | KeystoreEntity {
|
private static fromBytesToIdentity(
|
||||||
|
bytes: Uint8Array
|
||||||
|
): undefined | KeystoreEntity {
|
||||||
try {
|
try {
|
||||||
const str = bytesToUtf8(bytes);
|
const str = bytesToUtf8(bytes);
|
||||||
const obj = JSON.parse(str);
|
const obj = JSON.parse(str);
|
||||||
@ -264,7 +268,7 @@ export class Keystore {
|
|||||||
};
|
};
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Cannot parse bytes to Nwaku Credentials:", err);
|
console.error("Cannot parse bytes to Nwaku Credentials:", err);
|
||||||
return null;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -17,3 +17,20 @@ export type KeystoreEntity = {
|
|||||||
identity: IdentityCredential;
|
identity: IdentityCredential;
|
||||||
membership: MembershipInfo;
|
membership: MembershipInfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type DecryptedCredentials = KeystoreEntity;
|
||||||
|
|
||||||
|
export type EncryptedCredentials = {
|
||||||
|
/**
|
||||||
|
* Valid JSON string that contains Keystore
|
||||||
|
*/
|
||||||
|
keystore: string;
|
||||||
|
/**
|
||||||
|
* ID of credentials from provided Keystore to use
|
||||||
|
*/
|
||||||
|
id: string;
|
||||||
|
/**
|
||||||
|
* Password to decrypt credentials provided
|
||||||
|
*/
|
||||||
|
password: Password;
|
||||||
|
};
|
||||||
|
|||||||
67
src/rln.ts
67
src/rln.ts
@ -14,7 +14,12 @@ import type { RLNDecoder, RLNEncoder } from "./codec.js";
|
|||||||
import { createRLNDecoder, createRLNEncoder } from "./codec.js";
|
import { createRLNDecoder, createRLNEncoder } from "./codec.js";
|
||||||
import { SEPOLIA_CONTRACT } from "./constants.js";
|
import { SEPOLIA_CONTRACT } from "./constants.js";
|
||||||
import { dateToEpoch, epochIntToBytes } from "./epoch.js";
|
import { dateToEpoch, epochIntToBytes } from "./epoch.js";
|
||||||
import type { KeystoreEntity } from "./keystore/index.js";
|
import { Keystore } from "./keystore/index.js";
|
||||||
|
import type {
|
||||||
|
DecryptedCredentials,
|
||||||
|
EncryptedCredentials,
|
||||||
|
} from "./keystore/index.js";
|
||||||
|
import { Password } from "./keystore/types.js";
|
||||||
import { extractMetaMaskSigner } from "./metamask.js";
|
import { extractMetaMaskSigner } from "./metamask.js";
|
||||||
import verificationKey from "./resources/verification_key.js";
|
import verificationKey from "./resources/verification_key.js";
|
||||||
import { RLNContract } from "./rln_contract.js";
|
import { RLNContract } from "./rln_contract.js";
|
||||||
@ -184,7 +189,7 @@ type StartRLNOptions = {
|
|||||||
* Credentials to use for generating proofs and connecting to the contract and network.
|
* Credentials to use for generating proofs and connecting to the contract and network.
|
||||||
* If provided used for validating the network chainId and connecting to registry contract.
|
* If provided used for validating the network chainId and connecting to registry contract.
|
||||||
*/
|
*/
|
||||||
credentials?: KeystoreEntity;
|
credentials?: EncryptedCredentials | DecryptedCredentials;
|
||||||
};
|
};
|
||||||
|
|
||||||
type RegisterMembershipOptions =
|
type RegisterMembershipOptions =
|
||||||
@ -197,7 +202,9 @@ export class RLNInstance {
|
|||||||
|
|
||||||
private _contract: undefined | RLNContract;
|
private _contract: undefined | RLNContract;
|
||||||
private _signer: undefined | ethers.Signer;
|
private _signer: undefined | ethers.Signer;
|
||||||
private _credentials: undefined | KeystoreEntity;
|
|
||||||
|
private _keystore: undefined | Keystore;
|
||||||
|
private _credentials: undefined | DecryptedCredentials;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private zkRLN: number,
|
private zkRLN: number,
|
||||||
@ -212,6 +219,10 @@ export class RLNInstance {
|
|||||||
return this._signer;
|
return this._signer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get keystore(): undefined | Keystore {
|
||||||
|
return this._keystore;
|
||||||
|
}
|
||||||
|
|
||||||
public async start(options: StartRLNOptions = {}): Promise<void> {
|
public async start(options: StartRLNOptions = {}): Promise<void> {
|
||||||
if (this.started || this.starting) {
|
if (this.started || this.starting) {
|
||||||
return;
|
return;
|
||||||
@ -220,11 +231,11 @@ export class RLNInstance {
|
|||||||
this.starting = true;
|
this.starting = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { signer, credentials, registryAddress } =
|
const { signer, registryAddress } = await this.determineStartOptions(
|
||||||
await this.determineStartOptions(options);
|
options
|
||||||
|
);
|
||||||
|
|
||||||
this._signer = signer!;
|
this._signer = signer!;
|
||||||
this._credentials = credentials;
|
|
||||||
this._contract = await RLNContract.init(this, {
|
this._contract = await RLNContract.init(this, {
|
||||||
registryAddress: registryAddress!,
|
registryAddress: registryAddress!,
|
||||||
signer: signer!,
|
signer: signer!,
|
||||||
@ -238,9 +249,13 @@ export class RLNInstance {
|
|||||||
private async determineStartOptions(
|
private async determineStartOptions(
|
||||||
options: StartRLNOptions
|
options: StartRLNOptions
|
||||||
): Promise<StartRLNOptions> {
|
): Promise<StartRLNOptions> {
|
||||||
let chainId = options.credentials?.membership.chainId;
|
const credentials = await this.decryptCredentialsIfNeeded(
|
||||||
|
options.credentials
|
||||||
|
);
|
||||||
|
|
||||||
|
let chainId = credentials?.membership.chainId;
|
||||||
const registryAddress =
|
const registryAddress =
|
||||||
options.credentials?.membership.address ||
|
credentials?.membership.address ||
|
||||||
options.registryAddress ||
|
options.registryAddress ||
|
||||||
SEPOLIA_CONTRACT.address;
|
SEPOLIA_CONTRACT.address;
|
||||||
|
|
||||||
@ -264,6 +279,33 @@ export class RLNInstance {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async decryptCredentialsIfNeeded(
|
||||||
|
credentials?: EncryptedCredentials | DecryptedCredentials
|
||||||
|
): Promise<undefined | DecryptedCredentials> {
|
||||||
|
if (!credentials) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("identity" in credentials) {
|
||||||
|
this._credentials = credentials;
|
||||||
|
return credentials;
|
||||||
|
}
|
||||||
|
|
||||||
|
const keystore = Keystore.fromString(credentials.keystore);
|
||||||
|
|
||||||
|
if (!keystore) {
|
||||||
|
throw Error("Failed to start RLN: cannot read Keystore provided.");
|
||||||
|
}
|
||||||
|
|
||||||
|
this._keystore = keystore;
|
||||||
|
this._credentials = await keystore.readCredential(
|
||||||
|
credentials.id,
|
||||||
|
credentials.password
|
||||||
|
);
|
||||||
|
|
||||||
|
return this._credentials;
|
||||||
|
}
|
||||||
|
|
||||||
public async registerMembership(
|
public async registerMembership(
|
||||||
options: RegisterMembershipOptions
|
options: RegisterMembershipOptions
|
||||||
): Promise<undefined | KeystoreEntity> {
|
): Promise<undefined | KeystoreEntity> {
|
||||||
@ -284,6 +326,15 @@ export class RLNInstance {
|
|||||||
return this.contract.registerWithIdentity(identity);
|
return this.contract.registerWithIdentity(identity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes credentials in use by relying on provided Keystore earlier in rln.start
|
||||||
|
* @param id: string, hash of credentials to select from Keystore
|
||||||
|
* @param password: string or bytes to use to decrypt credentials from Keystore
|
||||||
|
*/
|
||||||
|
public async useCredentials(id: string, password: Password): Promise<void> {
|
||||||
|
this._credentials = await this.keystore?.readCredential(id, password);
|
||||||
|
}
|
||||||
|
|
||||||
public createEncoder(options: WakuEncoderOptions): RLNEncoder {
|
public createEncoder(options: WakuEncoderOptions): RLNEncoder {
|
||||||
if (!this._credentials) {
|
if (!this._credentials) {
|
||||||
throw Error(
|
throw Error(
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user