Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
- console debugs shall be removed again
  • Loading branch information
Karl committed Nov 25, 2024
1 parent 3538065 commit 471b117
Show file tree
Hide file tree
Showing 10 changed files with 170 additions and 106 deletions.
24 changes: 15 additions & 9 deletions packages/js-sdk/src/Dm3Sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export function getIdForAddress(address: string, addrEnsSubdomain: string) {

export interface Dm3SdkConfig {
mainnetProvider: ethers.providers.JsonRpcProvider;
storageApi: StorageAPI;
storageApi?: StorageAPI;
nonce: string;
defaultDeliveryService: string;
addressEnsSubdomain: string;
Expand Down Expand Up @@ -63,7 +63,7 @@ export class Dm3Sdk {
/**
* DM3 STORAGE
*/
private storageApi: StorageAPI;
private storageApi?: StorageAPI;

/**
* DM3 CONVERSATIONS
Expand All @@ -85,8 +85,8 @@ export class Dm3Sdk {
this.userEnsSubdomain = config.userEnsSubdomain;
this.resolverBackendUrl = config.resolverBackendUrl;
this.backendUrl = config.backendUrl;
this.storageApi = config.storageApi;
this._tld = config._tld;
this.storageApi = config.storageApi;
}
/**
* login can be used to login with a profile regardles the connector. Its also great for testing
Expand Down Expand Up @@ -132,6 +132,14 @@ export class Dm3Sdk {

await beConnector.login(profile);

this.storageApi = this.storageApi ?? new EncryptedCloudStorage(
beConnector,
account,
this.profileKeys,
).getCloudStorage();

console.log('this.storageApi', this.storageApi);

const conversations = new Conversations(
this.storageApi,
tld,
Expand All @@ -141,12 +149,6 @@ export class Dm3Sdk {
this.addressEnsSubdomain,
);

this.storageApi = new EncryptedCloudStorage(
beConnector,
account,
this.profileKeys,
).getCloudStorage();

return new Dm3(conversations, tld);
}

Expand All @@ -160,8 +162,12 @@ export class Dm3Sdk {
this.nonce,
this.defaultDeliveryService,
);

console.log('lc', lc, typeof lc.login);
const loginResult = await lc.login();

console.log('loginResult', loginResult);

const { profileKeys, profile, accountAddress } = loginResult as Success;
return await this.login({ profileKeys, profile, accountAddress });
}
Expand Down
27 changes: 13 additions & 14 deletions packages/js-sdk/src/connectors/LuksoConnector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,50 +3,49 @@ import { ethers } from 'ethers';
import ERC725Abi from './ERC725Abi.json';
import { SmartAccountConnector } from './SmartAccountConnector';

declare global {
interface Window {
lukso?: any;
}
}
export class LuksoConnector {
//TODO move to class tailored to lukso
public static async _instance(
lukso: ethers.providers.ExternalProvider,
nonce: string,
defaultDeliveryService: string,
): Promise<SmartAccountConnector> {
//The universal profile extension can be accessed via the window.lukso object
// if (!window.lukso) {
// throw 'Universal Profile extension not found';
// }
const provider = new ethers.providers.Web3Provider(lukso);
//Connect with the UP extension
console.log('done0');
await provider.send('eth_requestAccounts', []);
console.log('done1');

//The signer that will be used to sign transactions
const upController = await provider.getSigner();
const upController = provider.getSigner();
console.log('done2');
//When used with UP the signer.getAddress() will return the UP address. Even though the signer uses the controller address to sign transactions
//TODO clearify with Lukso-Team if that is always the case
const upAddress = upController._address;
const upAddress = await upController.getAddress();
console.log(upController);
console.log('done3 ', upAddress);
console.log('done3 .', upAddress);

//Instance of the UP contract

//Instance of the UP contract
const upContract = new ethers.Contract(
upAddress,
ERC725Abi,
upController,
);
console.log('done4', upContract);
const keyStore = new Lukso.LuksoKeyStore(upContract);
console.log('done5', keyStore);


return new SmartAccountConnector(
const sc = new SmartAccountConnector(
keyStore,
upController,
nonce,
defaultDeliveryService,
);

console.log('done6', sc);

return sc;
}
}
39 changes: 30 additions & 9 deletions packages/js-sdk/src/connectors/SmartAccountConnector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,30 +142,36 @@ export class SmartAccountConnector {

public async login(): Promise<LoginResult> {
const keyStore = await this.keyStoreService.readDm3KeyStore();
console.log('keyStore', keyStore);
//Smart account has never used dm3 before
if (Object.keys(keyStore).length === 0) {
console.log('signUp');
return await this.signUp();
}
//Smart account has used Dm before. We have to check if the controller has published its public key yet
const { encryptionKeyPair, signature } =
await this.createEncryptionKeys();
console.debug('Starting login process for existing smart account.');
const { encryptionKeyPair, signature } = await this.createEncryptionKeys();
console.debug('Encryption keys created:', encryptionKeyPair, 'Signature:', signature);

//Recover the address of the controller from the signature
const upControllerAddress =
await this.recoverAddressFromEncryptionKeySignature(signature);
const upControllerAddress = await this.recoverAddressFromEncryptionKeySignature(signature);
console.debug('Recovered UP controller address from signature:', upControllerAddress);

//Check if the controller has already a ketStore entry
//Check if the controller has already a keyStore entry
const encryptedControllerKeyStore = keyStore[upControllerAddress];
console.debug('Retrieved encrypted controller key store:', encryptedControllerKeyStore);

//If the controller already has a keyStore, we can decrypt the profileKeys using its encryptionKeys
//If not we've to start the keyExchange process
if (
!encryptedControllerKeyStore ||
!encryptedControllerKeyStore.encryptedProfileKeys
) {
//The signer connected to the UP has not used dm3 before, it has to publish its public key so another device can share the profile keys
console.debug('No existing key store or encrypted profile keys found. Initiating key exchange process.');
//The signer connected to the UP has not used dm3 before, it has to publish its public key so another device can share the profile keys
return await this.addNewSigner(keyStore);
}
console.debug('Existing key store and encrypted profile keys found. Proceeding with sign-in for existing signer.');
//The signer connected to the UP has already used dm3 before, hence it knows the profile
return await this.signInExistingSigner(
encryptionKeyPair,
Expand Down Expand Up @@ -222,15 +228,22 @@ export class SmartAccountConnector {

//Returns Keys to encrypt the actual profile at UP
private async createEncryptionKeys() {
//If the user has created its encryption keys before, we can reuse them. That way we don't have to ask the user to sign again
// If the user has created its encryption keys before, we can reuse them. That way we don't have to ask the user to sign again
console.debug('Checking for cached encryption keys.');
if (this.cachedEncryptionKeys) {
console.debug('Cached encryption keys found, returning them.');
return this.cachedEncryptionKeys;
}

console.debug('No cached encryption keys found, proceeding to create new ones.');
const upAddress = await this.keyStoreService.getAccountAddress();
console.debug('Retrieved account address:', upAddress);

const statement =
`Connect the DM3 MESSENGER with your wallet. ` +
`Keys for secure communication are derived from this signature.` +
`(There is no paid transaction initiated. The signature is used off-chain only.)`;
console.debug('Prepared statement for SiweMessage:', statement);

const message = new SiweMessage({
domain: 'dm3.chat',
Expand All @@ -240,23 +253,31 @@ export class SmartAccountConnector {
version: '1',
chainId: 42,
nonce: this.nonce,
//Date is a mandatory property otherwise it'll be DAte.now(). We need it to be constant to create teh encryption keys deterministically
// Date is a mandatory property otherwise it'll be Date.now(). We need it to be constant to create the encryption keys deterministically
issuedAt: new Date(978307200000).toISOString(),
resources: ['https://dm3.network'],
});
console.debug('Created SiweMessage:', message);
console.debug('this.controller:', this.controller);
console.debug('message.prepareMessage():', message.prepareMessage());

const signature = await this.controller.signMessage(
message.prepareMessage(),
);
console.debug('Generated signature:', signature);

const storageKey = await createStorageKey(signature);
console.debug('Created storage key:', storageKey);

const keys = await _createProfileKeys(storageKey, this.nonce);
console.debug('Generated profile keys:', keys);

//Keep the encryptionKeyPair for later use
// Keep the encryptionKeyPair for later use
this.cachedEncryptionKeys = {
encryptionKeyPair: keys.encryptionKeyPair,
signature: signature,
};
console.debug('Cached encryption keys for future use.');

return {
encryptionKeyPair: keys.encryptionKeyPair,
Expand Down
8 changes: 8 additions & 0 deletions packages/js-sdk/src/message/Messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@ export class Messages {
this._messages = [];
}

get meta() {
return {
sender: this.senderAccount,
receiver: this.receiver,
messages: this._messages,
}
}

public get list() {
return renderMessage(this._messages);
}
Expand Down
11 changes: 9 additions & 2 deletions packages/js-sdk/src/storage/EncryptedCloudStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,20 @@ export class EncryptedCloudStorage {
account: Account,
profileKeys: ProfileKeys,
) {
if(!account.ensName) {
throw new Error('Account must have an ENS name');
}

this.backendConnector = backendConnector;
this.account = account;
this.profileKeys = profileKeys;
}

private async encryptSync(data: string) {
const accountNonce = sha256(this.account!.ensName).slice(0, 26);
console.log('this.account', this.account);
console.log('this.account.ensName', this.account.ensName);

const accountNonce = sha256(this.account.ensName).slice(0, 26);
const encryptedPayload: EncryptedPayload = await _encrypt(
this.profileKeys?.encryptionKeyPair?.privateKey!,
data,
Expand Down Expand Up @@ -63,7 +70,7 @@ export class EncryptedCloudStorage {
}

public getCloudStorage() {
return getCloudStorage(this.backendConnector, this.account!.ensName, {
return getCloudStorage(this.backendConnector, this.account.ensName, {
encryptAsync: this.encryptAsync,
decryptAsync: this.decryptAsync,
encryptSync: this.encryptSync,
Expand Down
2 changes: 1 addition & 1 deletion packages/messenger-vue-demo/src/App.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup lang="ts">
import Chat from './components/Chat.vue'
import Chat from './components/Dm3Chat.vue'
</script>

<template>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
<template>
<vue-advanced-chat
{{ rooms }}
{{ messages }}
<!-- <vue-advanced-chat
:current-user-id="currentUserId"
:rooms="JSON.stringify(rooms)"
:messages="JSON.stringify(messages)"
:room-actions="JSON.stringify(roomActions)"
:messages-loaded="messagesLoaded"
:rooms-loaded="roomsLoaded"
/>
/> -->
<button @click="startTestConversation">Start test conversation</button>
isReady: {{ isReady }}
</template>

<script setup>
Expand All @@ -18,9 +22,11 @@ register()
const roomsLoaded = ref(false);
const messagesLoaded = ref(false);
const { rooms, messages, init } = useDm3Chat();
const { rooms, messages, init, startTestConversation, isReady } = useDm3Chat();
init();
onMounted(() => {
init();
})
const currentUserId = '1234'
// const rooms = [
Expand Down
Loading

0 comments on commit 471b117

Please sign in to comment.