diff --git a/package.json b/package.json index 58ec5ed..44df8ff 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "passwall-extension", - "version": "1.0.2", + "version": "1.0.3", "private": true, "scripts": { "serve": "vue-cli-service build --mode development --watch", diff --git a/public/options-page.html b/public/options-page.html new file mode 100644 index 0000000..46553cc --- /dev/null +++ b/public/options-page.html @@ -0,0 +1,12 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="UTF-8" /> + <meta http-equiv="X-UA-Compatible" content="IE=edge" /> + <meta name="viewport" content="width=device-width,initial-scale=1.0" /> + <title><%= htmlWebpackPlugin.options.title %></title> + </head> + <body> + <div id="app"></div> + </body> +</html> diff --git a/src/background.js b/src/background.js index a7690ee..a6c791f 100644 --- a/src/background.js +++ b/src/background.js @@ -1,6 +1,67 @@ const browser = require('webextension-polyfill') -browser.runtime.onMessage.addListener(function(request, sender, sendResponse) { - console.log('Hello from the background') - console.log(browser) -}) +/* // Login Hashmap +let loginHashmap = new Map() + +// Listener +browser.runtime.onMessage.addListener(handleMessage); + +// Handler +function handleMessage(request, sender, sendResponse) { + let status = "No new record" + + // Create new record + if ((typeof request.username !== 'undefined') && (typeof request.password !== 'undefined')) { + + let url = domainFromUrl(sender.tab.url); + let key = url + ":" + request.username; + + if (!loginHashmap.has(key)) { + loginHashmap.set(key, { + title: sender.tab.title, + url: url, + username: request.username, + password: request.password, + }); + status = "New record added"; + } + } + + sendResponse({ + response: status, + }); +} + +//onUpdated listener fired when a tab URL is changed +browser.tabs.onUpdated.addListener(handleUpdated); + +function handleUpdated(tabId, changeInfo, tabInfo) { + + let url = domainFromUrl(tabInfo.url); + console.log(url); + + // Bu üçü de sistemde yoksa yeni login aç + // url : sender.tab.url, + // username: request.username, + // password: request.password, + + // Bu üçü de sistemde var ve aynıysa hiç popup çıkarma + + // url ve username ayni ve parola farkliysa update olmali + + + + if (tabInfo.active) { + // console.log(`handleUpdates : ${tabInfo.url}`); + } + + // if (loginHashmap.has(tabInfo.url)) { + // console.log(loginHashmap.get(tabInfo.url)) + // } +} + +function domainFromUrl(url) { + const matches = url.match(/^(?:https?:)?(?:\/\/)?([^\/\?]+)/i) + return matches ? matches[1] : 'NONE' +} */ + diff --git a/src/components/VTextArea.vue b/src/components/VTextArea.vue index 10eb0fb..f6daecb 100644 --- a/src/components/VTextArea.vue +++ b/src/components/VTextArea.vue @@ -1,8 +1,20 @@ <template> <div class="text-area-wrapper"> - <label v-if="label" class="title">{{ label }}</label> + <div class="d-flex"> + <label v-if="label" class="title">{{ label }}</label> + <!-- Copy button goes here --> + <ClipboardButton :copy="value"></ClipboardButton> + <!-- Show/Hide button goes here --> + <button + type="button" + @click="showNote = !showNote" + class="detail-page-header-icon ml-2" + v-tooltip="$t(showNote ? 'Hide' : 'Show')"> + <VIcon :name="showNote ? 'eye-off' : 'eye'" size="20px" /> + </button> + </div> <textarea - :value="sensitive ? '●●●●●●' : value" + :value="showNote || isEditable ? value : '●●●●●●'" autocorrect="off" autocomplete="off" spellcheck="false" @@ -17,23 +29,28 @@ <script> export default { name: 'VTextArea', - props: { name: String, value: String, - sensitive: Boolean, + isEditable: Boolean, label: { type: String, default: '' } }, - + data() { + return { + showNote: false + } + }, computed: { getError() { const error = this.errors.items.find(e => e.field == this.name) return error ? error.msg : '' }, - + hiddenNote() { + return this.note.replaceAll("","*"); + }, inputListeners() { return Object.assign({}, this.$listeners, { input: event => this.$emit('input', event.target.value) diff --git a/src/content-scripts/content-script.js b/src/content-scripts/content-script.js index baaecbc..f3c0d5d 100644 --- a/src/content-scripts/content-script.js +++ b/src/content-scripts/content-script.js @@ -1,4 +1,46 @@ const browser = require('webextension-polyfill') -console.log('Hello from the content-script') -console.log(browser) +// CATCHER +let inputs = document.querySelectorAll('input'), i; +let username = ""; +let password = ""; + +for (i = 0; i < inputs.length; ++i) { + + // Find password + if (inputs[i].type === "password") { + password = inputs[i]; + + // Find username. Check type against type hidden or checkbox etc. + for (var k = i; k >= 0; k--) { + if (inputs[k].type == "text") { + username = inputs[k]; + break; + } + } + } +} + +// Listen and send data to fill hashmap in the background +/* if (password !== "" && username !== "") { + password.addEventListener('blur', function () { + let login = browser.runtime.sendMessage({ + username: username.value, + password: password.value, + }); + login.then(handleResponse, handleError); + }); +} + +function handleResponse(message) { console.log(`Response: ${message.response}`); } +function handleError(error) { console.log(`Error: ${error}`); } */ + +// FILLER +// Sender is in /src/popup/views/Logins/detail.vue +browser.runtime.onMessage.addListener((request, sender) => { + username.style.borderColor = "#5707FF"; + password.style.borderColor = "#5707FF"; + + username.value = request.msg.username; + password.value = request.msg.password; +}); \ No newline at end of file diff --git a/src/manifest.json b/src/manifest.json index b0aff0a..014a20b 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -14,6 +14,7 @@ "scripts": ["js/background.js"], "persistent": true }, + "options_page": "options.html", "content_scripts": [ { "matches": ["*://*/**"], diff --git a/src/options/App.vue b/src/options/App.vue new file mode 100644 index 0000000..a82c3a0 --- /dev/null +++ b/src/options/App.vue @@ -0,0 +1,19 @@ +<template> + <h1>options page</h1> +</template> + +<script> +export default { + created() { + this.$storage.getItem('email').then(console.log) + } +} +</script> + +<style lang="scss"> +html, +body { + background-color: $color-gray-500; + scrollbar-width: none; /* Firefox */ +} +</style> diff --git a/src/options/main.js b/src/options/main.js new file mode 100644 index 0000000..5eb30b9 --- /dev/null +++ b/src/options/main.js @@ -0,0 +1,13 @@ +import Vue from 'vue' +import App from './App.vue' + +import '../styles/app.scss' + +import storage from '@/utils/storage' +Vue.prototype.$storage = storage + +/* eslint-disable no-new */ +new Vue({ + el: '#app', + render: h => h(App) +}) diff --git a/src/popup/store/index.js b/src/popup/store/index.js index fc0be28..442fe0f 100644 --- a/src/popup/store/index.js +++ b/src/popup/store/index.js @@ -29,7 +29,7 @@ export default new Vuex.Store({ }, getters: { hasProPlan(state) { - return state.user.status == 'active' + return state.user.type == 'pro' } }, diff --git a/src/popup/views/Home/index.vue b/src/popup/views/Home/index.vue index 007ac44..71da9fd 100644 --- a/src/popup/views/Home/index.vue +++ b/src/popup/views/Home/index.vue @@ -8,20 +8,24 @@ v-if="!hasProPlan" @click="goUpgrade" > - <VIcon name="upgrade" size="24px" class="mr-2" /> - <span class="fs-x-big">Upgrade</span> + <VIcon name="upgrade" size="16px" class="mr-2" /> + <span class="fs-big">Upgrade Subscription</span> </div> <div class="c-pointer my-2 d-flex flex-items-center mb-4" v-if="hasProPlan" @click="goUpdate" > - <VIcon name="refresh" size="24px" class="mr-2" /> - <span class="fs-x-big">Update</span> + <VIcon name="refresh" size="16px" class="mr-2" /> + <span class="fs-big">Update Subscription</span> </div> - <div class="c-pointer my-2 d-flex flex-items-center mb-4" @click="goCancel"> - <VIcon name="cross" size="24px" class="mr-2" /> - <span class="fs-x-big">Cancel</span> + <div + class="c-pointer my-2 d-flex flex-items-center mb-4" + v-if="hasProPlan" + @click="goCancel" + > + <VIcon name="cross" size="16px" class="mr-2" /> + <span class="fs-big">Cancel Subscription</span> </div> <div class="bg-black w-100" style="height: 1px" /> <div @@ -30,7 +34,7 @@ @click="logout" > <VIcon name="logout" size="24px" class="mr-2" /> - <span class="fs-x-big">Log out</span> + <span class="fs-big">Log out</span> </div> </div> </div> diff --git a/src/popup/views/Home/tabs.vue b/src/popup/views/Home/tabs.vue index a7e030c..a7035de 100644 --- a/src/popup/views/Home/tabs.vue +++ b/src/popup/views/Home/tabs.vue @@ -34,11 +34,22 @@ </template> <script> +import { mapGetters } from 'vuex' + export default { name: 'Tabs', + computed: { + ...mapGetters(['hasProPlan']) + }, methods: { switchTabs(name) { - this.$router.replace({ name }) + if (!this.hasProPlan) { + if (name === "Logins") { + this.$router.replace({ name }) + } + } else { + this.$router.replace({ name }) + } }, getColor(name) { return this.$route.name === name diff --git a/src/popup/views/Logins/create.vue b/src/popup/views/Logins/create.vue index b587fd0..6a3ab39 100644 --- a/src/popup/views/Logins/create.vue +++ b/src/popup/views/Logins/create.vue @@ -80,6 +80,7 @@ v-model="form.extra" label="Extra" name="extra" + isEditable /> </div> diff --git a/src/popup/views/Logins/detail.vue b/src/popup/views/Logins/detail.vue index bfa4afa..6c905ec 100644 --- a/src/popup/views/Logins/detail.vue +++ b/src/popup/views/Logins/detail.vue @@ -20,6 +20,11 @@ <button v-if="!isEditMode" v-tooltip="$t('Edit')" @click="isEditMode = true"> <VIcon class="c-pointer ml-2 cogs" name="cogs" /> </button> + + <!-- Fill Btn --> + <button v-if="!isEditMode" v-tooltip="$t('Fill')" @click="fillForm"> + <VIcon class="c-pointer ml-2 plus" name="plus" /> + </button> </div> </div> </template> @@ -128,6 +133,24 @@ export default { await this.$request(onSuccess, this.$waiters.Logins.Update) this.isEditMode = false + }, + + fillForm() { + this.$browser.tabs.query({ active: true, currentWindow: true }).then(tabs => { + this.$browser.tabs + .sendMessage(tabs[0].id, { + msg: { + username: this.form.username, + password: this.form.password, + } + }) + .then(() => { + console.log("Form data sent successfully") + }) + .catch((error) => { + console.error('Can not send form data Error: ', error); + }); + }); } }, computed: { diff --git a/src/popup/views/Notes/create.vue b/src/popup/views/Notes/create.vue index 320840b..b336a30 100644 --- a/src/popup/views/Notes/create.vue +++ b/src/popup/views/Notes/create.vue @@ -29,11 +29,12 @@ </div> <div> - <VTextArea - :placeholder="$t('ClickToFill')" - v-model="form.note" - label="Note" - name="note" + <VTextArea + :placeholder="$t('ClickToFill')" + v-model="form.note" + label="Note" + name="note" + isEditable /> </div> diff --git a/src/popup/views/Notes/detail.vue b/src/popup/views/Notes/detail.vue index f51b309..4cfa29e 100644 --- a/src/popup/views/Notes/detail.vue +++ b/src/popup/views/Notes/detail.vue @@ -24,12 +24,19 @@ </Header> <div class="scroll detail"> <form class="form" @submit.stop.prevent="onClickUpdate"> - <FormRowText v-model="form.title" title="title" :edit-mode="isEditMode" :show-icons="false"> - <template v-slot:second-icon> <div /> </template> - </FormRowText> - - <div> + <div class="d-flex flex-content-between"> + <FormRowText + v-model="form.title" + title="title" + :edit-mode="isEditMode" + :show-icons="false" + > + <template v-slot:second-icon> <div /> </template> + </FormRowText> + </div> + <div class="d-flex"> <VTextArea + :isEditable="isEditMode" v-model="form.note" label="Note" name="note" @@ -69,6 +76,7 @@ export default { beforeRouteUpdate(to, from, next) { this.isEditMode = false this.showPass = false + next() }, diff --git a/src/popup/views/Servers/create.vue b/src/popup/views/Servers/create.vue index e0b98bc..857e228 100644 --- a/src/popup/views/Servers/create.vue +++ b/src/popup/views/Servers/create.vue @@ -158,7 +158,8 @@ :placeholder="$t('ClickToFill')" v-model="form.extra" label="Extra" - name="extra" + name="extra" + isEditable /> </div> diff --git a/vue.config.js b/vue.config.js index 6a898b1..bb08499 100644 --- a/vue.config.js +++ b/vue.config.js @@ -4,6 +4,11 @@ module.exports = { template: 'public/browser-extension.html', entry: './src/popup/main.js', title: 'Popup' + }, + options: { + template: 'public/options-page.htm', + entry: 'src/options/main.js', + title: 'Passwall Extension Options' } }, css: {