forked from trent_larson/crowd-funder-for-time-pwa
cache the passkey JWANT access token for multiple signatures
This commit is contained in:
@@ -152,7 +152,7 @@
|
||||
|
||||
<div class="text-blue-500 text-sm font-bold">
|
||||
<router-link :to="{ path: '/did/' + encodeURIComponent(activeDid) }">
|
||||
Activity
|
||||
Your Activity
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
@@ -216,7 +216,6 @@
|
||||
<div class="mb-2 font-bold">Location</div>
|
||||
<router-link
|
||||
:to="{ name: 'search-area' }"
|
||||
v-if="activeDid"
|
||||
class="block w-full text-center text-m bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-1.5 py-2 rounded-md mb-2 mt-6"
|
||||
>
|
||||
Set Search Area…
|
||||
@@ -622,6 +621,26 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-between">
|
||||
<span>
|
||||
<span class="text-slate-500 text-sm font-bold mb-2">
|
||||
Passkey Expiration Minutes
|
||||
</span>
|
||||
<br />
|
||||
<span class="text-sm ml-2">
|
||||
{{ passkeyExpirationDescription }}
|
||||
</span>
|
||||
</span>
|
||||
<div class="relative ml-2">
|
||||
<input
|
||||
type="number"
|
||||
class="border border-slate-400 rounded px-2 py-2 text-center w-20"
|
||||
v-model="passkeyExpirationMinutes"
|
||||
@change="updatePasskeyExpiration"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label
|
||||
for="toggleShowGeneralAdvanced"
|
||||
class="flex items-center justify-between cursor-pointer mt-4"
|
||||
@@ -667,7 +686,7 @@ import ImageMethodDialog from "@/components/ImageMethodDialog.vue";
|
||||
import QuickNav from "@/components/QuickNav.vue";
|
||||
import TopMessage from "@/components/TopMessage.vue";
|
||||
import {
|
||||
AppString,
|
||||
AppString, DEFAULT_ENDORSER_API_SERVER,
|
||||
DEFAULT_IMAGE_API_SERVER,
|
||||
DEFAULT_PUSH_SERVER,
|
||||
IMAGE_TYPE_PROFILE,
|
||||
@@ -675,14 +694,20 @@ import {
|
||||
} from "@/constants/app";
|
||||
import { db, accountsDB } from "@/db/index";
|
||||
import { Account } from "@/db/tables/accounts";
|
||||
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
|
||||
import { accessToken } from "@/libs/crypto";
|
||||
import {
|
||||
DEFAULT_PASSKEY_EXPIRATION_MINUTES,
|
||||
MASTER_SETTINGS_KEY,
|
||||
Settings,
|
||||
} from "@/db/tables/settings";
|
||||
import {
|
||||
clearPasskeyToken,
|
||||
ErrorResponse,
|
||||
EndorserRateLimits,
|
||||
ImageRateLimits,
|
||||
fetchEndorserRateLimits,
|
||||
fetchImageRateLimits,
|
||||
getHeaders,
|
||||
ImageRateLimits,
|
||||
tokenExpiryTimeDescription,
|
||||
} from "@/libs/endorserServer";
|
||||
import { getAccount } from "@/libs/util";
|
||||
|
||||
@@ -713,6 +738,9 @@ export default class AccountViewView extends Vue {
|
||||
limitsMessage = "";
|
||||
loadingLimits = false;
|
||||
notificationMaybeChanged = false;
|
||||
passkeyExpirationDescription = "";
|
||||
passkeyExpirationMinutes = DEFAULT_PASSKEY_EXPIRATION_MINUTES;
|
||||
previousPasskeyExpirationMinutes = DEFAULT_PASSKEY_EXPIRATION_MINUTES;
|
||||
profileImageUrl?: string;
|
||||
publicHex = "";
|
||||
publicBase64 = "";
|
||||
@@ -745,12 +773,32 @@ export default class AccountViewView extends Vue {
|
||||
await this.initializeState();
|
||||
await this.processIdentity();
|
||||
|
||||
this.passkeyExpirationDescription = tokenExpiryTimeDescription();
|
||||
|
||||
/**
|
||||
* Beware! I've seen where this "ready" never resolves.
|
||||
*/
|
||||
const registration = await navigator.serviceWorker.ready;
|
||||
this.subscription = await registration.pushManager.getSubscription();
|
||||
this.isSubscribed = !!this.subscription;
|
||||
console.log("Got to the end of 'mounted' call.");
|
||||
/**
|
||||
* Beware! I've seen where we never get to this point because "ready" never resolves.
|
||||
*/
|
||||
} catch (error) {
|
||||
console.error("Mount error:", error);
|
||||
this.handleError(error);
|
||||
console.error(
|
||||
"Telling user to clear cache at page create because:",
|
||||
error,
|
||||
);
|
||||
this.$notify(
|
||||
{
|
||||
group: "alert",
|
||||
type: "danger",
|
||||
title: "Error Loading Account",
|
||||
text: "Clear your cache and start over (after data backup).",
|
||||
},
|
||||
-1,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -780,6 +828,10 @@ export default class AccountViewView extends Vue {
|
||||
this.showContactGives = !!settings?.showContactGivesInline;
|
||||
this.hideRegisterPromptOnNewContact =
|
||||
!!settings?.hideRegisterPromptOnNewContact;
|
||||
this.passkeyExpirationMinutes =
|
||||
(settings?.passkeyExpirationMinutes as number) ??
|
||||
DEFAULT_PASSKEY_EXPIRATION_MINUTES;
|
||||
this.previousPasskeyExpirationMinutes = this.passkeyExpirationMinutes;
|
||||
this.showGeneralAdvanced = !!settings?.showGeneralAdvanced;
|
||||
this.showShortcutBvc = !!settings?.showShortcutBvc;
|
||||
this.warnIfProdServer = !!settings?.warnIfProdServer;
|
||||
@@ -835,11 +887,11 @@ export default class AccountViewView extends Vue {
|
||||
this.publicHex = identity.keys[0].publicKeyHex;
|
||||
this.publicBase64 = Buffer.from(this.publicHex, "hex").toString("base64");
|
||||
this.derivationPath = identity.keys[0].meta?.derivationPath as string;
|
||||
this.checkLimitsFor(this.activeDid);
|
||||
await this.checkLimitsFor(this.activeDid);
|
||||
} else if (account?.publicKeyHex) {
|
||||
this.publicHex = account.publicKeyHex as string;
|
||||
this.publicBase64 = Buffer.from(this.publicHex, "hex").toString("base64");
|
||||
this.checkLimitsFor(this.activeDid);
|
||||
await this.checkLimitsFor(this.activeDid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -868,75 +920,18 @@ export default class AccountViewView extends Vue {
|
||||
this.notificationMaybeChanged = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles errors and updates the component's state accordingly.
|
||||
* @param {Error} err - The error object.
|
||||
*/
|
||||
handleError(err: unknown) {
|
||||
if (
|
||||
err instanceof Error &&
|
||||
err.message ===
|
||||
"Attempted to load account records with no identifier available."
|
||||
) {
|
||||
this.limitsMessage = "No identifier.";
|
||||
} else {
|
||||
console.error("Telling user to clear cache at page create because:", err);
|
||||
this.$notify(
|
||||
{
|
||||
group: "alert",
|
||||
type: "danger",
|
||||
title: "Error Loading Account",
|
||||
text: "Clear your cache and start over (after data backup).",
|
||||
},
|
||||
-1,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public async updateShowContactAmounts() {
|
||||
try {
|
||||
await db.open();
|
||||
await db.settings.update(MASTER_SETTINGS_KEY, {
|
||||
showContactGivesInline: this.showContactGives,
|
||||
});
|
||||
} catch (err) {
|
||||
this.$notify(
|
||||
{
|
||||
group: "alert",
|
||||
type: "danger",
|
||||
title: "Error Updating Contact Setting",
|
||||
text: "The setting may not have saved. Try again, maybe after restarting the app.",
|
||||
},
|
||||
-1,
|
||||
);
|
||||
console.error(
|
||||
"Telling user to try again after contact-amounts setting update because:",
|
||||
err,
|
||||
);
|
||||
}
|
||||
await db.open();
|
||||
await db.settings.update(MASTER_SETTINGS_KEY, {
|
||||
showContactGivesInline: this.showContactGives,
|
||||
});
|
||||
}
|
||||
|
||||
public async updateShowGeneralAdvanced() {
|
||||
try {
|
||||
await db.open();
|
||||
await db.settings.update(MASTER_SETTINGS_KEY, {
|
||||
showGeneralAdvanced: this.showGeneralAdvanced,
|
||||
});
|
||||
} catch (err) {
|
||||
this.$notify(
|
||||
{
|
||||
group: "alert",
|
||||
type: "danger",
|
||||
title: "Error Updating Advanced Setting",
|
||||
text: "The setting may not have saved. Try again, maybe after restarting the app.",
|
||||
},
|
||||
-1,
|
||||
);
|
||||
console.error(
|
||||
"Telling user to try again after general-advanced setting update because:",
|
||||
err,
|
||||
);
|
||||
}
|
||||
await db.open();
|
||||
await db.settings.update(MASTER_SETTINGS_KEY, {
|
||||
showGeneralAdvanced: this.showGeneralAdvanced,
|
||||
});
|
||||
}
|
||||
|
||||
public async updateWarnIfProdServer(newSetting: boolean) {
|
||||
@@ -963,71 +958,35 @@ export default class AccountViewView extends Vue {
|
||||
}
|
||||
|
||||
public async updateWarnIfTestServer(newSetting: boolean) {
|
||||
try {
|
||||
await db.open();
|
||||
await db.settings.update(MASTER_SETTINGS_KEY, {
|
||||
warnIfTestServer: newSetting,
|
||||
});
|
||||
} catch (err) {
|
||||
this.$notify(
|
||||
{
|
||||
group: "alert",
|
||||
type: "danger",
|
||||
title: "Error Updating Test Warning",
|
||||
text: "The setting may not have saved. Try again, maybe after restarting the app.",
|
||||
},
|
||||
-1,
|
||||
);
|
||||
console.error(
|
||||
"Telling user to try again after test-server-warning setting update because:",
|
||||
err,
|
||||
);
|
||||
}
|
||||
await db.open();
|
||||
await db.settings.update(MASTER_SETTINGS_KEY, {
|
||||
warnIfTestServer: newSetting,
|
||||
});
|
||||
}
|
||||
|
||||
public async toggleHideRegisterPromptOnNewContact() {
|
||||
const newSetting = !this.hideRegisterPromptOnNewContact;
|
||||
try {
|
||||
await db.open();
|
||||
await db.settings.update(MASTER_SETTINGS_KEY, {
|
||||
hideRegisterPromptOnNewContact: newSetting,
|
||||
});
|
||||
this.hideRegisterPromptOnNewContact = newSetting;
|
||||
} catch (err) {
|
||||
this.$notify(
|
||||
{
|
||||
group: "alert",
|
||||
type: "danger",
|
||||
title: "Error Updating Setting",
|
||||
text: "The setting may not have saved. Try again, maybe after restarting the app.",
|
||||
},
|
||||
-1,
|
||||
);
|
||||
console.error("Telling user to try again because:", err);
|
||||
}
|
||||
await db.open();
|
||||
await db.settings.update(MASTER_SETTINGS_KEY, {
|
||||
hideRegisterPromptOnNewContact: newSetting,
|
||||
});
|
||||
this.hideRegisterPromptOnNewContact = newSetting;
|
||||
}
|
||||
|
||||
public async updatePasskeyExpiration() {
|
||||
await db.open();
|
||||
await db.settings.update(MASTER_SETTINGS_KEY, {
|
||||
passkeyExpirationMinutes: this.passkeyExpirationMinutes,
|
||||
});
|
||||
clearPasskeyToken();
|
||||
this.passkeyExpirationDescription = tokenExpiryTimeDescription();
|
||||
}
|
||||
|
||||
public async updateShowShortcutBvc(newSetting: boolean) {
|
||||
try {
|
||||
await db.open();
|
||||
await db.settings.update(MASTER_SETTINGS_KEY, {
|
||||
showShortcutBvc: newSetting,
|
||||
});
|
||||
} catch (err) {
|
||||
this.$notify(
|
||||
{
|
||||
group: "alert",
|
||||
type: "danger",
|
||||
title: "Error Updating BVC Shortcut Setting",
|
||||
text: "The setting may not have saved. Try again, maybe after restarting the app.",
|
||||
},
|
||||
-1,
|
||||
);
|
||||
console.error(
|
||||
"Telling user to try again after BVC-shortcut setting update because:",
|
||||
err,
|
||||
);
|
||||
}
|
||||
await db.open();
|
||||
await db.settings.update(MASTER_SETTINGS_KEY, {
|
||||
showShortcutBvc: newSetting,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1220,7 +1179,7 @@ export default class AccountViewView extends Vue {
|
||||
// the user was not known to be registered, but now they are (because we got no error) so let's record it
|
||||
try {
|
||||
await db.open();
|
||||
db.settings.update(MASTER_SETTINGS_KEY, {
|
||||
await db.settings.update(MASTER_SETTINGS_KEY, {
|
||||
isRegistered: true,
|
||||
});
|
||||
this.isRegistered = true;
|
||||
@@ -1247,7 +1206,7 @@ export default class AccountViewView extends Vue {
|
||||
|
||||
try {
|
||||
await db.open();
|
||||
db.settings.update(MASTER_SETTINGS_KEY, {
|
||||
await db.settings.update(MASTER_SETTINGS_KEY, {
|
||||
isRegistered: false,
|
||||
});
|
||||
this.isRegistered = false;
|
||||
@@ -1272,8 +1231,8 @@ export default class AccountViewView extends Vue {
|
||||
(data?.error?.message as string) || "Bad server response.";
|
||||
console.error(
|
||||
"Got bad response retrieving limits, which usually means user isn't registered.",
|
||||
error,
|
||||
);
|
||||
//console.error(error);
|
||||
} else {
|
||||
this.limitsMessage = "Got an error retrieving limits.";
|
||||
console.error("Got some error retrieving limits:", error);
|
||||
@@ -1350,7 +1309,7 @@ export default class AccountViewView extends Vue {
|
||||
|
||||
async onClickSaveApiServer() {
|
||||
await db.open();
|
||||
db.settings.update(MASTER_SETTINGS_KEY, {
|
||||
await db.settings.update(MASTER_SETTINGS_KEY, {
|
||||
apiServer: this.apiServerInput,
|
||||
});
|
||||
this.apiServer = this.apiServerInput;
|
||||
@@ -1358,7 +1317,7 @@ export default class AccountViewView extends Vue {
|
||||
|
||||
async onClickSavePushServer() {
|
||||
await db.open();
|
||||
db.settings.update(MASTER_SETTINGS_KEY, {
|
||||
await db.settings.update(MASTER_SETTINGS_KEY, {
|
||||
webPushServer: this.webPushServerInput,
|
||||
});
|
||||
this.webPushServer = this.webPushServerInput;
|
||||
@@ -1377,7 +1336,7 @@ export default class AccountViewView extends Vue {
|
||||
(this.$refs.imageMethodDialog as ImageMethodDialog).open(
|
||||
async (imgUrl) => {
|
||||
await db.open();
|
||||
db.settings.update(MASTER_SETTINGS_KEY, {
|
||||
await db.settings.update(MASTER_SETTINGS_KEY, {
|
||||
profileImageUrl: imgUrl,
|
||||
});
|
||||
this.profileImageUrl = imgUrl;
|
||||
@@ -1407,16 +1366,13 @@ export default class AccountViewView extends Vue {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const token = await accessToken(this.activeDid);
|
||||
const headers = await getHeaders(this.activeDid);
|
||||
this.passkeyExpirationDescription = tokenExpiryTimeDescription();
|
||||
const response = await this.axios.delete(
|
||||
DEFAULT_IMAGE_API_SERVER +
|
||||
"/image/" +
|
||||
encodeURIComponent(this.profileImageUrl),
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
},
|
||||
{ headers },
|
||||
);
|
||||
if (response.status === 204) {
|
||||
// don't bother with a notification
|
||||
@@ -1436,7 +1392,7 @@ export default class AccountViewView extends Vue {
|
||||
}
|
||||
|
||||
await db.open();
|
||||
db.settings.update(MASTER_SETTINGS_KEY, {
|
||||
await db.settings.update(MASTER_SETTINGS_KEY, {
|
||||
profileImageUrl: undefined,
|
||||
});
|
||||
|
||||
@@ -1448,7 +1404,7 @@ export default class AccountViewView extends Vue {
|
||||
console.error("The image was already deleted:", error);
|
||||
|
||||
await db.open();
|
||||
db.settings.update(MASTER_SETTINGS_KEY, {
|
||||
await db.settings.update(MASTER_SETTINGS_KEY, {
|
||||
profileImageUrl: undefined,
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user