Merge pull request #129 from simple-login/ac-require-tabs-on-install

Require tabs permission on install
This commit is contained in:
Son Nguyen Kim
2022-04-28 12:22:25 +02:00
committed by GitHub
9 changed files with 78 additions and 254 deletions
+18 -27
View File
@@ -1,37 +1,28 @@
import browser from "webextension-polyfill";
import { havePermission, addPermissionListener } from "./permissions";
import SLStorage from "../popup/SLStorage";
let hasAlreadySetup = false;
async function setupContentScript() {
if (await havePermission("tabs")) {
if (hasAlreadySetup) return;
hasAlreadySetup = true;
const apiUrl = SLStorage.get(SLStorage.SETTINGS.API_URL);
const apiUrl = SLStorage.get(SLStorage.SETTINGS.API_URL);
browser.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
if (
tab.url.startsWith("chrome") || // chrome internal pages
tab.url.startsWith("about") || // firefox internal pages
tab.url.startsWith("moz") || // firefox internal pages
tab.url.startsWith(apiUrl) // app domain
) {
return;
}
browser.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
if (
tab.url.startsWith("chrome") || // chrome internal pages
tab.url.startsWith("about") || // firefox internal pages
tab.url.startsWith("moz") || // firefox internal pages
tab.url.startsWith(apiUrl) // app domain
) {
return;
}
browser.tabs.executeScript(tabId, {
file: "content_script/input_tools.js",
runAt: "document_idle",
});
browser.tabs.insertCSS(tabId, {
file: "content_script/input_tools.css",
});
browser.tabs.executeScript(tabId, {
file: "content_script/input_tools.js",
runAt: "document_idle",
});
}
browser.tabs.insertCSS(tabId, {
file: "content_script/input_tools.css",
});
});
}
addPermissionListener(setupContentScript);
setupContentScript();
-3
View File
@@ -9,7 +9,6 @@ import {
handleOnClickContextMenu,
generateAliasHandlerJS,
} from "./context-menu";
import { firePermissionListener } from "./permissions";
global.isBackgroundJS = true;
@@ -35,8 +34,6 @@ browser.runtime.onMessage.addListener(async function (request, sender) {
return await handleNewRandomAlias(request.currentUrl);
} else if (request.tag === "GET_APP_SETTINGS") {
return await handleGetAppSettings();
} else if (request.tag === "PERMISSIONS_CHANGED") {
return firePermissionListener();
}
});
-52
View File
@@ -1,52 +0,0 @@
import browser from "webextension-polyfill";
const listeners = [];
/**
* To be used by background.js
* @param {function} callback
*/
function addPermissionListener(callback) {
listeners.push(callback);
}
/**
* To be used by background.js
*/
function firePermissionListener() {
listeners.forEach((callback) => callback());
}
/**
* Can be used by both frontend & background
* @param {string} name name of permission
*/
async function havePermission(name) {
return await browser.permissions.contains({
permissions: [name],
origins: ["http://*/*", "https://*/*"],
});
}
/**
* To be called on frontend (on user interaction)
* @param {string} name name of permission
*/
async function requestPermission(name) {
const result = await browser.permissions.request({
permissions: [name],
origins: ["http://*/*", "https://*/*"],
});
// emit "changed" event to background
if (result) {
browser.runtime.sendMessage({ tag: "PERMISSIONS_CHANGED" });
}
return result;
}
export {
havePermission,
requestPermission,
addPermissionListener,
firePermissionListener,
};
+13 -15
View File
@@ -16,10 +16,8 @@
"storage",
"cookies",
"contextMenus",
"https://*.simplelogin.io/*"
],
"optional_permissions": [
"tabs",
"https://*.simplelogin.io/*",
"http://*/*",
"https://*/*"
],
@@ -38,17 +36,17 @@
]
},
"commands": {
"generate-random-alias": {
"suggested_key": {
"default": "Ctrl+Shift+X"
},
"description": "Generate a random email alias"
},
"_execute_browser_action": {
"suggested_key": {
"default": "Ctrl+Shift+S"
},
"description":"Open the extension action menu"
}
"generate-random-alias": {
"suggested_key": {
"default": "Ctrl+Shift+X"
},
"description": "Generate a random email alias"
},
"_execute_browser_action": {
"suggested_key": {
"default": "Ctrl+Shift+S"
},
"description":"Open the extension action menu"
}
}
}
+23 -101
View File
@@ -4,8 +4,7 @@
<div class="col-3 screen-left">
<div class="left-content">
<p :class="{ active: step === 2 }" @click="toStep(2)">Account</p>
<p :class="{ active: step === 3 }" @click="toStep(3)">Permission</p>
<p :class="{ active: step === 4 }" @click="toStep(4)">Done</p>
<p :class="{ active: step === 3 }" @click="toStep(3)">Done</p>
</div>
</div>
<div class="col-6 screen-right">
@@ -47,72 +46,6 @@
</div>
<div class="content" v-if="step === 3">
<div v-if="isAuthenticated">
<h1 class="h2 text-primary">Welcome {{ userName }}!</h1>
<hr />
</div>
<h5>Extra permission</h5>
<p>
SimpleLogin extension requires the
<b v-if="isChrome"
>Read and change all your data on the websites you visit</b
>
<b v-else
>Access your data for all websites & access browser tabs</b
>
permission.
</p>
<img
v-if="isChrome"
src="../images/chrome-permission-screenshot.png"
style="width: 400px;"
/>
<img
v-else
src="../images/firefox-permission-screenshot.png"
style="width: 400px;"
/>
<p>
Though seemingly scary, the only thing SimpleLogin does is to
detect the email field on a page and display the icon to its
right.
</p>
<img
alt="SimpleLogin Button demo"
src="../images/sl-button-demo.png"
style="width: 400px;"
class="mb-3"
/>
<p>
SimpleLogin code is open-source on
<a
href="https://github.com/simple-login/browser-extension"
target="_blank"
rel="noopener noreferrer"
>GitHub</a
>
if you want to know about what's going behind the scenes.
</p>
<br />
<button @click="askTabsPermission()" class="btn btn-primary">
Approve access permission
</button>
<button
@click="nextStep()"
class="btn"
style="color: #888; font-size: 0.8em;"
>
Skip
</button>
</div>
<div class="content" v-if="step === 4">
<h5>It's all set!</h5>
<p>
To start using SimpleLogin, please click on
@@ -148,7 +81,6 @@
</template>
<script>
import { requestPermission } from "../background/permissions";
import SLStorage from "../popup/SLStorage";
import axios from "axios";
import { API_ROUTE } from "../popup/APIService";
@@ -175,15 +107,15 @@ export default {
this.url.createNewAccount = `${apiUrl}/auth/register?next=%2Fdashboard%2Fsetup_done`;
this.url.login = `${apiUrl}/dashboard/setup_done`;
// maybe user redirected from the setup_done page
if (this.step === 3) {
await this.tryGetUserInfo();
}
//Show first step while the request is being executed
setTimeout(async () => {
if (await this.tryGetUserInfo()) {
this.step = 3;
}
}, 1);
// update setup step
const self = this;
const updateStep = function () {
self.step = window.location.href.match(/#step3/) ? 3 : 1;
const updateStep = () => {
this.step = window.location.href.match(/#step3/) ? 3 : 1;
};
window.addEventListener("hashchange", updateStep, false);
updateStep();
@@ -195,34 +127,24 @@ export default {
nextStep() {
this.step = this.step + 1;
},
async askTabsPermission() {
if (await requestPermission("tabs")) {
this.nextStep();
} else {
alert(
"Please approve permissions. If you don't want to approve, please click Skip button."
);
}
},
async tryGetUserInfo() {
const apiUrl = await SLStorage.get(SLStorage.SETTINGS.API_URL);
const that = this;
// check api key
axios
.get(apiUrl + API_ROUTE.GET_USER_INFO.path, {
headers: { Authentication: this.apiKey },
})
.then(async (res) => {
that.userName = res.data.name || res.data.email;
that.isAuthenticated = true;
try {
// check api key
const response = await axios.get(
apiUrl + API_ROUTE.GET_USER_INFO.path,
{ headers: { Authentication: this.apiKey } }
);
this.userName = response.data.name || response.data.email;
this.isAuthenticated = true;
await SLStorage.set(SLStorage.SETTINGS.API_KEY, this.apiKey);
EventManager.broadcast(EventManager.EVENT.SETTINGS_CHANGED);
})
.catch((err) => {
// user isn't authenticated, ignore
});
await SLStorage.set(SLStorage.SETTINGS.API_KEY, this.apiKey);
EventManager.broadcast(EventManager.EVENT.SETTINGS_CHANGED);
return true;
} catch (err) {
return false;
}
},
},
};
+7 -39
View File
@@ -3,8 +3,8 @@
<div class="p-3 container">
<p class="font-weight-bold align-self-center">App Settings</p>
<table class="settings-list" v-if="isSettingsFetched">
<tr :class="{ disabled: !hasTabsPermission }">
<table class="settings-list">
<tr>
<td>
<toggle-button
:value="showSLButton"
@@ -31,16 +31,6 @@
</td>
</tr>
<tr v-if="!hasTabsPermission">
<td></td>
<td>
SimpleLogin button requires extra permission<br />
<span class="link cursor" @click="askTabsPermission()">
Click here to grant access
</span>
</td>
</tr>
<tr v-show="showSLButton">
<td>
<toggle-button
@@ -74,47 +64,31 @@
</template>
<script>
import axios from "axios";
import SLStorage from "../SLStorage";
import EventManager from "../EventManager";
import Navigation from "../Navigation";
import Utils from "../Utils";
import { callAPI, API_ROUTE, API_ON_ERR } from "../APIService";
import {
havePermission,
requestPermission,
} from "../../background/permissions";
export default {
data() {
return {
isSettingsFetched: false,
hasTabsPermission: false,
showSLButton: false,
positionSLButton: "right-inside",
reportURISLButton: "",
};
},
async mounted() {
this.fetchSettings();
this.showSLButton = await SLStorage.get(SLStorage.SETTINGS.SHOW_SL_BUTTON);
this.positionSLButton = await SLStorage.get(
SLStorage.SETTINGS.SL_BUTTON_POSITION
);
await this.setMailToUri();
},
methods: {
async fetchSettings() {
this.hasTabsPermission = await havePermission("tabs");
this.showSLButton = this.hasTabsPermission
? await SLStorage.get(SLStorage.SETTINGS.SHOW_SL_BUTTON)
: false;
this.positionSLButton = await SLStorage.get(
SLStorage.SETTINGS.SL_BUTTON_POSITION
);
await this.setMailToUri();
this.isSettingsFetched = true;
},
async handleToggleSLButton() {
this.showSLButton = !this.showSLButton;
await SLStorage.set(SLStorage.SETTINGS.SHOW_SL_BUTTON, this.showSLButton);
this.fetchSettings();
this.showSavedSettingsToast();
},
@@ -135,12 +109,6 @@ export default {
Utils.showSuccess("Settings saved");
},
async askTabsPermission() {
if (await requestPermission("tabs")) {
this.fetchSettings();
}
},
async handleLogout() {
await callAPI(API_ROUTE.LOGOUT, {}, {}, API_ON_ERR.IGNORE);
await SLStorage.remove(SLStorage.SETTINGS.API_KEY);
+11 -12
View File
@@ -15,15 +15,15 @@
v-clipboard:error="clipboardErrorHandler"
class="cursor"
>
<span class="text-success recommended-alias">{{ recommendation.alias }}</span>
<span class="text-success recommended-alias">{{
recommendation.alias
}}</span>
</a>
</div>
<hr />
</div>
<div>
<form @submit.prevent="createCustomAlias">
<div class="row mb-2">
@@ -88,10 +88,10 @@
<hr />
<div class="text-center">
<button
:disabled="loading || !canCreate"
style="margin-left: 15px;"
class="btn btn-outline-primary btn-sm"
@click="createRandomAlias"
:disabled="loading || !canCreate"
style="margin-left: 15px;"
class="btn btn-outline-primary btn-sm"
@click="createRandomAlias"
>
<font-awesome-icon icon="random" /> OR create a totally random alias
</button>
@@ -142,7 +142,6 @@
v-clipboard="() => alias.email"
v-clipboard:success="clipboardSuccessHandler"
v-clipboard:error="clipboardErrorHandler"
>
<a class="cursor" v-b-tooltip.hover.top="'Click to Copy'">
{{ alias.email }}
@@ -220,7 +219,7 @@ import EventManager from "../EventManager";
import Navigation from "../Navigation";
import AliasMoreOptions from "./AliasMoreOptions";
import { callAPI, API_ROUTE, API_ON_ERR } from "../APIService";
import tippy from 'tippy.js';
import tippy from "tippy.js";
const ALIAS_PREFIX_REGEX = /^[0-9a-z-_.]+$/;
@@ -296,9 +295,9 @@ export default {
await this.loadAlias();
tippy('.recommended-alias', {
content: 'Click to copy',
placement: 'bottom',
tippy(".recommended-alias", {
content: "Click to copy",
placement: "bottom",
});
},
+4 -4
View File
@@ -56,7 +56,7 @@ import EventManager from "../EventManager";
import Utils from "../Utils";
import AliasMoreOptions from "./AliasMoreOptions";
import { callAPI, API_ROUTE, API_ON_ERR } from "../APIService";
import tippy from 'tippy.js';
import tippy from "tippy.js";
export default {
components: {
@@ -77,9 +77,9 @@ export default {
// TODO showVoteScreen 1 day after user installed plugin
else this.showVoteScreen = Utils.getRandomIntBetween(0, 10) % 2 === 0;
tippy('.new-alias', {
content: 'Click to copy',
trigger: 'manual',
tippy(".new-alias", {
content: "Click to copy",
trigger: "manual",
showOnCreate: true,
});
},
+2 -1
View File
@@ -60,7 +60,8 @@ async function initApp() {
process.env.NODE_ENV !== "development"
) {
Sentry.init({
dsn: "https://0e2d03e61f194df9ba85a791d364088b@o336535.ingest.sentry.io/5341174",
dsn:
"https://0e2d03e61f194df9ba85a791d364088b@o336535.ingest.sentry.io/5341174",
integrations: [
new Integrations.Vue({ Vue, attachProps: true, logErrors: true }),
],