# kickstart-for-time-pwa ## Project setup ``` npm install ``` ### Compiles and hot-reloads for development ``` npm run serve ``` ### Compiles and minifies for production ``` npm run build ``` ### Lints and fixes files ``` npm run lint ``` ### Clear data & restart Clear cache for localhost, then go to http://localhost:8080/start (because it'll regenerate if you start on the `/account` page). ### Test key contents See [this page](openssl_signing_console.rst) ### Register new user on test server New users require registration. This can be done with a claim payload like this by an existing user: ``` const vcClaim = { "@context": "https://schema.org", "@type": "RegisterAction", agent: { identifier: identity0.did }, object: SERVICE_ID, participant: { identifier: newIdentity.did }, }; ``` On the test server, User #0 has rights to register others, so you can start playing one of two ways: - Import the keys for that test User `did:ethr:0x000Ee5654b9742f6Fe18ea970e32b97ee2247B51` by importing this seed phrase: `seminar accuse mystery assist delay law thing deal image undo guard initial shallow wrestle list fragile borrow velvet tomorrow awake explain test offer control` - Register someone else under User #0 on the `/account` page: * Edit the `src/views/AccountViewView.vue` file and uncomment the lines referring to "testServerRegisterUser". * Visit the `/account` page, open the [Vue Devtools browser extension](https://devtools.vuejs.org/), select a component, then type this into the console: `$vm.ctx.testRegisterUser()` ### Create keys with alternate tools See [this page](openssl_signing_console.rst) ### Customize configuration See [Configuration Reference](https://cli.vuejs.org/config/). ## Dependencies See https://tea.xyz | Project | Version | | ---------- | --------- | | nodejs.org | ^16.0.0 | | npmjs.com | ^8.0.0 | ## Other ``` // reference material from https://github.com/trentlarson/endorser-mobile/blob/8dc8e0353e0cc80ffa7ed89ded15c8b0da92726b/src/utility/idUtility.ts#L83 // Import an existing ID export const importAndStoreIdentifier = async (mnemonic: string, mnemonicPassword: string, toLowercase: boolean, previousIdentifiers: Array) => { // just to get rid of variability that might cause an error mnemonic = mnemonic.trim().toLowerCase() /** // an approach I pieced together // requires: yarn add elliptic // ... plus: // const EC = require('elliptic').ec // const secp256k1 = new EC('secp256k1') // const keyHex: string = bip39.mnemonicToEntropy(mnemonic) // returns a KeyPair from the elliptic.ec library const keyPair = secp256k1.keyFromPrivate(keyHex, 'hex') // this code is from did-provider-eth createIdentifier const privateHex = keyPair.getPrivate('hex') const publicHex = keyPair.getPublic('hex') const address = didJwt.toEthereumAddress(publicHex) **/ /** // from https://github.com/uport-project/veramo/discussions/346#discussioncomment-302234 // ... which almost works but the didJwt.toEthereumAddress is wrong // requires: yarn add bip32 // ... plus: import * as bip32 from 'bip32' // const seed: Buffer = await bip39.mnemonicToSeed(mnemonic) const root = bip32.fromSeed(seed) const node = root.derivePath(UPORT_ROOT_DERIVATION_PATH) const privateHex = node.privateKey.toString("hex") const publicHex = node.publicKey.toString("hex") const address = didJwt.toEthereumAddress('0x' + publicHex) **/ /** // from https://github.com/uport-project/veramo/discussions/346#discussioncomment-302234 // requires: yarn add @ethersproject/hdnode // ... plus: import { HDNode } from '@ethersproject/hdnode' **/ const hdnode: HDNode = HDNode.fromMnemonic(mnemonic) const rootNode: HDNode = hdnode.derivePath(UPORT_ROOT_DERIVATION_PATH) const privateHex = rootNode.privateKey.substring(2) // original starts with '0x' const publicHex = rootNode.publicKey.substring(2) // original starts with '0x' let address = rootNode.address const prevIds = previousIdentifiers || []; if (toLowercase) { const foundEqual = R.find( (id) => utility.rawAddressOfDid(id.did) === address, prevIds ) if (foundEqual) { // They're trying to create a lowercase version of one that exists in normal case. // (We really should notify the user.) appStore.dispatch(appSlice.actions.addLog({log: true, msg: "Will create a normal-case version of the DID since a regular version exists."})) } else { address = address.toLowerCase() } } else { // They're not trying to convert to lowercase. const foundLower = R.find((id) => utility.rawAddressOfDid(id.did) === address.toLowerCase(), prevIds ) if (foundLower) { // They're trying to create a normal case version of one that exists in lowercase. // (We really should notify the user.) appStore.dispatch(appSlice.actions.addLog({log: true, msg: "Will create a lowercase version of the DID since a lowercase version exists."})) address = address.toLowerCase() } } appStore.dispatch(appSlice.actions.addLog({log: false, msg: "... derived keys and address..."})) const newId = newIdentifier(address, publicHex, privateHex, UPORT_ROOT_DERIVATION_PATH) appStore.dispatch(appSlice.actions.addLog({log: false, msg: "... created new ID..."})) // awaiting because otherwise the UI may not see that a mnemonic was created const savedId = await storeIdentifier(newId, mnemonic, mnemonicPassword) appStore.dispatch(appSlice.actions.addLog({log: false, msg: "... stored new ID..."})) return savedId } // Create a totally new ID export const createAndStoreIdentifier = async (mnemonicPassword) => { // This doesn't give us the entropy/seed. //const id = await agent.didManagerCreate() const entropy = crypto.randomBytes(32) const mnemonic = bip39.entropyToMnemonic(entropy) appStore.dispatch(appSlice.actions.addLog({log: false, msg: "... generated mnemonic..."})) return importAndStoreIdentifier(mnemonic, mnemonicPassword, false, []) } ```