aboutsummaryrefslogtreecommitdiff
path: root/extension/src/entries
diff options
context:
space:
mode:
authorLibravatar vnugent <public@vaughnnugent.com>2023-11-22 02:21:53 -0500
committerLibravatar vnugent <public@vaughnnugent.com>2023-11-22 02:21:53 -0500
commit2ba94602a87c87b47f566745bdab40ce75e0e879 (patch)
tree396cb9c6d73d6bfb4e4b2d4fb440d7656fe493e0 /extension/src/entries
parent43429314c0989b423e116be3e9f222eba5b636c3 (diff)
latest patches, remove webext-bridge, lastest vnlib.browser
Diffstat (limited to 'extension/src/entries')
-rw-r--r--extension/src/entries/contentScript/nostr-shim.js49
-rw-r--r--extension/src/entries/contentScript/primary/components/PromptPopup.vue127
-rw-r--r--extension/src/entries/contentScript/primary/main.js24
-rw-r--r--extension/src/entries/contentScript/renderContent.js4
-rw-r--r--extension/src/entries/nostr-provider.js10
-rw-r--r--extension/src/entries/popup/Components/Login.vue2
-rw-r--r--extension/src/entries/popup/Components/PageContent.vue7
-rw-r--r--extension/src/entries/popup/main.js4
-rw-r--r--extension/src/entries/store/allowedOrigins.ts4
-rw-r--r--extension/src/entries/store/features.ts50
-rw-r--r--extension/src/entries/store/identity.ts15
11 files changed, 152 insertions, 144 deletions
diff --git a/extension/src/entries/contentScript/nostr-shim.js b/extension/src/entries/contentScript/nostr-shim.js
index eddc678..418b9c1 100644
--- a/extension/src/entries/contentScript/nostr-shim.js
+++ b/extension/src/entries/contentScript/nostr-shim.js
@@ -17,7 +17,6 @@ import { runtime } from "webextension-polyfill"
import { isEqual, isNil, isEmpty } from 'lodash'
import { apiCall } from '@vnuge/vnlib.browser'
import { useScriptTag, watchOnce } from "@vueuse/core"
-import { createPort } from '../../webext-bridge/'
import { useStore } from '../store'
import { storeToRefs } from 'pinia'
@@ -34,11 +33,14 @@ export const usePrompt = (callback) => _promptHandler.set(callback);
export const onLoad = async () =>{
+ const store = useStore()
+ const { nostr } = store.plugins
+ const { isTabAllowed, selectedKey } = storeToRefs(store)
+
const injectHandler = () => {
//Setup listener for the content script to process nostr messages
const ext = '@vnuge/nvault-extension'
- const { sendMessage } = createPort('content-script')
const scriptUrl = runtime.getURL('src/entries/nostr-provider.js')
@@ -47,6 +49,14 @@ export const onLoad = async () =>{
//Only listen for messages if injection is enabled
window.addEventListener('message', async ({ source, data, origin }) => {
+
+ const invokePrompt = async (cb) => {
+ //await propmt for user to allow the request
+ const allow = await _promptHandler.invoke({ ...data, origin })
+ //send request to background
+ return response = allow ? await cb() : { error: 'User denied permission' }
+ }
+
//Confirm the message format is correct
if (!isEqual(source, window) || isEmpty(data) || isNil(data.type)) {
return
@@ -56,21 +66,42 @@ export const onLoad = async () =>{
return
}
+ //clean any junk/methods with json parse/stringify
+ data = JSON.parse(JSON.stringify(data))
+
// pass on to background
var response;
await apiCall(async () => {
switch (data.type) {
case 'getPublicKey':
+ return invokePrompt(async () => selectedKey.value.PublicKey)
case 'signEvent':
+ return invokePrompt(async () => {
+ const event = data.payload.event
+
+ //Set key id to selected key
+ event.KeyId = selectedKey.value.Id
+ event.pubkey = selectedKey.value.PublicKey;
+
+ return await nostr.signEvent(event);
+ })
//Check the public key against selected key
case 'getRelays':
+ return invokePrompt(async () => await nostr.getRelays())
case 'nip04.encrypt':
+ return invokePrompt(async () => await nostr.nip04Encrypt({
+ pubkey: data.payload.peer,
+ content: data.payload.plaintext,
+ //Set selected key id as our desired decryption key
+ KeyId: selectedKey.value.Id
+ }))
case 'nip04.decrypt':
- //await propmt for user to allow the request
- const allow = await _promptHandler.invoke({ ...data, origin })
- //send request to background
- response = allow ? await sendMessage(data.type, { ...data.payload, origin }, 'background') : { error: 'User denied permission' }
- break;
+ return invokePrompt(async () => await nostr.nip04Decrypt({
+ pubkey: data.payload.peer,
+ content: data.payload.ciphertext,
+ //Set selected key id as our desired decryption key
+ KeyId: selectedKey.value.Id
+ }))
default:
throw new Error('Unknown nostr message type')
}
@@ -80,14 +111,10 @@ export const onLoad = async () =>{
});
}
- const store = useStore()
- const { isTabAllowed } = storeToRefs(store)
-
//Make sure the origin is allowed
if (store.isTabAllowed === false){
//If not allowed yet, wait for the store to update
watchOnce(isTabAllowed, val => val ? injectHandler() : undefined);
- return;
}
else{
injectHandler();
diff --git a/extension/src/entries/contentScript/primary/components/PromptPopup.vue b/extension/src/entries/contentScript/primary/components/PromptPopup.vue
index 195c6db..b8b7cab 100644
--- a/extension/src/entries/contentScript/primary/components/PromptPopup.vue
+++ b/extension/src/entries/contentScript/primary/components/PromptPopup.vue
@@ -1,80 +1,89 @@
<template>
- <div v-show="isOpen" id="nvault-ext-prompt">
- <div class="relative text-white" style="z-index:9147483647 !important" ref="prompt">
- <div class="fixed inset-0 left-0 flex justify-center w-full h-full p-4 bg-black/50">
- <div class="relative w-full max-w-md mx-auto mt-20 mb-auto">
- <div class="w-full p-4 border rounded-lg shadow-lg bg-dark-700 border-dark-400">
- <div v-if="loggedIn" class="">
- <h3 class="">Allow access</h3>
- <div class="pl-1 text-sm">
- Identity:
- </div>
- <div class="p-2 mt-1 text-center border rounded border-dark-400 bg-dark-600">
- <div :class="[keyName ? '' : 'text-red-500']">
- {{ keyName ?? 'Select Identity' }}
+ <div v-show="isOpen" id="nvault-ext-prompt" :class="{'dark': darkMode }">
+
+ <div class="absolute top-0 bottom-0 left-0 right-0 text-white" style="z-index:9147483647 !important" >
+ <div class="fixed inset-0 left-0 w-full h-full bg-black/50" @click.self="close" />
+ <div class="relative w-full max-w-[28rem] mx-auto mt-36 mb-auto" ref="prompt">
+ <div class="w-full p-5 bg-white border rounded-lg shadow-lg dark:bg-dark-900 dark:border-dark-500">
+ <div v-if="loggedIn" class="text-gray-800 dark:text-gray-200">
+
+ <div class="flex flex-row justify-between">
+ <div class="">
+ <div class="text-lg font-bold">
+ Allow access
+ </div>
+ <div class="text-sm">
+ <span class="">
+ Identity:
+ </span>
+ <span :class="[keyName ? '' : 'text-red-500']">
+ {{ keyName ?? 'Select Identity' }}
+ </span>
</div>
</div>
- <div class="mt-5 text-center">
- <span class="text-primary-500">{{ site }}</span>
- would like to access to
- <span class="text-yellow-500">{{ event?.msg }}</span>
- </div>
- <div class="flex gap-2 mt-4">
<div class="">
- <Popover class="relative">
- <PopoverButton class="rounded btn sm">View Raw</PopoverButton>
- <PopoverPanel class="absolute z-10">
- <div class="min-w-[22rem] p-2 border rounded bg-dark-700 border-dark-400 shadow-md text-sm">
- <p class="pl-1">
- Event Data:
- </p>
- <div class="p-2 mt-1 text-left border rounded border-dark-400 bg-dark-600 overflow-y-auto max-h-[22rem]">
-<pre>
-{{ evData }}
-</pre>
- </div>
+ <Popover class="relative">
+ <PopoverButton class="">
+ <fa-icon icon="circle-info" class="w-4 h-4" />
+ </PopoverButton>
+ <PopoverPanel class="absolute right-0 z-10">
+ <div class="min-w-[22rem] p-2 border rounded dark:bg-dark-800 bg-gray-50 dark:border-dark-500 shadow-md text-sm">
+ <p class="pl-1">
+ Event Data:
+ </p>
+ <div class="p-2 mt-1 text-left border rounded dark:border-dark-500 border-gray-300 overflow-auto max-h-[22rem] max-w-lg">
+ <pre>{{ evData }}</pre>
</div>
- </PopoverPanel>
- </Popover>
- </div>
- <div class="ml-auto">
- <button :disabled="selectedKey?.Id == undefined" class="rounded btn primary sm" @click="allow">Allow</button>
- </div>
- <div>
- <button class="rounded btn sm red" @click="close">Close</button>
- </div>
+ </div>
+ </PopoverPanel>
+ </Popover>
</div>
</div>
- <div v-else class="">
- <h3 class="">Log in!</h3>
- <div class="">
- You must log in before you can allow access.
+
+ <div class="py-3 text-sm text-center">
+ <span class="font-bold">{{ site }}</span>
+ would like to access to
+ <span class="font-bold">{{ event?.msg }}</span>
+ </div>
+
+ <div class="flex gap-2 mt-4">
+ <div class="ml-auto">
+ <button class="rounded btn sm" @click="close">Close</button>
</div>
- <div class="flex justify-end gap-2 mt-4">
- <div>
- <button class="rounded btn sm red" @click="close">Close</button>
- </div>
+ <div>
+ <button :disabled="selectedKey?.Id == undefined" class="rounded btn sm" @click="allow">Allow</button>
+ </div>
+ </div>
+ </div>
+ <div v-else class="">
+ <h3 class="">Log in!</h3>
+ <div class="">
+ You must log in before you can allow access.
+ </div>
+ <div class="flex justify-end gap-2 mt-4">
+ <div>
+ <button class="rounded btn xs" @click="close">Close</button>
</div>
</div>
</div>
</div>
</div>
</div>
+
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { usePrompt } from '../../nostr-shim.js'
-import { computed } from '@vue/reactivity';
-import { } from '@vueuse/core';
+import { computed } from 'vue';
import { Popover, PopoverButton, PopoverPanel } from '@headlessui/vue'
-import { first } from 'lodash';
+import { clone, first } from 'lodash';
import { useStore } from '../../../store';
import { storeToRefs } from 'pinia';
const store = useStore()
-const { loggedIn, selectedKey } = storeToRefs(store)
+const { loggedIn, selectedKey, darkMode } = storeToRefs(store)
const keyName = computed(() => selectedKey.value?.UserName)
const prompt = ref(null)
@@ -107,12 +116,11 @@ const allow = () => {
res?.allow()
}
-//Setup click outside
-//onClickOutside(prompt, () => isOpen.value ? close() : null)
-
//Listen for events
usePrompt(async (ev: PopupEvent) => {
+ ev = clone(ev)
+
console.log('[usePrompt] =>', ev)
switch(ev.type){
@@ -131,6 +139,9 @@ usePrompt(async (ev: PopupEvent) => {
case 'nip04.decrypt':
ev.msg = "decrypt data"
break;
+ default:
+ ev.msg = "unknown event"
+ break;
}
return new Promise((resolve) => {
@@ -142,10 +153,4 @@ usePrompt(async (ev: PopupEvent) => {
})
})
-
</script>
-
-<style lang="scss">
-
-
-</style>
diff --git a/extension/src/entries/contentScript/primary/main.js b/extension/src/entries/contentScript/primary/main.js
index bbf0932..e73923d 100644
--- a/extension/src/entries/contentScript/primary/main.js
+++ b/extension/src/entries/contentScript/primary/main.js
@@ -28,6 +28,13 @@ import localStyle from './style.scss?inline'
import { onLoad } from "../nostr-shim";
import { defer } from "lodash";
+/* FONT AWESOME CONFIG */
+import { library } from '@fortawesome/fontawesome-svg-core'
+import { faCircleInfo } from '@fortawesome/free-solid-svg-icons'
+import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
+
+library.add(faCircleInfo)
+
renderContent([], (appRoot, shadowRoot) => {
//Create the background feature wiring
@@ -38,14 +45,6 @@ renderContent([], (appRoot, shadowRoot) => {
.use(identityPlugin)
.use(originPlugin)
- createApp(App)
- .use(store)
- .use(Notification)
- .mount(appRoot);
-
- //Load the nostr shim
- defer(onLoad)
-
//Add tailwind styles just to the shadow dom element
const style = document.createElement('style')
style.innerHTML = tw.toString()
@@ -55,4 +54,13 @@ renderContent([], (appRoot, shadowRoot) => {
const style2 = document.createElement('style')
style2.innerHTML = localStyle.toString()
shadowRoot.appendChild(style2)
+
+ createApp(App)
+ .use(store)
+ .use(Notification)
+ .component('fa-icon', FontAwesomeIcon)
+ .mount(appRoot);
+
+ //Load the nostr shim
+ defer(onLoad)
}); \ No newline at end of file
diff --git a/extension/src/entries/contentScript/renderContent.js b/extension/src/entries/contentScript/renderContent.js
index 84c5b9f..293bdd5 100644
--- a/extension/src/entries/contentScript/renderContent.js
+++ b/extension/src/entries/contentScript/renderContent.js
@@ -21,9 +21,7 @@ export default async function renderContent(
render = (_appRoot) => {}
) {
const appContainer = document.createElement("div");
- const shadowRoot = appContainer.attachShadow({
- mode: import.meta.env.DEV ? "open" : "closed",
- });
+ const shadowRoot = appContainer.attachShadow({ mode: 'closed' });
const appRoot = document.createElement("div");
if (import.meta.hot) {
diff --git a/extension/src/entries/nostr-provider.js b/extension/src/entries/nostr-provider.js
index 1b8807f..9fa3bb7 100644
--- a/extension/src/entries/nostr-provider.js
+++ b/extension/src/entries/nostr-provider.js
@@ -69,9 +69,8 @@ window.addEventListener('message', ({ data }) => {
window.nostr = {
//Redirect calls to the background script
- async getPublicKey(){
- const { PublicKey } = await sendMessage('getPublicKey', {})
- return PublicKey
+ getPublicKey(){
+ return sendMessage('getPublicKey', {})
} ,
async signEvent(event){
@@ -80,9 +79,8 @@ window.nostr = {
return ev
},
- async getRelays(){
- const { relays } = await sendMessage('getRelays', {})
- return relays
+ getRelays(){
+ return sendMessage('getRelays', {})
},
nip04: {
diff --git a/extension/src/entries/popup/Components/Login.vue b/extension/src/entries/popup/Components/Login.vue
index 44df714..93c0178 100644
--- a/extension/src/entries/popup/Components/Login.vue
+++ b/extension/src/entries/popup/Components/Login.vue
@@ -31,7 +31,7 @@ const token = ref('')
const onSubmit = async () => {
await apiCall(async ({ toaster }) => {
await login(token.value)
- toaster.general.success({
+ toaster.form.success({
'title': 'Login successful',
'text': 'Successfully logged into your profile'
})
diff --git a/extension/src/entries/popup/Components/PageContent.vue b/extension/src/entries/popup/Components/PageContent.vue
index 1a3995e..e4fcb49 100644
--- a/extension/src/entries/popup/Components/PageContent.vue
+++ b/extension/src/entries/popup/Components/PageContent.vue
@@ -19,6 +19,12 @@
<fa-icon icon="arrow-right-from-bracket" />
</button>
</div>
+ <div class="my-auto">
+ <button class="rounded btn xs" @click="toggleDark" >
+ <fa-icon class="w-4" v-if="darkMode" icon="sun"/>
+ <fa-icon class="w-4" v-else icon="moon" />
+ </button>
+ </div>
<div class="my-auto">
<button class="rounded btn xs" @click="openOptions">
<fa-icon :icon="['fas', 'gear']"/>
@@ -106,6 +112,7 @@ const { copy, copied } = useClipboard()
const pubKey = computed(() => selectedKey!.value?.PublicKey)
const openOptions = () => runtime.openOptionsPage();
+const toggleDark = () => store.toggleDarkMode()
//Watch for dark mode changes and update the body class
watchEffect(() => darkMode.value ? document.body.classList.add('dark') : document.body.classList.remove('dark'));
diff --git a/extension/src/entries/popup/main.js b/extension/src/entries/popup/main.js
index a259e63..8b8a3d9 100644
--- a/extension/src/entries/popup/main.js
+++ b/extension/src/entries/popup/main.js
@@ -24,10 +24,10 @@ import "./local.scss"
/* FONT AWESOME CONFIG */
import { library } from '@fortawesome/fontawesome-svg-core'
-import { faArrowRightFromBracket, faCopy, faEdit, faGear, faMinus, faPlus, faSpinner } from '@fortawesome/free-solid-svg-icons'
+import { faArrowRightFromBracket, faCopy, faEdit, faGear, faMinus, faMoon, faPlus, faSpinner, faSun } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
-library.add(faSpinner, faEdit, faGear, faCopy, faArrowRightFromBracket, faPlus, faMinus)
+library.add(faSpinner, faEdit, faGear, faCopy, faArrowRightFromBracket, faPlus, faMinus, faSun, faMoon)
const bgPlugin = useBackgroundPiniaPlugin('popup')
diff --git a/extension/src/entries/store/allowedOrigins.ts b/extension/src/entries/store/allowedOrigins.ts
index 7fc5e15..d6de42d 100644
--- a/extension/src/entries/store/allowedOrigins.ts
+++ b/extension/src/entries/store/allowedOrigins.ts
@@ -2,7 +2,7 @@
import 'pinia'
import { } from 'lodash'
import { PiniaPluginContext } from 'pinia'
-import { computed, ref } from 'vue';
+import { computed, shallowRef } from 'vue';
import { onWatchableChange } from '../../features/types';
import { type AllowedOriginStatus } from '../../features/nip07allow-api';
@@ -22,7 +22,7 @@ declare module 'pinia' {
export const originPlugin = ({ store }: PiniaPluginContext) => {
const { plugins } = store
- const status = ref<AllowedOriginStatus>()
+ const status = shallowRef<AllowedOriginStatus>()
onWatchableChange(plugins.allowedOrigins, async () => {
//Update the status
diff --git a/extension/src/entries/store/features.ts b/extension/src/entries/store/features.ts
index 9bf3052..219386f 100644
--- a/extension/src/entries/store/features.ts
+++ b/extension/src/entries/store/features.ts
@@ -2,10 +2,8 @@
import 'pinia'
import { } from 'lodash'
import { PiniaPluginContext } from 'pinia'
-import { type Tabs, tabs } from 'webextension-polyfill'
import {
- SendMessageHandler,
useAuthApi,
useHistoryApi,
useIdentityApi,
@@ -18,9 +16,8 @@ import {
useInjectAllowList
} from "../../features"
-import { RuntimeContext, createPort } from '../../webext-bridge'
-import { ref } from 'vue'
import { onWatchableChange } from '../../features/types'
+import { ChannelContext } from '../../messaging'
export type BgPlugins = ReturnType<typeof usePlugins>
export type BgPluginState<T> = { plugins: BgPlugins } & T
@@ -28,13 +25,12 @@ export type BgPluginState<T> = { plugins: BgPlugins } & T
declare module 'pinia' {
export interface PiniaCustomProperties {
plugins: BgPlugins
- currentTab: Tabs.Tab | undefined
}
}
-const usePlugins = (sendMessage: SendMessageHandler) => {
+const usePlugins = (context: ChannelContext) => {
//Create plugin wrapping function
- const { use } = useForegoundFeatures(sendMessage)
+ const { use } = useForegoundFeatures(context)
return {
settings: use(useSettingsApi),
@@ -49,14 +45,11 @@ const usePlugins = (sendMessage: SendMessageHandler) => {
}
}
-export const useBackgroundPiniaPlugin = (context: RuntimeContext) => {
+export const useBackgroundPiniaPlugin = (context: ChannelContext) => {
//Create port for context
- const { sendMessage } = createPort(context)
- const plugins = usePlugins(sendMessage)
+ const plugins = usePlugins(context)
const { user } = plugins;
- const currentTab = ref<Tabs.Tab | undefined>(undefined)
-
//Plugin store
return ({ store }: PiniaPluginContext) => {
@@ -71,46 +64,13 @@ export const useBackgroundPiniaPlugin = (context: RuntimeContext) => {
//Wait for settings changes
onWatchableChange(plugins.settings, async () => {
-
//Update settings and dark mode on change
store.settings = await plugins.settings.getSiteConfig();
store.darkMode = await plugins.settings.getDarkMode();
- console.log("Settings changed")
}, { immediate: true })
-
-
- const initTab = async () => {
-
- if(!tabs){
- return;
- }
-
- //Get the current tab
- const [active] = await tabs.query({ active: true, currentWindow: true })
- currentTab.value = active
-
- //Watch for changes to the current tab
- tabs.onUpdated.addListener(async (tabId, changeInfo, tab) => {
- //If the url changed, update the current tab
- if (changeInfo.url) {
- currentTab.value = tab
- }
- })
-
- tabs.onActivated.addListener(async ({ tabId }) => {
- //Get the tab
- const tab = await tabs.get(tabId)
- //Update the current tab
- currentTab.value = tab
- })
- }
-
-
- initTab()
return{
plugins,
- currentTab,
}
}
} \ No newline at end of file
diff --git a/extension/src/entries/store/identity.ts b/extension/src/entries/store/identity.ts
index 58a6b67..320263f 100644
--- a/extension/src/entries/store/identity.ts
+++ b/extension/src/entries/store/identity.ts
@@ -3,7 +3,7 @@ import 'pinia'
import { } from 'lodash'
import { PiniaPluginContext } from 'pinia'
import { NostrPubKey } from '../../features'
-import { ref } from 'vue';
+import { shallowRef } from 'vue';
import { onWatchableChange } from '../../features/types';
declare module 'pinia' {
@@ -22,17 +22,22 @@ export const identityPlugin = ({ store }: PiniaPluginContext) => {
const { identity } = store.plugins
- const allKeys = ref<NostrPubKey[]>([])
- const selectedKey = ref<NostrPubKey | undefined>(undefined)
+ const originalReset = store.$reset.bind(store)
+ const allKeys = shallowRef<NostrPubKey[]>([])
+ const selectedKey = shallowRef<NostrPubKey | undefined>(undefined)
onWatchableChange(identity, async () => {
+ console.log('Identity changed')
allKeys.value = await identity.getAllKeys();
- //Get the current key
selectedKey.value = await identity.getPublicKey();
- console.log('Selected key is now', selectedKey.value)
}, { immediate:true })
return {
+ $reset(){
+ originalReset()
+ allKeys.value = []
+ selectedKey.value = undefined
+ },
selectedKey,
allKeys,
selectKey: identity.selectKey,