mirror of
https://github.com/logos-messaging/js-rln.git
synced 2026-01-07 16:13:07 +00:00
feat: improve cred managment (#95)
This commit is contained in:
parent
77ba0a6d5d
commit
ac12f6800a
86
src/rln.ts
86
src/rln.ts
@ -19,7 +19,7 @@ import type {
|
|||||||
DecryptedCredentials,
|
DecryptedCredentials,
|
||||||
EncryptedCredentials,
|
EncryptedCredentials,
|
||||||
} from "./keystore/index.js";
|
} from "./keystore/index.js";
|
||||||
import { Password } from "./keystore/types.js";
|
import { KeystoreEntity, 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";
|
||||||
@ -196,6 +196,10 @@ type RegisterMembershipOptions =
|
|||||||
| { signature: string }
|
| { signature: string }
|
||||||
| { identity: IdentityCredential };
|
| { identity: IdentityCredential };
|
||||||
|
|
||||||
|
type WakuRLNEncoderOptions = WakuEncoderOptions & {
|
||||||
|
credentials: EncryptedCredentials | DecryptedCredentials;
|
||||||
|
};
|
||||||
|
|
||||||
export class RLNInstance {
|
export class RLNInstance {
|
||||||
private started = false;
|
private started = false;
|
||||||
private starting = false;
|
private starting = false;
|
||||||
@ -227,10 +231,18 @@ export class RLNInstance {
|
|||||||
this.starting = true;
|
this.starting = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const { credentials, keystore } =
|
||||||
|
await RLNInstance.decryptCredentialsIfNeeded(options.credentials);
|
||||||
const { signer, registryAddress } = await this.determineStartOptions(
|
const { signer, registryAddress } = await this.determineStartOptions(
|
||||||
options
|
options,
|
||||||
|
credentials
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (keystore) {
|
||||||
|
this.keystore = keystore;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._credentials = credentials;
|
||||||
this._signer = signer!;
|
this._signer = signer!;
|
||||||
this._contract = await RLNContract.init(this, {
|
this._contract = await RLNContract.init(this, {
|
||||||
registryAddress: registryAddress!,
|
registryAddress: registryAddress!,
|
||||||
@ -243,12 +255,9 @@ export class RLNInstance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async determineStartOptions(
|
private async determineStartOptions(
|
||||||
options: StartRLNOptions
|
options: StartRLNOptions,
|
||||||
|
credentials: KeystoreEntity | undefined
|
||||||
): Promise<StartRLNOptions> {
|
): Promise<StartRLNOptions> {
|
||||||
const credentials = await this.decryptCredentialsIfNeeded(
|
|
||||||
options.credentials
|
|
||||||
);
|
|
||||||
|
|
||||||
let chainId = credentials?.membership.chainId;
|
let chainId = credentials?.membership.chainId;
|
||||||
const registryAddress =
|
const registryAddress =
|
||||||
credentials?.membership.address ||
|
credentials?.membership.address ||
|
||||||
@ -271,35 +280,35 @@ export class RLNInstance {
|
|||||||
return {
|
return {
|
||||||
signer,
|
signer,
|
||||||
registryAddress,
|
registryAddress,
|
||||||
credentials: options.credentials,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private async decryptCredentialsIfNeeded(
|
private static async decryptCredentialsIfNeeded(
|
||||||
credentials?: EncryptedCredentials | DecryptedCredentials
|
credentials?: EncryptedCredentials | DecryptedCredentials
|
||||||
): Promise<undefined | DecryptedCredentials> {
|
): Promise<{ credentials?: DecryptedCredentials; keystore?: Keystore }> {
|
||||||
if (!credentials) {
|
if (!credentials) {
|
||||||
return;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("identity" in credentials) {
|
if ("identity" in credentials) {
|
||||||
this._credentials = credentials;
|
return { credentials };
|
||||||
return credentials;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const keystore = Keystore.fromString(credentials.keystore);
|
const keystore = Keystore.fromString(credentials.keystore);
|
||||||
|
|
||||||
if (!keystore) {
|
if (!keystore) {
|
||||||
throw Error("Failed to start RLN: cannot read Keystore provided.");
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
this.keystore = keystore;
|
const decryptedCredentials = await keystore.readCredential(
|
||||||
this._credentials = await keystore.readCredential(
|
|
||||||
credentials.id,
|
credentials.id,
|
||||||
credentials.password
|
credentials.password
|
||||||
);
|
);
|
||||||
|
|
||||||
return this._credentials;
|
return {
|
||||||
|
keystore,
|
||||||
|
credentials: decryptedCredentials,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public async registerMembership(
|
public async registerMembership(
|
||||||
@ -331,21 +340,56 @@ export class RLNInstance {
|
|||||||
this._credentials = await this.keystore?.readCredential(id, password);
|
this._credentials = await this.keystore?.readCredential(id, password);
|
||||||
}
|
}
|
||||||
|
|
||||||
public createEncoder(options: WakuEncoderOptions): RLNEncoder {
|
public async createEncoder(
|
||||||
if (!this._credentials) {
|
options: WakuRLNEncoderOptions
|
||||||
|
): Promise<RLNEncoder> {
|
||||||
|
const { credentials: decryptedCredentials } =
|
||||||
|
await RLNInstance.decryptCredentialsIfNeeded(options.credentials);
|
||||||
|
const credentials = decryptedCredentials || this._credentials;
|
||||||
|
|
||||||
|
if (!credentials) {
|
||||||
throw Error(
|
throw Error(
|
||||||
"Failed to create Encoder: missing RLN credentials. Use createRLNEncoder directly."
|
"Failed to create Encoder: missing RLN credentials. Use createRLNEncoder directly."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await this.verifyCredentialsAgainstContract(credentials);
|
||||||
|
|
||||||
return createRLNEncoder({
|
return createRLNEncoder({
|
||||||
encoder: createEncoder(options),
|
encoder: createEncoder(options),
|
||||||
rlnInstance: this,
|
rlnInstance: this,
|
||||||
index: this._credentials.membership.treeIndex,
|
index: credentials.membership.treeIndex,
|
||||||
credential: this._credentials.identity,
|
credential: credentials.identity,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async verifyCredentialsAgainstContract(
|
||||||
|
credentials: KeystoreEntity
|
||||||
|
): Promise<void> {
|
||||||
|
if (!this._contract) {
|
||||||
|
throw Error(
|
||||||
|
"Failed to verify chain coordinates: no contract initialized."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const registryAddress = credentials.membership.address;
|
||||||
|
const currentRegistryAddress = this._contract.registry.address;
|
||||||
|
if (registryAddress !== currentRegistryAddress) {
|
||||||
|
throw Error(
|
||||||
|
`Failed to verify chain coordinates: credentials contract address=${registryAddress} is not equal to registryContract address=${currentRegistryAddress}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const chainId = credentials.membership.chainId;
|
||||||
|
const network = await this._contract.registry.getNetwork();
|
||||||
|
const currentChainId = network.chainId;
|
||||||
|
if (chainId !== currentChainId) {
|
||||||
|
throw Error(
|
||||||
|
`Failed to verify chain coordinates: credentials chainID=${chainId} is not equal to registryContract chainID=${currentChainId}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public createDecoder(
|
public createDecoder(
|
||||||
contentTopic: ContentTopic
|
contentTopic: ContentTopic
|
||||||
): RLNDecoder<IDecodedMessage> {
|
): RLNDecoder<IDecodedMessage> {
|
||||||
|
|||||||
@ -93,6 +93,13 @@ export class RLNContract {
|
|||||||
this.deployBlock = await this.storageContract.deployedBlockNumber();
|
this.deployBlock = await this.storageContract.deployedBlockNumber();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get registry(): ethers.Contract {
|
||||||
|
if (!this.registryContract) {
|
||||||
|
throw Error("Registry contract was not initialized");
|
||||||
|
}
|
||||||
|
return this.registryContract as ethers.Contract;
|
||||||
|
}
|
||||||
|
|
||||||
public get contract(): ethers.Contract {
|
public get contract(): ethers.Contract {
|
||||||
if (!this.storageContract) {
|
if (!this.storageContract) {
|
||||||
throw Error("Storage contract was not initialized");
|
throw Error("Storage contract was not initialized");
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user