Browse Source

Merge pull request 'add page to show mnemonic seed phrase for backup' (#20) from seed-backup into switching-servers

Reviewed-on: https://gitea.anomalistdesign.com/trent_larson/kick-starter-for-time-pwa/pulls/20
world-fix
anomalist 2 years ago
parent
commit
b0ccd84b62
  1. 11
      project.task.yaml
  2. 8
      src/router/index.ts
  3. 9
      src/views/AccountViewView.vue
  4. 5
      src/views/ContactAmountsView.vue
  5. 5
      src/views/ContactsView.vue
  6. 93
      src/views/HelpView.vue
  7. 19
      src/views/NewEditProjectView.vue
  8. 1
      src/views/ProjectViewView.vue
  9. 1
      src/views/ProjectsView.vue
  10. 162
      src/views/SeedBackupView.vue

11
project.yaml → project.task.yaml

@ -6,13 +6,10 @@
- replace user-affecting console.logs with error messages (eg. catches)
- contacts v1 :
- .1 remove 'copy' until it works
- .5 Add page to show seed.
- 01 Provide a way to import the non-sensitive data.
- 01 Provide way to share your contact info.
- 01 Provide a way to import the non-sensitive data.
- .2 move all "identity" references to temporary account access
- .5 make deploy for give-only features
- .5 get 'copy' to work on account page
- contacts v+ :
- .5 make advanced "show/hide amounts" button into a nice UI toggle
@ -22,10 +19,12 @@
- refactor UI :
- .5 Alerts show at the top and can be missed, eg. account data download
- 01 Change alerts into a component (to cut down duplicate code)
- 01 Code for "nav" tabs across the bottom is duplicated on each page.
- .2 Add "copied" feedback when they click "copy" on /account
- 01 Change "nav" tabs across the bottom into a component (eliminating duplicate code).
- .5 Fix how icons show on top of bottom bar on ContactAmounts page
- on stats-world, use all bits of randomness for location
- show pop-up confirming that settings & contacts have been downloaded
- commit screen
- discover screen

8
src/router/index.ts

@ -115,6 +115,14 @@ const routes: Array<RouteRecordRaw> = [
component: () =>
import(/* webpackChunkName: "projects" */ "../views/ProjectsView.vue"),
},
{
path: "/seed-backup",
name: "seed-backup",
component: () =>
import(
/* webpackChunkName: "seed-backup" */ "../views/SeedBackupView.vue"
),
},
{
path: "/start",
name: "start",

9
src/views/AccountViewView.vue

@ -164,12 +164,13 @@
<h3 class="text-sm uppercase font-semibold mb-3">Data</h3>
<a
<router-link
:to="{ name: 'seed-backup' }"
href=""
class="block w-full text-center text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md mb-2"
>
Backup Identifier Seed
</a>
</router-link>
<a
class="block w-full text-center text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md mb-6"
@click="exportDatabase()"
@ -291,6 +292,7 @@
</span>
</div>
<!-- This same popup code is in many files. -->
<div v-bind:class="computedAlertClassNames()">
<button
class="close-button bg-slate-200 w-8 leading-loose rounded-full absolute top-2 right-2"
@ -542,16 +544,15 @@ export default class AccountViewView extends Vue {
this.apiServerInput = value;
}
// This same popup code is in many files.
alertMessage = "";
alertTitle = "";
isAlertVisible = false;
public onClickClose() {
this.isAlertVisible = false;
this.alertTitle = "";
this.alertMessage = "";
}
public computedAlertClassNames() {
return {
hidden: !this.isAlertVisible,

5
src/views/ContactAmountsView.vue

@ -110,6 +110,7 @@
</div>
</div>
<!-- This same popup code is in many files. -->
<div v-bind:class="computedAlertClassNames()">
<button
class="close-button bg-slate-200 w-8 leading-loose rounded-full absolute top-2 right-2"
@ -130,7 +131,6 @@ import { Options, Vue } from "vue-class-component";
import { accountsDB, db } from "@/db";
import { Contact } from "@/db/tables/contacts";
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
import { AppString } from "@/constants/app";
import { accessToken, SimpleSigner } from "@/libs/crypto";
import {
AgreeVerifiableCredential,
@ -321,16 +321,15 @@ export default class ContactsView extends Vue {
this.isAlertVisible = true;
}
// This same popup code is in many files.
alertTitle = "";
alertMessage = "";
isAlertVisible = false;
public onClickClose() {
this.isAlertVisible = false;
this.alertTitle = "";
this.alertMessage = "";
}
public computedAlertClassNames() {
return {
hidden: !this.isAlertVisible,

5
src/views/ContactsView.vue

@ -232,6 +232,7 @@
</ul>
</section>
<!-- This same popup code is in many files. -->
<div v-bind:class="computedAlertClassNames()">
<button
class="close-button bg-slate-200 w-8 leading-loose rounded-full absolute top-2 right-2"
@ -251,7 +252,6 @@ import * as R from "ramda";
import { IIdentifier } from "@veramo/core";
import { Options, Vue } from "vue-class-component";
import { AppString } from "@/constants/app";
import { accountsDB, db } from "@/db";
import { Contact } from "@/db/tables/contacts";
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
@ -828,16 +828,15 @@ export default class ContactsView extends Vue {
}
}
// This same popup code is in many files.
alertTitle = "";
alertMessage = "";
isAlertVisible = false;
public onClickClose() {
this.isAlertVisible = false;
this.alertTitle = "";
this.alertMessage = "";
}
public computedAlertClassNames() {
return {
hidden: !this.isAlertVisible,

93
src/views/HelpView.vue

@ -55,12 +55,34 @@
</h1>
<div>
<h2 class="text-xl font-semibold">Introduction</h2>
<p>
This app is a window into data that you and your friends own, focused on
gifts and collaboration.
</p>
<h2 class="text-xl font-semibold">How is this app useful?</h2>
<p>
We are building networks of people who want to grow a gifting society.
First of all, you can record ways you've seen people give, and that
leaves a permanent record... one that they show came from you. This is
personally gratifying, but it extends to broader work: volunteers can
get confirmation of activity and selectively show off their
contributions and network.
</p>
<p>
You can also record projects and plans and invite others to collaborate.
Soon you'll be able to see when others are interested and see how much
they're willing to contribute, even if there are conditions.
</p>
<p>
This app uses the power of cryptography to build a reputation, recording
activity that you can share at your discretion. You put some activity
public, but your sensitive information is not shared with anyone,
including our services. This is in contrast to Meta and Google, who hold
your data and allow you use it. Those services are useful, but they have
the control; this app gives you the control.
</p>
<h2 class="text-xl font-semibold">How do I backup all my data?</h2>
<p>
There are two parts to backup your data: the identifier secrets and the
@ -147,19 +169,76 @@
key.
</p>
<h2 class="text-xl font-semibold">
How do I get permission to store claims on the server?
</h2>
<p>
Get registered by someone else with the app; they can register you on
the Contacts <fa icon="circle-user" class="fa-fw" /> page. There are
limits to how many each person can register, so you may have to wait.
</p>
<h2 class="text-xl font-semibold">What do you mean by "claims"?</h2>
<p>
Certain actions in this app are signed by your private keys, and these
are often called "claims". For example, when you give time to a person
or project, you sign a claim declaring that you gave that time. When you
declare a project, you sign a claim declaring it to the world. When you
confirm someone else's claim, you sign a claim of agreement.
</p>
<p>
Some of the data in this app does not involve claims, such as your
contact list and your identifier.
</p>
<h2 class="text-xl font-semibold">
I know there is a record from someone, so why can't I see that info?
</h2>
<p>
Sometimes someone else has made claims -- meaning they have given time,
or recognized time given, or declared a project -- but you cannot see
anything associated with them. The reason may be because they have not
given you permission to see their information. Ask them to add you to
their contact list and make sure the eye next to your name is open like
this
If you don't see anything associated with a person, this is typically
because they have not given you permission to see their information. Ask
them to add you to their contact list and make sure the eye next to your
name is open like this
<fa icon="eye" class="fa-fw" /> and not closed like this
<fa icon="eye-slash" class="fa-fw" />.
</p>
<p>
Sometimes the reason you don't see something is because the search time
is limited. Go to the bottom and make sure to load all the data on a
list. If you still don't see it, try a search or view on a different
page.
</p>
<h2 class="text-xl font-semibold">How do I create another identity?</h2>
<p>
Go
<router-link to="import-account" class="text-blue-500">
import another mnemonic here.
</router-link>
</p>
<h2 class="text-xl font-semibold">What is your privacy policy?</h2>
<p>
See
<a href="https://endorser.ch/privacy-policy" class="text-blue-500">
the Endorser Service Privacy Policy.
</a>
</p>
<h2 class="text-xl font-semibold">What app version is this?</h2>
<p>
{{ package.version }}
</p>
</div>
</section>
</template>
<script lang="ts">
import * as Package from "../../package.json";
import { Component, Vue } from "vue-facing-decorator";
@Component
export default class Help extends Vue {
package = Package;
}
</script>

19
src/views/NewEditProjectView.vue

@ -63,6 +63,8 @@
</button>
</div>
</section>
<!-- This same popup code is in many files. -->
<div v-bind:class="computedAlertClassNames()">
<button
class="close-button bg-slate-200 w-8 leading-loose rounded-full absolute top-2 right-2"
@ -81,7 +83,6 @@ import * as didJwt from "did-jwt";
import * as R from "ramda";
import { Options, Vue } from "vue-class-component";
import { AppString } from "@/constants/app";
import { accountsDB, db } from "@/db";
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
import { accessToken, SimpleSigner } from "@/libs/crypto";
@ -105,8 +106,6 @@ export default class NewEditProjectView extends Vue {
projectName = "";
description = "";
errorMessage = "";
alertTitle = "";
alertMessage = "";
projectId = localStorage.getItem("projectId") || "";
isHiddenSave = false;
@ -249,12 +248,6 @@ export default class NewEditProjectView extends Vue {
}
}
public onClickClose() {
this.isAlertVisible = false;
this.alertTitle = "";
this.alertMessage = "";
}
public async onSaveProjectClick() {
this.isHiddenSave = true;
this.isHiddenSpinner = false;
@ -274,7 +267,15 @@ export default class NewEditProjectView extends Vue {
this.$router.back();
}
// This same popup code is in many files.
alertTitle = "";
alertMessage = "";
isAlertVisible = false;
public onClickClose() {
this.isAlertVisible = false;
this.alertTitle = "";
this.alertMessage = "";
}
public computedAlertClassNames() {
return {
hidden: !this.isAlertVisible,

1
src/views/ProjectViewView.vue

@ -151,7 +151,6 @@ import * as moment from "moment";
import * as R from "ramda";
import { Options, Vue } from "vue-class-component";
import { AppString } from "@/constants/app";
import { accountsDB, db } from "@/db";
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
import { accessToken } from "@/libs/crypto";

1
src/views/ProjectsView.vue

@ -104,7 +104,6 @@
import * as R from "ramda";
import { Options, Vue } from "vue-class-component";
import { AppString } from "@/constants/app";
import { accountsDB, db } from "@/db";
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
import { accessToken } from "@/libs/crypto";

162
src/views/SeedBackupView.vue

@ -0,0 +1,162 @@
<template>
<!-- QUICK NAV -->
<nav id="QuickNav" class="fixed bottom-0 left-0 right-0 bg-slate-200 z-50">
<ul class="flex text-2xl p-2 gap-2">
<!-- Home Feed -->
<li class="basis-1/5 rounded-md text-slate-500">
<router-link :to="{ name: 'home' }" class="block text-center py-3 px-1">
<fa icon="house-chimney" class="fa-fw"></fa>
</router-link>
</li>
<!-- Search -->
<li class="basis-1/5 rounded-md text-slate-500">
<router-link
:to="{ name: 'discover' }"
class="block text-center py-3 px-1"
>
<fa icon="magnifying-glass" class="fa-fw"></fa>
</router-link>
</li>
<!-- Projects -->
<li class="basis-1/5 rounded-md text-slate-500">
<router-link
:to="{ name: 'projects' }"
class="block text-center py-3 px-1"
>
<fa icon="folder-open" class="fa-fw"></fa>
</router-link>
</li>
<!-- Contacts -->
<li class="basis-1/5 rounded-md text-slate-500">
<router-link
:to="{ name: 'contacts' }"
class="block text-center py-3 px-1"
>
<fa icon="users" class="fa-fw"></fa>
</router-link>
</li>
<!-- Profile -->
<li class="basis-1/5 rounded-md bg-slate-400 text-white">
<router-link
:to="{ name: 'account' }"
class="block text-center py-3 px-1"
>
<fa icon="circle-user" class="fa-fw"></fa>
</router-link>
</li>
</ul>
</nav>
<!-- CONTENT -->
<section id="Content" class="p-6 pb-24">
<!-- Heading -->
<h1 id="ViewHeading" class="text-4xl text-center font-light pt-4 mb-8">
Seed Backup
</h1>
<div class="flex justify-between py-2">
<span />
<span>
<router-link
:to="{ name: 'help' }"
class="text-xs uppercase bg-blue-500 text-white px-1.5 py-1 rounded-md ml-1"
>
Help
</router-link>
</span>
</div>
<div v-if="activeAccount">
<p>
BEWARE: Anyone who gets hold of this mnemonic seed phrase will be able
impersonate you and take over any digital holdings based on it. So only
reveal it when you are in a private place out of sight of other eyes,
and only record it in something private -- don't take a screenshot or
send it to any online service.
</p>
<button
class="block w-full text-center text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md"
@click="showSeedPhrase"
>
Click here when you're ready to see it.
</button>
<p v-if="showSeed">{{ activeAccount.mnemonic }}</p>
</div>
<div v-else>You do not have an active identity.</div>
<!-- This same popup code is in many files. -->
<div v-bind:class="computedAlertClassNames()">
<button
class="close-button bg-slate-200 w-8 leading-loose rounded-full absolute top-2 right-2"
@click="onClickClose()"
>
<fa icon="xmark"></fa>
</button>
<h4 class="font-bold pr-5">{{ alertTitle }}</h4>
<p>{{ alertMessage }}</p>
</div>
</section>
</template>
<script lang="ts">
import { Component, Vue } from "vue-facing-decorator";
import { accountsDB, db } from "@/db";
import * as R from "ramda";
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
@Component
export default class SeedBackupView extends Vue {
activeAccount = null;
showSeed = false;
// 'created' hook runs when the Vue instance is first created
async created() {
try {
await db.open();
const settings = await db.settings.get(MASTER_SETTINGS_KEY);
const activeDid = settings?.activeDid || "";
await accountsDB.open();
const accounts = await accountsDB.accounts.toArray();
this.activeAccount = R.find((acc) => acc.did === activeDid, accounts);
} catch (err) {
console.log("Got an error loading an identity:", err);
this.alertTitle = "Error Loading Account";
this.alertMessage = "Got an error loading your seed data.";
this.isAlertVisible = true;
}
}
showSeedPhrase() {
this.showSeed = true;
}
// This same popup code is in many files.
alertMessage = "";
alertTitle = "";
isAlertVisible = false;
public onClickClose() {
this.isAlertVisible = false;
this.alertTitle = "";
this.alertMessage = "";
}
public computedAlertClassNames() {
return {
hidden: !this.isAlertVisible,
"dismissable-alert": true,
"bg-slate-100": true,
"p-5": true,
rounded: true,
"drop-shadow-lg": true,
fixed: true,
"top-3": true,
"inset-x-3": true,
"transition-transform": true,
"ease-in": true,
"duration-300": true,
};
}
}
</script>
Loading…
Cancel
Save