@krebitdao/reputation-passport
Version:
Krebit SDK for Verified Credentials
200 lines (199 loc) • 8.3 kB
JavaScript
import { ethers } from 'ethers';
import { SiweMessage } from 'siwe';
import localStore from 'store2';
import { schemas } from '../schemas/index.js';
import { utils } from '../utils/index.js';
import { config } from '../config/index.js';
export const AUTH_SIGNATURE_BODY = 'I am creating an account to use the private features of Krebit at {{timestamp}}';
const signAuthMessage = async (props) => {
const { wallet, resources = [], config } = props;
const now = new Date().toISOString();
const statement = AUTH_SIGNATURE_BODY.replace('{{timestamp}}', now);
const message = {
domain: config.publicUrl.replace('https://', '').replace('http://', ''),
address: await wallet.getAddress(),
statement,
uri: config.publicUrl,
version: '1',
chainId: Number(schemas.krbToken[config.network].domain.chainId)
};
if (resources && resources.length > 0) {
message['resources'] = resources;
}
const siweMessage = new SiweMessage(message);
const messageToSign = siweMessage.prepareMessage();
const signature = await wallet.signMessage(messageToSign);
console.log('signature: ', signature);
const recoveredAddress = ethers.utils.verifyMessage(messageToSign, signature);
const authSig = {
sig: signature,
derivedVia: 'web3.eth.personal.sign',
signedMessage: messageToSign,
address: recoveredAddress
};
localStore.set('lit-auth-signature', authSig);
return authSig;
};
export function canonicalAccessControlConditionFormatter(cond) {
// need to return in the exact format below:
/*
pub struct JsonAccessControlCondition {
pub contract_address: String,
pub chain: String,
pub standard_contract_type: String,
pub method: String,
pub parameters: Vec<String>,
pub return_value_test: JsonReturnValueTest,
}
*/
if (Array.isArray(cond)) {
return cond.map(c => canonicalAccessControlConditionFormatter(c));
}
if ('operator' in cond) {
return {
operator: cond.operator
};
}
if ('returnValueTest' in cond) {
return {
contractAddress: cond.contractAddress,
chain: cond.chain,
standardContractType: cond.standardContractType,
method: cond.method,
parameters: cond.parameters,
returnValueTest: {
comparator: cond.returnValueTest.comparator,
value: cond.returnValueTest.value
}
};
}
throw new Error(`invalid access control condition: ${cond}`);
}
export class Lit {
constructor() {
this.connect = async () => {
this.litSdk = this.currentConfig.litSdk;
this.litNodeClient = new this.litSdk.LitNodeClient();
await this.litNodeClient.connect();
};
this.getOwnsAddressCondition = (address) => {
return [
{
conditionType: 'evmBasic',
contractAddress: '',
standardContractType: '',
chain: this.currentConfig.network,
method: '',
parameters: [':userAddress'],
returnValueTest: {
comparator: '=',
value: address
}
}
];
};
this.getShareWithCondition = (address) => {
return [
{
operator: 'or'
},
{
conditionType: 'evmBasic',
contractAddress: '',
standardContractType: '',
chain: this.currentConfig.network,
method: '',
parameters: [':userAddress'],
returnValueTest: {
comparator: '=',
value: address
}
}
];
};
this.encrypt = async (message, accessControlConditions, wallet) => {
try {
if (!this.litNodeClient) {
await this.connect();
}
let authSig = localStore.get('lit-auth-signature');
if (!authSig || authSig === 'undefined') {
console.log('signing auth message because sig is not in local storage');
await signAuthMessage({
wallet,
config: this.currentConfig
});
authSig = localStore.get('lit-auth-signature');
}
const { encryptedString, symmetricKey } = await this.litSdk.encryptString(message);
const encryptedStringBase64 = await utils.base64.blobToBase64(encryptedString);
const conds = accessControlConditions.map(c => canonicalAccessControlConditionFormatter(c));
const encryptedSymmetricKey = await this.litNodeClient.saveEncryptionKey({
accessControlConditions: conds,
symmetricKey,
authSig,
chain: this.currentConfig.network,
permanent: false
});
return {
encryptedString: encryptedStringBase64,
encryptedSymmetricKey: this.litSdk.uint8arrayToString(encryptedSymmetricKey, 'base16'),
unifiedAccessControlConditions: accessControlConditions,
chain: this.currentConfig.network
};
}
catch (error) {
console.error('Encrypt error', error);
}
};
this.updateConditions = async (encryptedSymmetricKey, newAccessControlConditions, wallet, permanent = false) => {
if (!this.litNodeClient) {
await this.connect();
}
let authSig = localStore.get('lit-auth-signature');
if (!authSig || authSig === 'undefined') {
console.log('signing auth message because sig is not in local storage');
await signAuthMessage({
wallet,
config: this.currentConfig
});
authSig = localStore.get('lit-auth-signature');
}
const conds = newAccessControlConditions.map(c => canonicalAccessControlConditionFormatter(c));
const decodedKey = this.litSdk.uint8arrayFromString(encryptedSymmetricKey, 'base16');
const newEncryptedSymmetricKey = await this.litNodeClient.saveEncryptionKey({
accessControlConditions: conds,
encryptedSymmetricKey: decodedKey,
authSig,
chain: this.currentConfig.network,
permanent
});
return this.litSdk.uint8arrayToString(newEncryptedSymmetricKey, 'base16');
};
this.decrypt = async (encryptedString, encryptedSymmetricKey, accessControlConditions, wallet) => {
if (!this.litNodeClient) {
await this.connect();
}
let authSig = localStore.get('lit-auth-signature');
if (!authSig || authSig === 'undefined') {
console.log('signing auth message because sig is not in local storage');
await signAuthMessage({
wallet,
config: this.currentConfig
});
authSig = localStore.get('lit-auth-signature');
}
const conds = accessControlConditions.map(c => canonicalAccessControlConditionFormatter(c));
const decryptedSymmKey = await this.litNodeClient.getEncryptionKey({
accessControlConditions: conds,
toDecrypt: encryptedSymmetricKey,
authSig,
chain: this.currentConfig.network
});
const decryptedString = await this.litSdk.decryptString(new Blob([utils.base64.decodeb64(encryptedString)]), decryptedSymmKey);
return decryptedString;
};
const currentConfig = config.get();
this.currentConfig = currentConfig;
}
}