diff --git a/README.md b/README.md index d3e62418..1f22caed 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# kickstart-for-time-pwa +# TimeSafari.app - Crowd-Funder for Time - PWA ## Project setup @@ -13,6 +13,11 @@ npm install npm run serve ``` +### Lints and fixes files +``` +npm run lint +``` + ### Compiles and minifies for production If you are deploying in a subdirectory, add it to `publicPath` in vue.config.js, eg: `publicPath: "/app/time-tracker/",` @@ -21,41 +26,19 @@ If you are deploying in a subdirectory, add it to `publicPath` in vue.config.js, npm run build ``` -### Lints and fixes files -``` -npm run lint -``` - -## Tests +... then copy the contents of the `sw_scripts` folder to the `dist` folder - except additional_scripts.js. -### -For your own web-push tests, change the 'vapid' URL in App.vue, and install apps on the same domain. -### Test key contents - -See [this page](openssl_signing_console.rst) +## Tests ### 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 the 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` +- Import the keys for the test User `did:ethr:0x0000694B58C2cC69658993A90D3840C560f2F51F` by importing this seed phrase: + `rigid shrug mobile smart veteran half all pond toilet brave review universe ship congress found yard skate elite apology jar uniform subway slender luggage` (Other test users are found [here](https://github.com/trentlarson/endorser-ch/blob/master/test/util.js).) - Alternatively, register someone else under User #0 automatically: @@ -66,14 +49,35 @@ playing one of two ways: ### Create multiple identifiers -Go to /start and create or import a new one. Then switch identifiers on the bottom of the Your Identity page. +Under the "Your Identity" screen, click "Advanced", click "Switch Identity / No Identity", then "Add Another Identity...". ### Create keys with alternate tools -See [this page](openssl_signing_console.rst) +[This page](openssl_signing_console.rst) is a tool to create a JWT from a locally-generated keypair. + +### Web-push + +For your own web-push tests, change the 'vapid' URL in App.vue, and install apps on the same domain. + +### Manual walk-through + +- Clear the browser cache for localhost for a new user. + - See that it's using the test API. + - On each page, verify the messaging. + - On the home page, see the feed without names, and see a message prompting to generate an ID. + - On the discovery page, check that they can see projects, and set a search area to see projects nearby. +- As User #0 in another browser on the test API, add a give & a project. (See User #0 details above.) + - With the new user on the home page, see the feed that shows User #0 in network but without the name. +- As the new user on the contacts page, add User #0 as a contact. + - On the home page, see the feed that shows User #0 with a name. +- Generate an ID. + - On the home page, check that it now prompts them to get registered. + - On the account page, check that they see messages on limits. +- Register the ID from User #0. + - As the new user on the home page, check that they can now record a gift. + - On the contacts page, check that they cannot register someone else yet. +- Walk through the functions on each page. -### Customize Vue configuration -See [Configuration Reference](https://cli.vuejs.org/config/). ## Scenarios @@ -88,12 +92,13 @@ See [Configuration Reference](https://cli.vuejs.org/config/). - Click on the "Registration Unknown" button and register that person to be able to make claims as them. -### Clear data & restart +### Clear/Reset data & restart -* Clear cache for localhost, then go to http://localhost:8080/start - (because it'll generate a new one automatically if you start on the `/account` page). +* Clear cache for localhost. * Unregister service worker (in Chrome, go to `chrome://serviceworker-internals/`; in Firefox, go to `about:serviceworkers` or `about:debugging`). -* Clear notifications (in Chrome, go to `chrome://settings/content/notifications`; in Firefox, go to `about:preferences` and search). +* Clear notification permission (in Chrome, go to `chrome://settings/content/notifications`; in Firefox, go to `about:preferences` and search). + + ## Other @@ -103,110 +108,10 @@ See [Configuration Reference](https://cli.vuejs.org/config/). * Notifications can be type of `toast` (self-dismiss), `info`, `success`, `warning`, and `danger`. They are done via [notiwind](https://www.npmjs.com/package/notiwind) and set up in App.vue. -``` -// 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, []) -} -``` +* [Customize Vue configuration](https://cli.vuejs.org/config/). + -## Kudos +### Kudos Gifts make the world go 'round! diff --git a/openssl_signing_console.rst b/openssl_signing_console.rst index 28a272ab..8b7befdf 100644 --- a/openssl_signing_console.rst +++ b/openssl_signing_console.rst @@ -1,8 +1,11 @@ -Prerequisites: +JWT Creation & Verification -jq +To run this in a script, see ./openssl_signing_console.sh -You can create a JWT using a library or by encoding the header and payload base64Url and signing it with a secret using a ES256K algorithm. Here is an example of how you can create a JWT using the jq and openssl command line utilities: +Prerequisites: openssl, jq + +You can create a JWT using a library or by encoding the header and payload base64Url and signing it with a secret using +a ES256K algorithm. Here is an example of how you can create a JWT using the jq and openssl command line utilities: Here is an example of how you can use openssl to sign a JWT with the ES256K algorithm: @@ -15,20 +18,22 @@ openssl ec -in private.pem -pubout -out public.pem header='{"alg":"ES256K", "issuer": "", "typ":"JWT"}' - Next, create a payload object as a JSON object containing the claims you want to include in the JWT. For example schema.org : + Next, create a payload object as a JSON object containing the claims you want to include in the JWT. + For example schema.org : payload='{"@context": "http://schema.org", "@type": "PlanAction", "identifier": "did:ethr:0xb86913f83A867b5Ef04902419614A6FF67466c12", "name": "Test", "description": "Me"}' Encode the header and payload objects as base64Url strings. You can use the jq command line utility to do this: -header_b64=$(echo -n "$header" | jq -c -M . | tr -d '\n') -payload_b64=$(echo -n "$payload" | jq -c -M . | tr -d '\n') +header_b64=$(echo -n "$header" | jq -c -M . | tr -d '\n' | base64 | tr -d '=' | tr '+' '-' | tr '/' '_') +payload_b64=$(echo -n "$payload" | jq -c -M . | tr -d '\n' | base64 | tr -d '=' | tr '+' '-' | tr '/' '_') Concatenate the encoded header, payload, and a secret to create the signing input: signing_input="$header_b64.$payload_b64" - Create the signature by signing the signing input with a ES256K algorithm and your secret. You can use the openssl command line utility to do this: + Create the signature by signing the signing input with a ES256K algorithm and your secret. + You can use the openssl command line utility to do this: signature=$(echo -n "$signing_input" | openssl dgst -sha256 -sign private.pem) @@ -43,7 +48,7 @@ Authorization: Bearer $jwt To verify the JWT, you can use the openssl utility with the public key: -openssl dgst -sha256 -verify public.pem -signature <(echo -n "$signature") "$signing_input" - - This will verify the signature and output Verified OK if the signature is valid. If the signature is not valid, it will output an error. +echo -n "$signing_input" | openssl dgst -sha256 -verify public.pem -signature <(echo -n "$signature") + This will verify the signature and output "Verified OK" if the signature is valid. + If the signature is not valid, it will give an error response and output "Verification failure". diff --git a/openssl_signing_console.sh b/openssl_signing_console.sh index acdda689..b459dad0 100755 --- a/openssl_signing_console.sh +++ b/openssl_signing_console.sh @@ -1,25 +1,39 @@ #!/bin/bash +# Generate a JWT, with signature verified using OpenSSL +# +# Prerequisites: openssl, jq +# +# Usage: source ./openssl_signing_console.sh +# +# For a more complete explanation, see ./openssl_signing_console.rst + + +# Generate a key and extract the public part openssl ecparam -name secp256k1 -genkey -noout -out private.pem openssl ec -in private.pem -pubout -out public.pem +# Use test data header='{"alg":"ES256K", "issuer": "", "typ":"JWT"}' - payload='{"@context": "http://schema.org", "@type": "PlanAction", "identifier": "did:ethr:0xb86913f83A867b5Ef04902419614A6FF67466c12", "name": "Test", "description": "Me"}' -header_b64=$(echo -n "$header" | jq -c -M . | tr -d '\n') -payload_b64=$(echo -n "$payload" | jq -c -M . | tr -d '\n') +header_b64=$(echo -n "$header" | jq -c -M . | tr -d '\n' | base64 | tr -d '=' | tr '+' '-' | tr '/' '_') +payload_b64=$(echo -n "$payload" | jq -c -M . | tr -d '\n' | base64 | tr -d '=' | tr '+' '-' | tr '/' '_') signing_input="$header_b64.$payload_b64" -echo -n "$signing_input" | openssl dgst -sha256 -sign private.pem -out signature.bin +signature=$(echo -n "$signing_input" | openssl dgst -sha256 -sign private.pem | openssl base64 -e) -# Read binary signature from file and encode it to Base64 URL-Safe format -signature_b64=$(base64 -w 0 < signature.bin | tr -d '=' | tr '+' '-' | tr '/' '_') +echo -n "$signing_input" | openssl dgst -sha256 -verify public.pem -signature <(echo -n "$signature" | openssl base64 -d) -# Construct the JWT -jwt="$signing_input.$signature_b64" -openssl dgst -sha256 -verify public.pem -signature signature.bin -out verified.txt <(echo -n "$signing_input") + +# Read binary signature and encode it to Base64 URL-Safe format +signature_b64=$(echo -n "$signature" | base64 | tr -d '=' | tr '+' '-' | tr '/' '_') + +# Construct the JWT +jwt="$signing_input.$signature_b64" + +echo Resulting JWT: $jwt diff --git a/package-lock.json b/package-lock.json index 17450802..75f460e7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { - "name": "kickstart-for-time-pwa", - "version": "0.1.3", + "name": "crowd-funder-for-time-pwa", + "version": "0.1.4", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "kickstart-for-time-pwa", - "version": "0.1.3", + "name": "crowd-funder-for-time-pwa", + "version": "0.1.4", "dependencies": { "@ethersproject/hdnode": "^5.7.0", "@fortawesome/fontawesome-svg-core": "^6.4.2", diff --git a/package.json b/package.json index c96b1bfd..0abdcc40 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { - "name": "kickstart-for-time-pwa", - "version": "0.1.3", + "name": "crowd-funder-for-time-pwa", + "version": "0.1.4", "private": true, "scripts": { "serve": "vue-cli-service serve", @@ -72,13 +72,13 @@ "@vue/cli-service": "~5.0.8", "@vue/eslint-config-typescript": "^11.0.3", "autoprefixer": "^10.4.15", - "eslint": "^8.48.0", + "eslint": "^8.53.0", "eslint-config-prettier": "^9.0.0", "eslint-plugin-prettier": "^5.0.0", "eslint-plugin-vue": "^9.17.0", "leaflet": "^1.9.4", "postcss": "^8.4.29", - "prettier": "^3.0.3", + "prettier": "^3.1.0", "tailwindcss": "^3.3.3", "typescript": "~5.2.2" } diff --git a/project.task.yaml b/project.task.yaml index af1c65bf..9b565845 100644 --- a/project.task.yaml +++ b/project.task.yaml @@ -1,55 +1,45 @@ tasks: +- remove hard-coded anomalistlabs.com + +- don't show "Give" & "Offer" on project screen if they don't have an identifier +- allow some gives even if they aren't registered + - in endorser-push-server - mount folder for persistent sqlite DB outside of container +- extract private_key_hex in webpush.py - 40 notifications : - push, where we trigger a ServiceWorker(?) in the app to reach out and check for new data assignee:matthew -- 01 Replace Gifted/Give in ContactsView with GiftedDialog assignee:matthew - -- 01 fix the Discovery map display to not show on top of bottom icons (and any other UI tweaks on the map flow) assignee-group:ui -- .1 add instructions for map location selection - -- 01 Show pop-up or some message confirming that settings & contacts download has been initiated/finished - +- .2 change the "claims" verbiage in feeds (eg. safari-notifications.js) +- .5 allow to manage their notifications even without an identity - 01 Ensure each action sent to the server has a confirmation - eg registration (ie a toast something that dismisses after 5-10s) +- .3 fix the Project-location-selection map display to not show on top of bottom icons (and any other UI tweaks on the map flow) assignee-group:ui -- Home Feed & Quick Give screen : - - 01 save the feed-viewed status in settings storage ("afterQuery") - - 01 quick action - send action, maybe choose via canvas tool - - SEE: https://github.com/konvajs/vue-konva - -- 24 Move to Vite assignee:matthew - -- .5 switch so DiscoverView shows anywhere by default, and no number unless search is done (and maybe a better filter UI, including "mine" to consolidate with ProjectsView) -- .2 fit as many icons as possible on home & project view screens but only going halfway down the page assignee-group:ui - .5 Add infinite scroll to gifts on the home page - .5 bug - search for "Safari" does not find the project, but if already on the "Anywhere" tab it shows all - .2 figure out why endorser-mobile search doesn't find recently created PlanAction - .1 when creating a plan, select location and then make sure you can deselect on Android -- .5 add link to further project / people when a project pays ahead -- .5 add project ID to the URL of the project-view, to make a project publicly-accessible - .5 fix where user 0 sees no txns from user 1 on contacts page but sees them on list page -- .2 on ProjectViewView, show different messages for "to" and "from" sections if none exist -- .2 fix rate limit verbiage (with the new one-per-day allowance) assignee:trent -- .1 remove the logic to exclude beforeId in list of plans after server has commit 26b25af605e715600d4f12b6416ed9fd7142d164 +- .1 remove the logic to exclude beforeId in list of plans after server has commit 26b25af605e715600d4f12b6416ed9fd7142d164 assignee:trent - .2 in SeedBackupView, don't load the mnemonic and keep it in memory; only load it when they click "show" -- .1 Make give description text box into something that expands as they type -- .1 Make contact info specific to Time Safari - rather pointing at CommunityCred.org +- fix cert generation (since it didn't happen automatically for Nov 30) - Discuss whether the remaining tasks are worthwhile before MVP release. +- .1 Make give description text box into something that expands as they type? - 04 allow user to download claims, mine + ones I can see about me from others -- 02 allow user to create new DIDs from the same seed phrase (ie. increment derivation path) -- .5 on ProjectView page, show immediate feedback when a gift is given (on list?) -- and consider the same for Home & Contacts pages - .5 customize favicon assignee-group:ui - .2 Show a warning if both giver and recipient are the same (but still allow?) - 01 Would it look better to shrink the buttons on many pages so they don't expand to the width of the screen? assignee-group:ui - .5 Display a more appealing confirmation on the map when erasing the marker -- .5 make a VC details page +- .5 make a VC details page, or link to endorser.ch - .1 Add units or different icon to the coins (to distinguish $, BTC, hours, etc) -- .5 include the hash of the latest commit on help page next to version +- .5 include the hash of the latest commit on help page next to version (maybe Trent's git-hash branch) - .5 remove references to localStorage for projectId (now that it's pulling from the path) +- bug (that is hard to reproduce) - on the second 'give' recorded on prod it showed me as the agent +- make identicons for contacts into more-memorable faces (and maybe change project identicons, too) +- allow download of each VC (to show that they can actually own their data) - contacts v+ : - 01 Import all the non-sensitive data (ie. contacts & settings). @@ -58,14 +48,17 @@ tasks: - stats v1 : - 01 show numeric stats - - 04 show different graphic for projects vs people on world + - 04 show different graphic for projects vs people (gnome?) on world - 01 link to world for specific stats - .5 don't load another instance of a bush if it already exists - maybe - allow type annotations in World.js & landmarks.js (since we get this error - "Types are not supported by current JavaScript version") - 08 convert to cleaner implementation (maybe Drie -- https://github.com/janvorisek/drie) - Release Minimum Viable Product : + - generate new webpush.db entries, data/webpush.db private_key_hex & subscription_info & vapid_claims email + - .5 deploy endorser.ch server above Dec 1 (to get plan searches by names as well as descriptions) - 08 thorough testing for errors & edge cases + - 01 ensure ability to recover server remotely, and add redundant access - Turn off stats-world or ensure it's usable (eg. cannot zoom out too far and lose world, cannot screenshot). - Add disclaimers. - Switch default server to the public server. @@ -75,7 +68,9 @@ tasks: blocks: ref:https://raw.githubusercontent.com/trentlarson/lives-of-gifts/master/project.yaml#kickstarter%20for%20time - .5 show seed phrase in a QR code for transfer to another device +- .5 on DiscoverView, switch to a filter UI (eg. just from friend +- 24 Move to Vite - 32 accept images for projects - 32 accept images for contacts @@ -85,6 +80,10 @@ tasks: - for subtasks: fulfills (is it really the same?), feeds, contributes to, supplies, boosts, advances - for blocking: blocks, precedes, comes before, is sought by -- vs follows, seeks, builds on ("contributes to" isn't specific enough, "succeeds" has different, possibly confusing meaning) +- .5 add "back" button to all screens that aren't part of the bottom tray +- .5 fit as many icons as possible on home & project view screens but only going halfway down the page assignee-group:ui +- .5 Replace Gifted/Give in ContactsView with GiftedDialog + - Stats : - 01 point out user's location on the world - 01 present a credential selected from the stats @@ -101,11 +100,10 @@ tasks: - Multiple identities -- Peer DID - -- DIDComm - -- Write to or read from a different ledger (eg. private ACDC, attest.sh) +- Support KERI AIDs +- Support Peer DIDs +- Support messaging through DIDComm +- Write to or read from a different ledger (eg. private ACDC, EAS & attest.sh) - Do we want split first name & last name? @@ -113,6 +111,7 @@ tasks: - pull, w/ scheduled runs - 01 On nearby search, if user starts changing their box but cancels and goes back to the map it is zoomed far out. Fix to fit the box better. +- 16 From the home screen, make the quick action even easier. log: - videos for multiple identities https://youtu.be/p8L87AeD76w and for adding time to contacts https://youtu.be/7Yylczevp10 done:2023-03-29 diff --git a/sample.txt b/sample.txt deleted file mode 100644 index efe20be6..00000000 --- a/sample.txt +++ /dev/null @@ -1,177 +0,0 @@ - -> kickstart-for-time-pwa@0.1.0 build -> vue-cli-service build - -All browser targets in the browserslist configuration have supported ES module. -Therefore we don't build two separate bundles for differential loading. - - - WARNING Compiled with 5 warnings6:06:43 PM - -[eslint] -/home/matthew/projects/kick-starter-for-time-pwa/src/components/World/components/objects/landmarks.js - 98:11 warning Unexpected console statement no-console - 133:7 warning Unexpected console statement no-console - 144:5 warning Unexpected console statement no-console - -/home/matthew/projects/kick-starter-for-time-pwa/src/router/index.ts - 210:3 warning Unexpected console statement no-console - -/home/matthew/projects/kick-starter-for-time-pwa/src/views/AccountViewView.vue - 362:7 warning Unexpected console statement no-console - 375:7 warning Unexpected console statement no-console - 404:7 warning Unexpected console statement no-console - 516:7 warning Unexpected console statement no-console - 536:7 warning Unexpected console statement no-console - 630:5 warning Unexpected console statement no-console - 682:7 warning Unexpected console statement no-console - -/home/matthew/projects/kick-starter-for-time-pwa/src/views/ContactAmountsView.vue - 206:9 warning Unexpected console statement no-console - 233:9 warning Unexpected console statement no-console - -/home/matthew/projects/kick-starter-for-time-pwa/src/views/ContactGiftingView.vue - 244:9 warning Unexpected console statement no-console - 267:7 warning Unexpected console statement no-console - -/home/matthew/projects/kick-starter-for-time-pwa/src/views/ContactsView.vue - 340:9 warning Unexpected console statement no-console - 577:9 warning Unexpected console statement no-console - -/home/matthew/projects/kick-starter-for-time-pwa/src/views/DiscoverView.vue - 315:9 warning Unexpected console statement no-console - 343:7 warning Unexpected console statement no-console - 390:9 warning Unexpected console statement no-console - 423:7 warning Unexpected console statement no-console - 532:9 warning Unexpected console statement no-console - 575:7 warning Unexpected console statement no-console - -/home/matthew/projects/kick-starter-for-time-pwa/src/views/HomeView.vue - 349:9 warning Unexpected console statement no-console - 498:9 warning Unexpected console statement no-console - 521:7 warning Unexpected console statement no-console - -/home/matthew/projects/kick-starter-for-time-pwa/src/views/IdentitySwitcherView.vue - 142:7 warning Unexpected console statement no-console - -/home/matthew/projects/kick-starter-for-time-pwa/src/views/ImportAccountView.vue - 123:9 warning Unexpected console statement no-console - -/home/matthew/projects/kick-starter-for-time-pwa/src/views/ImportDerivedAccountView.vue - 159:7 warning Unexpected console statement no-console - -/home/matthew/projects/kick-starter-for-time-pwa/src/views/NewEditProjectView.vue - 183:9 warning Unexpected console statement no-console - 215:7 warning Unexpected console statement no-console - 297:13 warning Unexpected console statement no-console - 320:11 warning Unexpected console statement no-console - 345:7 warning Unexpected console statement no-console - -/home/matthew/projects/kick-starter-for-time-pwa/src/views/ProjectViewView.vue - 387:9 warning Unexpected console statement no-console - 421:7 warning Unexpected console statement no-console - 457:7 warning Unexpected console statement no-console - 552:9 warning Unexpected console statement no-console - 554:11 warning Unexpected console statement no-console - -/home/matthew/projects/kick-starter-for-time-pwa/src/views/ProjectsView.vue - 131:9 warning Unexpected console statement no-console - 144:7 warning Unexpected console statement no-console - 221:9 warning Unexpected console statement no-console - 237:7 warning Unexpected console statement no-console - -/home/matthew/projects/kick-starter-for-time-pwa/src/views/SeedBackupView.vue - 94:7 warning Unexpected console statement no-console - -✖ 44 problems (0 errors, 44 warnings) - - -You may use special comments to disable some warnings. -Use // eslint-disable-next-line to ignore the next line. -Use /* eslint-disable */ to ignore all warnings in a file. - warning - -/models/lupine_plant/textures/lambert2SG_baseColor.png is 3.75 MB, and won't be precached. Configure maximumFileSizeToCacheInBytes to change this limit. - - warning - -/models/lupine_plant/textures/lambert2SG_normal.png is 4.91 MB, and won't be precached. Configure maximumFileSizeToCacheInBytes to change this limit. - - warning - -asset size limit: The following asset(s) exceed the recommended size limit (244 KiB). -This can impact web performance. -Assets: - js/project.44f30c9f.js (318 KiB) - js/statistics.8a97010a.js (586 KiB) - js/chunk-vendors.a4845bfb.js (411 KiB) - js/705.f6a6ce2a.js (252 KiB) - img/textures/leafy-autumn-forest-floor.jpg (705 KiB) - models/lupine_plant/textures/lambert2SG_baseColor.png (3.58 MiB) - models/lupine_plant/textures/lambert2SG_normal.png (4.69 MiB) - - warning - -entrypoint size limit: The following entrypoint(s) combined asset size exceeds the recommended limit (244 KiB). This can impact web performance. -Entrypoints: - app (447 KiB) - js/chunk-vendors.a4845bfb.js - css/app.8f21529c.css - js/app.8833cebc.js - - - File Size Gzipped - - dist/js/statistics.8a97010a.js 585.72 KiB 148.80 KiB - dist/js/chunk-vendors.a4845bfb.js 411.44 KiB 137.82 KiB - dist/js/project.44f30c9f.js 317.61 KiB 78.67 KiB - dist/js/705.f6a6ce2a.js 251.66 KiB 87.12 KiB - dist/js/891.33615e4f.js 147.32 KiB 42.09 KiB - dist/js/153.e2c8e249.js 146.26 KiB 42.21 KiB - dist/js/820.13565d16.js 66.10 KiB 18.33 KiB - dist/js/contact-qr.e170ec33.js 54.85 KiB 15.63 KiB - dist/js/772.7b4c53a7.js 30.29 KiB 7.21 KiB - dist/js/361.898a4525.js 27.40 KiB 8.19 KiB - dist/js/account.77d86130.js 17.51 KiB 5.93 KiB - dist/js/app.8833cebc.js 17.31 KiB 5.84 KiB - dist/js/contacts.3fc90ff8.js 16.94 KiB 5.52 KiB - dist/js/discover.24106939.js 15.30 KiB 5.22 KiB - dist/js/536.3bb13201.js 15.23 KiB 4.84 KiB - dist/workbox-5b385ed2.js 14.11 KiB 4.93 KiB - dist/js/home.218b99dd.js 13.89 KiB 4.97 KiB - dist/js/help.50d3117b.js 12.49 KiB 4.38 KiB - dist/js/projects.417a6cb7.js 8.71 KiB 3.00 KiB - dist/js/contact-amounts.a32b0ccd.js 8.44 KiB 3.25 KiB - dist/js/229.120e09bf.js 7.99 KiB 2.72 KiB - dist/js/identity-switcher.c7937333.js 7.44 KiB 2.52 KiB - dist/js/new-edit-project.0552181b.js 7.36 KiB 3.11 KiB - dist/js/300.dcaeb2a3.js 6.56 KiB 3.24 KiB - dist/js/seed-backup.76a0f7b3.js 3.99 KiB 1.97 KiB - dist/js/import-derive.c688d4b8.js 3.81 KiB 1.82 KiB - dist/js/import-account.c3fa35fd.js 3.54 KiB 1.66 KiB - dist/js/new-edit-account.bb763be2.js 3.39 KiB 1.51 KiB - dist/js/431.5a6d64e0.js 3.38 KiB 2.56 KiB - dist/service-worker.js 3.37 KiB 1.38 KiB - dist/js/scan-contact.46be989a.js 2.79 KiB 1.18 KiB - dist/js/start.091a7740.js 2.70 KiB 1.30 KiB - dist/js/new-identifier.bb379420.js 2.12 KiB 1.18 KiB - dist/js/93.b873dbbf.js 2.08 KiB 1.61 KiB - dist/js/new-edit-commitment.9248d367.j 1.96 KiB 1.05 KiB - s - dist/js/confirm-contact.02004d1d.js 1.89 KiB 1.04 KiB - dist/js/858.ae4c08ec.js 0.97 KiB 0.78 KiB - dist/css/app.8f21529c.css 18.41 KiB 4.39 KiB - dist/css/discover.73ee9bd3.css 14.77 KiB 6.25 KiB - dist/css/new-edit-project.73ee9bd3.css 14.77 KiB 6.25 KiB - dist/css/contacts.abb5e493.css 0.40 KiB 0.23 KiB - dist/css/contact-amounts.5b26ccd4.css 0.31 KiB 0.20 KiB - dist/css/home.828bc66e.css 0.25 KiB 0.19 KiB - dist/css/project.828bc66e.css 0.25 KiB 0.19 KiB - dist/css/statistics.828bc66e.css 0.25 KiB 0.19 KiB - - Images and other types of assets omitted. - Build at: 2023-09-07T10:06:43.972Z - Hash: 2b39fcd4d0e78263 - Time: 32016ms - - DONE Build complete. The dist directory is ready to be deployed. - INFO Check out deployment instructions at https://cli.vuejs.org/guide/deployment.html - diff --git a/src/App.vue b/src/App.vue index 2486884b..585cdcc9 100644 --- a/src/App.vue +++ b/src/App.vue @@ -262,6 +262,28 @@ + + diff --git a/src/libs/endorserServer.ts b/src/libs/endorserServer.ts index 628d5bac..8db51eb8 100644 --- a/src/libs/endorserServer.ts +++ b/src/libs/endorserServer.ts @@ -59,17 +59,40 @@ export interface GiveServerRecord { unit: string; } +export interface OfferServerRecord { + amount: number; + amountGiven: number; + offeredByDid: string; + recipientDid: string; + requirementsMet: boolean; + unit: string; + validThrough: string; +} + export interface GiveVerifiableCredential { "@context"?: string; // optional when embedded, eg. in an Agree - "@type": string; + "@type": "GiveAction"; agent?: { identifier: string }; description?: string; - fulfills?: { "@type": string; identifier: string }; + fulfills?: { "@type": string; identifier?: string; lastClaimId?: string }; identifier?: string; object?: { amountOfThisGood: number; unitCode: string }; recipient?: { identifier: string }; } +export interface OfferVerifiableCredential { + "@context"?: string; // optional when embedded, eg. in an Agree + "@type": "Offer"; + description?: string; + includesObject?: { amountOfThisGood: number; unitCode: string }; + itemOffered?: { + description?: string; + isPartOf?: { identifier?: string; lastClaimId?: string; "@type"?: string }; + }; + offeredBy?: { identifier: string }; + validThrough?: string; +} + export interface PlanVerifiableCredential { "@context": "https://schema.org"; "@type": "PlanAction"; @@ -152,7 +175,7 @@ export interface ErrorResult { error: InternalError; } -export type CreateAndSubmitGiveResult = SuccessResult | ErrorResult; +export type CreateAndSubmitClaimResult = SuccessResult | ErrorResult; /** * For result, see https://api.endorser.ch/api-docs/#/claims/post_api_v2_claim @@ -172,20 +195,81 @@ export async function createAndSubmitGive( description?: string, hours?: number, fulfillsProjectHandleId?: string, -): Promise { - try { - const vcClaim: GiveVerifiableCredential = { - "@context": "https://schema.org", - "@type": "GiveAction", - recipient: toDid ? { identifier: toDid } : undefined, - agent: fromDid ? { identifier: fromDid } : undefined, - description: description || undefined, - object: hours ? { amountOfThisGood: hours, unitCode: "HUR" } : undefined, - fulfills: fulfillsProjectHandleId - ? { "@type": "PlanAction", identifier: fulfillsProjectHandleId } - : undefined, +): Promise { + const vcClaim: GiveVerifiableCredential = { + "@context": "https://schema.org", + "@type": "GiveAction", + recipient: toDid ? { identifier: toDid } : undefined, + agent: fromDid ? { identifier: fromDid } : undefined, + description: description || undefined, + object: hours ? { amountOfThisGood: hours, unitCode: "HUR" } : undefined, + fulfills: fulfillsProjectHandleId + ? { "@type": "PlanAction", identifier: fulfillsProjectHandleId } + : undefined, + }; + return createAndSubmitClaim( + vcClaim as GenericClaim, + identity, + apiServer, + axios, + ); +} + +/** + * For result, see https://api.endorser.ch/api-docs/#/claims/post_api_v2_claim + * + * @param identity + * @param description may be null; should have this or hours + * @param hours may be null; should have this or description + * @param expirationDate ISO 8601 date string YYYY-MM-DD (may be null) + * @param fulfillsProjectHandleId ID of project to which this contributes (may be null) + */ +export async function createAndSubmitOffer( + axios: Axios, + apiServer: string, + identity: IIdentifier, + description?: string, + hours?: number, + expirationDate?: string, + fulfillsProjectHandleId?: string, +): Promise { + const vcClaim: OfferVerifiableCredential = { + "@context": "https://schema.org", + "@type": "Offer", + offeredBy: { identifier: identity.did }, + validThrough: expirationDate || undefined, + }; + if (hours) { + vcClaim.includesObject = { + amountOfThisGood: hours, + unitCode: "HUR", }; + } + if (description) { + vcClaim.itemOffered = { description }; + } + if (fulfillsProjectHandleId) { + vcClaim.itemOffered = vcClaim.itemOffered || {}; + vcClaim.itemOffered.isPartOf = { + "@type": "PlanAction", + identifier: fulfillsProjectHandleId, + }; + } + return createAndSubmitClaim( + vcClaim as GenericClaim, + identity, + apiServer, + axios, + ); +} +export async function createAndSubmitClaim( + vcClaim: GenericClaim, + identity: IIdentifier, + apiServer: string, + axios: Axios, +): Promise { + try { const vcPayload = { vc: { "@context": ["https://www.w3.org/2018/credentials/v1"], @@ -226,15 +310,11 @@ export async function createAndSubmitGive( }); return { type: "success", response }; - } catch (error: unknown) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } catch (error: any) { + console.log("Error creating claim:", error); const errorMessage: string = - error === null - ? "Null error" - : error instanceof Error - ? error.message - : typeof error === "object" && error !== null && "message" in error - ? (error as { message: string }).message - : "Unknown error"; + error.response?.data?.error?.message || error.message || "Unknown error"; return { type: "error", diff --git a/src/registerServiceWorker.ts b/src/registerServiceWorker.ts index 5b60bb7d..22ca9b9a 100644 --- a/src/registerServiceWorker.ts +++ b/src/registerServiceWorker.ts @@ -3,7 +3,7 @@ import { register } from "register-service-worker"; if (process.env.NODE_ENV === "production") { - register(`${process.env.BASE_URL}service-worker.js`, { + register("/additional-scripts.js", { ready() { console.log( "App is being served from cache by a service worker.\n" + diff --git a/src/router/index.ts b/src/router/index.ts index 8868f60d..49b33760 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -168,6 +168,14 @@ const routes: Array = [ /* webpackChunkName: "scan-contact" */ "../views/ContactScanView.vue" ), }, + { + path: "/search-area", + name: "search-area", + component: () => + import( + /* webpackChunkName: "search-area" */ "../views/SearchAreaView.vue" + ), + }, { path: "/seed-backup", name: "seed-backup", diff --git a/src/views/AccountViewView.vue b/src/views/AccountViewView.vue index 08083fb0..e33d0d2e 100644 --- a/src/views/AccountViewView.vue +++ b/src/views/AccountViewView.vue @@ -186,8 +186,9 @@

You have done {{ limits.doneRegistrationsThisMonth }} registrations - out of {{ limits.maxRegistrationsPerMonth }} for this month. Your - registrations counter resets at + out of {{ limits.maxRegistrationsPerMonth }} for this month. (You can + register nobody on your first day, and after that only one a day in + your first month.) Your registration counter resets at {{ readableTime(limits.nextMonthBeginDateTime) }}

@@ -700,11 +701,11 @@ export default class AccountViewView extends Vue { this.$notify( { group: "alert", - type: "toast", + type: "success", title: "Download Started", text: "See your downloads directory for the backup.", }, - 5000, + -1, ); } diff --git a/src/views/ContactAmountsView.vue b/src/views/ContactAmountsView.vue index 385a2851..897505c1 100644 --- a/src/views/ContactAmountsView.vue +++ b/src/views/ContactAmountsView.vue @@ -2,8 +2,11 @@
-
-

+
+

+ +

+ Given with {{ contact?.name }} +

-

- Given with {{ contact?.name }} -

(Only 50 most recent) @@ -358,7 +362,10 @@ export default class ContactsView extends Vue {