From dde33e794966c557c05d6fd42bc62b522bfa1b8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s?= <105802444+kilted-andres@users.noreply.github.com> Date: Wed, 22 May 2024 17:42:39 +0200 Subject: [PATCH] fix: reuse code instead of duplicating it (#82) ## fixes KILTProtocol/ticket#3094 - Stop having duplicates. - Imports the types and functions necessary for set-up from the backend. - Corrects some comments. ## How to test: 1. Delete all your all environment variables and domain linkage credential 2. run `yarn environment` and follow the instructions until you have all constants defined. 3. run `yarn did-configuration` to make a new domain linkage credential 4. run `yarn start` 5. login on the browser. ## Checklist: - [x] I have verified that the code works - [x] I have verified that the code is easy to understand - [ ] If not, I have left a well-balanced amount of inline comments - [x] I have [left the code in a better state](https://deviq.com/principles/boy-scout-rule) - [x] I have documented the changes (where applicable) * Either PR or Ticket to update [the Docs](https://github.com/KILTprotocol/docs) * Link the PR/Ticket here --- .gitignore | 7 +- .../genesisEnvironmentVariables.ts | 41 +++--- .../genesisWellKnownDidConfig.ts | 16 ++- .../launchUtils/generateFullDid.ts | 22 ++- .../recycledUtils/postEnvironment.ts | 20 +++ .../recycledUtils/preEnvironment.ts | 32 +++++ {scripts => launchScripts}/updatePorts.ts | 0 .../wellKnownDIDConfiguration.ts | 2 +- package.json | 10 +- scripts/launchUtils/connection.ts | 24 ---- scripts/launchUtils/generateAccount.ts | 21 --- scripts/launchUtils/generateKeyPairs.ts | 33 ----- scripts/launchUtils/types.ts | 131 ------------------ 13 files changed, 111 insertions(+), 248 deletions(-) rename {scripts => launchScripts}/genesisEnvironmentVariables.ts (85%) rename {scripts => launchScripts}/genesisWellKnownDidConfig.ts (96%) rename {scripts => launchScripts}/launchUtils/generateFullDid.ts (81%) create mode 100644 launchScripts/launchUtils/recycledUtils/postEnvironment.ts create mode 100644 launchScripts/launchUtils/recycledUtils/preEnvironment.ts rename {scripts => launchScripts}/updatePorts.ts (100%) rename {scripts => launchScripts}/wellKnownDIDConfiguration.ts (99%) delete mode 100644 scripts/launchUtils/connection.ts delete mode 100644 scripts/launchUtils/generateAccount.ts delete mode 100644 scripts/launchUtils/generateKeyPairs.ts delete mode 100644 scripts/launchUtils/types.ts diff --git a/.gitignore b/.gitignore index 950c68fc..706af5c5 100644 --- a/.gitignore +++ b/.gitignore @@ -29,12 +29,15 @@ build dist .well-known/ -# misc -.DS_Store +# environment constants .env .env.local .env.development.local .env.test.local .env.production.local +*.env + +# misc +.DS_Store .vscode tmp/ diff --git a/scripts/genesisEnvironmentVariables.ts b/launchScripts/genesisEnvironmentVariables.ts similarity index 85% rename from scripts/genesisEnvironmentVariables.ts rename to launchScripts/genesisEnvironmentVariables.ts index ff8addf2..56e7928c 100644 --- a/scripts/genesisEnvironmentVariables.ts +++ b/launchScripts/genesisEnvironmentVariables.ts @@ -1,9 +1,11 @@ -import dotenv from 'dotenv' import * as Kilt from '@kiltprotocol/sdk-js' import { mnemonicGenerate } from '@polkadot/util-crypto' +import dotenv from 'dotenv' -import { generateKeyPairs } from './launchUtils/generateKeyPairs' -import { generateAccount } from './launchUtils/generateAccount' +import { + generateAccount, + generateKeyPairs +} from './launchUtils/recycledUtils/preEnvironment' import { generateFullDid } from './launchUtils/generateFullDid' // try to read the variables from the .env-file: @@ -126,11 +128,11 @@ async function main() { case 9: imploreTrustedAttesters() break - // ask you to choose a Ctype Hash + // ask you to specify trusted credential issuers case 10: imploreRequestedProperties() break - // ask you to choose a Ctype Hash + // ask you to choose which credential-properties the user will have to disclose to login // if (step = -1): default: console.log( @@ -208,14 +210,14 @@ async function spawnDid() { 'This could take some minutes.\n', 'Make sure you have enough funds! \n\n' ) - // Load attester account - const attesterAccount = generateAccount(DAPP_ACCOUNT_MNEMONIC as string) + // Load payer account + const payerAccount = generateAccount(DAPP_ACCOUNT_MNEMONIC as string) // the DID can be generated by a different mnemonic than from the account. This is also the preferred option. // You could also pass a specific mnemonic, but here we generate a random mnemonic. // for custom, replace here with a string of 12 BIP-39 words const didMnemonic = mnemonicGenerate() // the next function requires connect() - const fullDid = await generateFullDid(attesterAccount, didMnemonic) + const fullDid = await generateFullDid(payerAccount, didMnemonic) console.log( "\n Please, save the mnemonic and URI of your dApp's DID to the .env-file to continue!\n", @@ -263,25 +265,28 @@ function imploreJwtSecretKey() { function imploreCtypeHash() { console.log( - 'Please provide the CType Hash(es) inside the .env file using this constant name:.\n', - 'Your dApp will only accept credentials of this given Claim Type(s).', - `CTYPE_HASH={CType IDs your dApp consider valid}\n`, - `If you wish to use the default Email Credential settings, please add the following line to your .env file:\n`, - `CTYPE_HASH=0x3291bb126e33b4862d421bfaa1d2f272e6cdfc4f96658988fbcffea8914bd9ac\n` + `Please specify with types of credentials your dApp should consider valid.`, + `For this, please, provide the CType Hash(es) inside the .env file using the constant name 'CTYPE_HASH'. \n`, + 'Your dApp will only accept credentials of the given Claim Type(s).\n\n', + + `If you wish to accept Email Credentials, as the ones issued by SocialKYC.io, please add the following line to your .env file:\n`, + `CTYPE_HASH=0x3291bb126e33b4862d421bfaa1d2f272e6cdfc4f96658988fbcffea8914bd9ac\n\n`, + + `If you rather work with other CTypes, we recommend checking out the registry under https://ctypehub.galaniprojects.de/.` ) } function imploreTrustedAttesters() { console.log( - 'Please provide a list for your Trusted Attesters inside the .env file using this constant name: \n', - `TRUSTED_ATTESTERS={lists of trusted attesters}\n`, - `If you wish to use the default Email Credential settings, please add the following line to your .env file:\n`, + `Please provide a list your dApp's Trusted Attesters (Credential Issuers) inside the .env file using the constant name 'TRUSTED_ATTESTERS'. \n`, + 'Only credentials attested on chain by one the specified DIDs will be accepted by your dApp.\n\n', + `If you wish to accept Credentials issued by the peregrine (test) version of SocialKYC.io, please add the following line to your .env file:\n`, `TRUSTED_ATTESTERS=did:kilt:4pehddkhEanexVTTzWAtrrfo2R7xPnePpuiJLC7shQU894aY\n` ) } function imploreRequestedProperties() { console.log( - 'Please provide a list of Required Properties inside the .env file using this constant name: \n', - `REQUIRED_PROPERTIES={lists of Properties users should be Required to disclose}\n`, + `Please provide a list of Required Properties inside the .env file using this constant name 'REQUIRED_PROPERTIES' \n`, + `The users will only be Required to disclose the listed Properties during credential presentation (≙login).\n\n`, `If you wish to use the default Email Credential settings, please add the following line to your .env file:\n`, `REQUIRED_PROPERTIES=Email\n` ) diff --git a/scripts/genesisWellKnownDidConfig.ts b/launchScripts/genesisWellKnownDidConfig.ts similarity index 96% rename from scripts/genesisWellKnownDidConfig.ts rename to launchScripts/genesisWellKnownDidConfig.ts index e6e983e5..ba847c5e 100644 --- a/scripts/genesisWellKnownDidConfig.ts +++ b/launchScripts/genesisWellKnownDidConfig.ts @@ -5,18 +5,22 @@ import path from 'path' import * as Kilt from '@kiltprotocol/sdk-js' import dotenv from 'dotenv' -import { validateOurKeys } from '../backend/src/config' -import { fetchDidDocument } from '../backend/src/utils/fetchDidDocument' +import { + VerifiableDomainLinkagePresentation, + generateAccount, + generateKeyPairs +} from './launchUtils/recycledUtils/preEnvironment' -import { generateAccount } from './launchUtils/generateAccount' -import { generateKeyPairs } from './launchUtils/generateKeyPairs' -import { VerifiableDomainLinkagePresentation } from './launchUtils/types' +import { + fetchDidDocument, + validateOurKeys +} from './launchUtils/recycledUtils/postEnvironment' import { createCredential, createPresentation, - selfAttestCredential, getDomainLinkagePresentation, + selfAttestCredential, verifyDidConfigPresentation } from './wellKnownDIDConfiguration' diff --git a/scripts/launchUtils/generateFullDid.ts b/launchScripts/launchUtils/generateFullDid.ts similarity index 81% rename from scripts/launchUtils/generateFullDid.ts rename to launchScripts/launchUtils/generateFullDid.ts index 798623d0..2398c10c 100644 --- a/scripts/launchUtils/generateFullDid.ts +++ b/launchScripts/launchUtils/generateFullDid.ts @@ -1,21 +1,30 @@ import * as Kilt from '@kiltprotocol/sdk-js' -import { getApi } from './connection' - -import { generateKeyPairs } from './generateKeyPairs' +import { generateKeyPairs } from './recycledUtils/preEnvironment' +/** + * Generates a on-chain DID from a mnemonic. + * + * You need to be connected to a KILT Endpoint beforehand, to know where to register your DID at. + * For that, use 'Kilt.connect()'. + * + * You could use the BOTLabs Endpoints: + * For the KILT Production Chain "Spiritnet": wss://spiritnet.kilt.io/ + * For the KILT Test Chain "Peregrine": wss://peregrine.kilt.io/ + * + * @param mnemonic + * @returns + */ export async function generateFullDid( submitterAccount: Kilt.KiltKeyringPair, mnemonic: string ): Promise { - await getApi() - const didMnemonic = mnemonic const { authentication, keyAgreement, assertionMethod, capabilityDelegation - } = generateKeyPairs(didMnemonic) + } = generateKeyPairs(mnemonic) // Before submitting the transaction, it is worth it to assure that the DID does not already exist. // If the DID already exist, the transaction will fail, but it will still costs the fee. Better to avoid this. @@ -73,6 +82,5 @@ export async function generateFullDid( throw new Error('Full DID was not successfully fetched.') } - Kilt.disconnect() return didDocument } diff --git a/launchScripts/launchUtils/recycledUtils/postEnvironment.ts b/launchScripts/launchUtils/recycledUtils/postEnvironment.ts new file mode 100644 index 00000000..3a745525 --- /dev/null +++ b/launchScripts/launchUtils/recycledUtils/postEnvironment.ts @@ -0,0 +1,20 @@ +/** + * Most of the utilities needed during the set-up that are also needed by the backend. + * It is important that this utilities correlate so that the backend can use what was configured during set-up (launch). + * To avoid duplicated code and discrepancies, it is better to import from the backend the utilities needed for the set-up. + * That is what is done here on the 'recycledUtils' folder. + */ + +// +// Import and Export Functions: +// + +// This two functions from the Backend use the backend-config directly or indirectly. +// The config from the backend try to loads all the env-constants and throws if one is missing. +// That's why they are imported in a separated file. +// This file should only be loaded after all environment constants are defined; e.g. while generating the Domain-Linkage-Credential, but not the Environment Variables. + +import { fetchDidDocument } from '../../../backend/src/utils/fetchDidDocument' +import { validateOurKeys } from '../../../backend/src/config' + +export { validateOurKeys, fetchDidDocument } diff --git a/launchScripts/launchUtils/recycledUtils/preEnvironment.ts b/launchScripts/launchUtils/recycledUtils/preEnvironment.ts new file mode 100644 index 00000000..39024530 --- /dev/null +++ b/launchScripts/launchUtils/recycledUtils/preEnvironment.ts @@ -0,0 +1,32 @@ +/** + * Most of the utilities needed during the set-up that are also needed by the backend. + * It is important that this utilities correlate so that the backend can use what was configured during set-up (launch). + * To avoid duplicated code and discrepancies, it is better to import from the backend the utilities needed for the set-up. + * That is what is done here on the 'recycledUtils' folder. + */ + +// +// Import and Export Types: +// + +import { + CredentialSubject, + DomainLinkageCredential, + VerifiableDomainLinkagePresentation +} from '../../../backend/src/utils/types' + +export type This = typeof globalThis +export { + CredentialSubject, + DomainLinkageCredential, + VerifiableDomainLinkagePresentation +} + +// +// Import and Export Functions: +// + +import { generateKeyPairs } from '../../../backend/src/utils/generateKeyPairs' +import { generateAccount } from '../../../backend/src/utils/generateAccount' + +export { generateAccount, generateKeyPairs } diff --git a/scripts/updatePorts.ts b/launchScripts/updatePorts.ts similarity index 100% rename from scripts/updatePorts.ts rename to launchScripts/updatePorts.ts diff --git a/scripts/wellKnownDIDConfiguration.ts b/launchScripts/wellKnownDIDConfiguration.ts similarity index 99% rename from scripts/wellKnownDIDConfiguration.ts rename to launchScripts/wellKnownDIDConfiguration.ts index 078f8c07..13a649f8 100644 --- a/scripts/wellKnownDIDConfiguration.ts +++ b/launchScripts/wellKnownDIDConfiguration.ts @@ -9,7 +9,7 @@ import { CredentialSubject, DomainLinkageCredential, VerifiableDomainLinkagePresentation -} from './launchUtils/types' +} from './launchUtils/recycledUtils/preEnvironment' // This constants are needed to create a credential and/or presentation. // They are standard, an so it's better to fetch them from the @kiltprotocol/vc-export package, to keep them up to date. diff --git a/package.json b/package.json index ce0ccadb..bcf7d903 100644 --- a/package.json +++ b/package.json @@ -15,23 +15,23 @@ "node": ">= v18.17.0" }, "scripts": { - "environment": "ts-node ./scripts/genesisEnvironmentVariables.ts", - "did-configuration": "ts-node ./scripts/genesisWellKnownDidConfig.ts", + "environment": "ts-node ./launchScripts/genesisEnvironmentVariables.ts", + "did-configuration": "ts-node ./launchScripts/genesisWellKnownDidConfig.ts", "build:frontend": "cd ./frontend && yarn build", "build:backend": "cd ./backend && yarn build", "build": "yarn build:frontend && yarn build:backend", - "start:frontend": "ts-node ./scripts/updatePorts.ts && cd ./frontend && yarn start", + "start:frontend": "ts-node ./launchScripts/updatePorts.ts && cd ./frontend && yarn start", "start:backend": "cd ./backend && yarn start", "start-prod:backend": "cd ./backend && yarn start-prod", "start": "concurrently 'yarn:start:*'", "lint": "concurrently 'yarn:lint:*'", "lint:frontend": "eslint --ext .js,.ts --config ./.eslintrc.json \"frontend/**/*.ts\"", "lint:backend": "eslint --ext .js,.ts --config ./.eslintrc.json \"backend/**/*.ts\"", - "lint:scripts": "eslint --ext .js,.ts --config ./.eslintrc.json \"scripts/**/*.ts\"", + "lint:scripts": "eslint --ext .js,.ts --config ./.eslintrc.json \"launchScripts/**/*.ts\"", "fix": "concurrently 'yarn:fix:*'", "fix:frontend": "eslint --ext .js,.ts --config ./.eslintrc.json --fix \"frontend/**/*.ts\"", "fix:backend": "eslint --ext .js,.ts --config ./.eslintrc.json --fix \"backend/**/*.ts\"", - "fix:scripts": "eslint --ext .js,.ts --config ./.eslintrc.json --fix \"scripts/**/*.ts\"" + "fix:scripts": "eslint --ext .js,.ts --config ./.eslintrc.json --fix \"launchScripts/**/*.ts\"" }, "devDependencies": { "@types/node": "^20.9.1", diff --git a/scripts/launchUtils/connection.ts b/scripts/launchUtils/connection.ts deleted file mode 100644 index 3fe51e16..00000000 --- a/scripts/launchUtils/connection.ts +++ /dev/null @@ -1,24 +0,0 @@ -import * as Kilt from '@kiltprotocol/sdk-js' - -/** - * Makes sure you only connect once to the API of the Blockchain. If you are connected, return it. - * If you are not connected yet, connect through the Web-Socket Address saved on the '.env' file. - * - * @returns active ApiPromise - */ -export async function getApi() { - // If the API is already set up, return it - if (Kilt.ConfigService.isSet('api')) { - return Kilt.ConfigService.get('api') - } - - // If it is not, connect to it using the Web-Socket Address from the environment variable: - if (!process.env.WSS_ADDRESS) { - throw new Error( - 'please, define a value for WSS_ADDRESS on .env-file to use this function' - ) - } - // internally Kilt.connect() calls cryptoWaitReady() - await Kilt.connect(process.env.WSS_ADDRESS) - return Kilt.ConfigService.get('api') -} diff --git a/scripts/launchUtils/generateAccount.ts b/scripts/launchUtils/generateAccount.ts deleted file mode 100644 index aaa52180..00000000 --- a/scripts/launchUtils/generateAccount.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { mnemonicToMiniSecret } from '@polkadot/util-crypto' -import * as Kilt from '@kiltprotocol/sdk-js' - -/** - * Generates a KiltKeyringPair from a mnemonic. - * - * The WASM needs to be loaded before. - * For that, use either 'Kilt.init()', 'Kilt.connect()' or 'getApi()'. - * - * @param mnemonic - * @returns - */ -export function generateAccount(mnemonic: string): Kilt.KiltKeyringPair { - const mnemonicToU8A = mnemonicToMiniSecret(mnemonic) - const account = Kilt.Utils.Crypto.makeKeypairFromSeed( - mnemonicToU8A, - 'ed25519' - ) - - return account -} diff --git a/scripts/launchUtils/generateKeyPairs.ts b/scripts/launchUtils/generateKeyPairs.ts deleted file mode 100644 index d04f50d9..00000000 --- a/scripts/launchUtils/generateKeyPairs.ts +++ /dev/null @@ -1,33 +0,0 @@ -import * as Kilt from '@kiltprotocol/sdk-js' - -const signingKeyPairType = 'ed25519' - -export function generateKeyPairs(mnemonic: string) { - const authentication = Kilt.Utils.Crypto.makeKeypairFromUri( - mnemonic, - signingKeyPairType - ) - - const assertionMethod = Kilt.Utils.Crypto.makeKeypairFromUri( - mnemonic, - signingKeyPairType - ) - - const keyAgreement = Kilt.Utils.Crypto.makeEncryptionKeypairFromSeed( - Kilt.Utils.Crypto.mnemonicToMiniSecret(mnemonic) - ) - - // This key is not necessary for this project. - // for the sake of completeness, your dApp's DID also gets one - const capabilityDelegation = Kilt.Utils.Crypto.makeKeypairFromUri( - mnemonic, - signingKeyPairType - ) - - return { - authentication, - assertionMethod, - keyAgreement, - capabilityDelegation - } -} diff --git a/scripts/launchUtils/types.ts b/scripts/launchUtils/types.ts deleted file mode 100644 index 000a120e..00000000 --- a/scripts/launchUtils/types.ts +++ /dev/null @@ -1,131 +0,0 @@ -import { - IEncryptedMessage, - DidUri, - KiltAddress, - DidResourceUri, - Hash -} from '@kiltprotocol/types' -import { HexString } from '@polkadot/util/types' -import { - SelfSignedProof, - VerifiableCredential, - constants -} from '@kiltprotocol/vc-export' - -export type This = typeof globalThis - -export interface IEncryptedMessageV1 { - /** ID of the key agreement key of the receiver DID used to encrypt the message */ - receiverKeyId: DidResourceUri - - /** ID of the key agreement key of the sender DID used to encrypt the message */ - senderKeyId: DidResourceUri - - /** ciphertext as hexadecimal */ - ciphertext: string - - /** 24 bytes nonce as hexadecimal */ - nonce: string -} - -export interface PubSubSessionV1 { - /** Configure the callback the extension must use to send messages to the dApp. Overrides previous values. */ - listen: ( - callback: (message: IEncryptedMessageV1) => Promise - ) => Promise - - /** send the encrypted message to the extension */ - send: (message: IEncryptedMessageV1) => Promise - - /** close the session and stop receiving further messages */ - close: () => Promise - - /** ID of the key agreement key of the temporary DID the extension will use to encrypt the session messages */ - encryptionKeyId: string - - /** bytes as hexadecimal */ - encryptedChallenge: string - - /** 24 bytes nonce as hexadecimal */ - nonce: string -} - -export interface PubSubSessionV2 { - /** Configure the callback the extension must use to send messages to the dApp. Overrides previous values. */ - listen: ( - callback: (message: IEncryptedMessage) => Promise - ) => Promise - - /** send the encrypted message to the extension */ - send: (message: IEncryptedMessage) => Promise - - /** close the session and stop receiving further messages */ - close: () => Promise - - /** ID of the key agreement key of the temporary DID the extension will use to encrypt the session messages */ - encryptionKeyUri: DidResourceUri - - /** bytes as hexadecimal */ - encryptedChallenge: string - - /** 24 bytes nonce as hexadecimal */ - nonce: string -} - -export interface InjectedWindowProvider { - startSession: ( - /** human-readable name of the dApp */ - dAppName: string, - /** URI of the key agreement key of the dApp DID to be used to encrypt the session messages */ - dAppEncryptionKeyId: DidResourceUri, - /** 24 random bytes as hexadecimal */ - challenge: string - ) => Promise - /** human-readable name of the extension */ - name: string - /** version of the extension */ - version: string - specVersion: '1.0' | '3.0' - signWithDid: ( - plaintext: string - ) => Promise<{ signature: string; didKeyUri: DidResourceUri }> - signExtrinsicWithDid: ( - extrinsic: HexString, - signer: KiltAddress - ) => Promise<{ signed: HexString; didKeyUri: DidResourceUri }> - getSignedDidCreationExtrinsic: ( - submitter: KiltAddress - ) => Promise<{ signedExtrinsic: HexString }> -} - -export interface ApiWindow extends This { - kilt: Record< - string, - InjectedWindowProvider - > -} - -export interface CredentialSubject { - id: DidUri - origin: string - rootHash: Hash -} - -const context = [ - constants.DEFAULT_VERIFIABLECREDENTIAL_CONTEXT, - 'https://identity.foundation/.well-known/did-configuration/v1' -] -export interface DomainLinkageCredential - extends Omit< - VerifiableCredential, - '@context' | 'legitimationIds' | 'credentialSubject' | 'proof' - > { - '@context': typeof context - credentialSubject: CredentialSubject - proof: SelfSignedProof -} - -export interface VerifiableDomainLinkagePresentation { - '@context': string - linked_dids: [DomainLinkageCredential] -}