diff options
author | vnugent <public@vaughnnugent.com> | 2023-11-22 02:21:53 -0500 |
---|---|---|
committer | vnugent <public@vaughnnugent.com> | 2023-11-22 02:21:53 -0500 |
commit | 2ba94602a87c87b47f566745bdab40ce75e0e879 (patch) | |
tree | 396cb9c6d73d6bfb4e4b2d4fb440d7656fe493e0 /extension/src/entries | |
parent | 43429314c0989b423e116be3e9f222eba5b636c3 (diff) |
latest patches, remove webext-bridge, lastest vnlib.browser
Diffstat (limited to 'extension/src/entries')
-rw-r--r-- | extension/src/entries/contentScript/nostr-shim.js | 49 | ||||
-rw-r--r-- | extension/src/entries/contentScript/primary/components/PromptPopup.vue | 127 | ||||
-rw-r--r-- | extension/src/entries/contentScript/primary/main.js | 24 | ||||
-rw-r--r-- | extension/src/entries/contentScript/renderContent.js | 4 | ||||
-rw-r--r-- | extension/src/entries/nostr-provider.js | 10 | ||||
-rw-r--r-- | extension/src/entries/popup/Components/Login.vue | 2 | ||||
-rw-r--r-- | extension/src/entries/popup/Components/PageContent.vue | 7 | ||||
-rw-r--r-- | extension/src/entries/popup/main.js | 4 | ||||
-rw-r--r-- | extension/src/entries/store/allowedOrigins.ts | 4 | ||||
-rw-r--r-- | extension/src/entries/store/features.ts | 50 | ||||
-rw-r--r-- | extension/src/entries/store/identity.ts | 15 |
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, |