Skip to content

add permissions management #827

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jan 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions _locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -445,5 +445,59 @@
},
"no_entires": {
"message": "No accounts to display. Add your first account now."
},
"permissions": {
"message": "Permissions"
},
"permission_revoke": {
"message": "Revoke"
},
"permission_show_required_permissions": {
"message": "Show non-revocable permissions"
},
"permission_required": {
"message": "This is a required permission and cannot be revoked."
},
"permission_active_tab": {
"message": "Access to the current tab to scan QR codes."
},
"permission_storage": {
"message": "Access to browser storage to store account data."
},
"permission_identity": {
"message": "Allows sign in to 3rd party storage services."
},
"permission_clipboard_write": {
"message": "Grants write-only access to the clipboard to copy codes to clipboard when you click on the account."
},
"permission_context_menus": {
"message": "Adds Authenticator to context menu."
},
"permission_all_urls": {
"message": "Access to all websites to scan QR codes."
},
"permission_sync_clock": {
"message": "Allows clock sync with Google."
},
"permission_dropbox": {
"message": "Allows backup to Dropbox."
},
"permission_dropbox_cannot_revoke": {
"message": "You must disable Dropbox backup first."
},
"permission_drive": {
"message": "Allows backup to Google Drive."
},
"permission_drive_cannot_revoke": {
"message": "You must disable Google Drive backup first."
},
"permission_onedrive": {
"message": "Allows backup to OneDrive."
},
"permission_onedrive_cannot_revoke": {
"message": "You must disable OneDrive backup first."
},
"permission_unknown_permission": {
"message": "Unknown permission. If see this message, please send a bug report."
}
}
43 changes: 43 additions & 0 deletions sass/permissions.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
@import "ui";

[v-cloak] {
display: none;
}

* {
font-family: arial, "Microsoft YaHei";
}

p {
font-size: 16px;
}

#permissions {
width: 900px;
position: relative;
margin: 0 auto;
}

h2 {
margin-top: 3em;
}

button {
display: inline-grid;
padding: 10px 20px;
border: #ccc 1px solid;
background: white;
border-radius: 2px;
position: relative;
text-align: center;
align-items: center;
font-size: 16px;
color: gray;
cursor: pointer;
outline: none;
margin-left: 0px !important;

&:not(:disabled):hover {
color: black;
}
}
53 changes: 53 additions & 0 deletions src/components/Permissions.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<template>
<div id="permissions" class="theme-normal">
<h1>Permissions</h1>
<div>
<input
type="checkbox"
id="showRequiredPermission"
v-model="showAllPermissions"
/>
<label for="showRequiredPermission">{{
i18n.permission_show_required_permissions
}}</label>
</div>
<div v-for="permission in permissions" :key="permission.id">
<h2>{{ permission.id }}</h2>
<p>{{ permission.description }}</p>
<p v-if="!permission.revocable">{{ i18n.permission_required }}</p>
<button
:disabled="!permission.revocable"
v-if="permission.revocable"
v-on:click="revoke(permission.id)"
>
{{ i18n.permission_revoke }}
</button>
</div>
</div>
</template>
<script lang="ts">
import Vue from "vue";
import { Permission } from "../models/permission";

export default Vue.extend({
computed: {
permissions: function () {
return this.$store.state.permissions.permissions.filter(
(permission: Permission) => {
return this.showAllPermissions || permission.revocable;
}
);
},
},
data: function () {
return {
showAllPermissions: false,
};
},
methods: {
revoke(permissionId: string) {
this.$store.commit("permissions/revokePermission", permissionId);
},
},
});
</script>
25 changes: 17 additions & 8 deletions src/components/Popup/MenuPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,16 @@
</div>
<div id="menuBody">
<div class="menuList">
<a href="licenses.html" target="_blank" style="text-decoration: none">
<p v-bind:title="i18n.about">
<span><IconInfo /></span>{{ i18n.about }}
<p v-bind:title="i18n.advisor" v-on:click="showInfo('AdvisorPage')">
<span><IconAdvisor /></span>{{ i18n.advisor }}
</p>
<a
href="permissions.html"
target="_blank"
style="text-decoration: none"
>
<p v-bind:title="i18n.permissions">
<span><IconClipboardCheck /></span>{{ i18n.permissions }}
</p>
</a>
</div>
Expand All @@ -34,11 +41,6 @@
<span><IconWrench /></span>{{ i18n.resize_popup_page }}
</p>
</div>
<div class="menuList">
<p v-bind:title="i18n.advisor" v-on:click="showInfo('AdvisorPage')">
<span><IconAdvisor /></span>{{ i18n.advisor }}
</p>
</div>
<div class="menuList">
<p v-bind:title="i18n.feedback" v-on:click="openHelp()">
<span><IconComments /></span>{{ i18n.feedback }}
Expand All @@ -55,6 +57,11 @@
>
<span><IconCode /></span>{{ i18n.source }}
</p>
<a href="licenses.html" target="_blank" style="text-decoration: none">
<p v-bind:title="i18n.about">
<span><IconInfo /></span>{{ i18n.about }}
</p>
</a>
</div>
<div id="version">Version {{ version }}</div>
</div>
Expand All @@ -75,6 +82,7 @@ import IconAdvisor from "../../../svg/lightbulb.svg";
import IconComments from "../../../svg/comments.svg";
import IconGlobe from "../../../svg/globe.svg";
import IconCode from "../../../svg/code.svg";
import IconClipboardCheck from "../../../svg/clipboard-check.svg";

export default Vue.extend({
components: {
Expand All @@ -89,6 +97,7 @@ export default Vue.extend({
IconComments,
IconGlobe,
IconCode,
IconClipboardCheck,
},
computed: {
version: function () {
Expand Down
4 changes: 4 additions & 0 deletions src/definitions/module-interface.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,7 @@ interface AdvisorState {
insights: AdvisorInsightInterface[];
ignoreList: string[];
}

interface PermissionsState {
permissions: PermissionInterface[];
}
11 changes: 11 additions & 0 deletions src/definitions/permission.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
interface ValidationResult {
valid: boolean;
message?: string;
}

interface PermissionInterface {
id: string;
description: string;
revocable: boolean;
validation?: Array<() => ValidationResult>;
}
13 changes: 13 additions & 0 deletions src/models/permission.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export class Permission implements PermissionInterface {
id: string;
description: string;
revocable: boolean;
validation?: Array<() => ValidationResult>;

constructor(permission: PermissionInterface) {
this.id = permission.id;
this.description = permission.description;
this.revocable = permission.revocable;
this.validation = permission.validation;
}
}
45 changes: 45 additions & 0 deletions src/permissions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Vue
import Vue from "vue";
import Vuex from "vuex";

// Components
import PermissionsView from "./components/Permissions.vue";
import CommonComponents from "./components/common/index";

// Other
import { loadI18nMessages } from "./store/i18n";
import { Permissions } from "./store/Permissions";

async function init() {
// i18n
Vue.prototype.i18n = await loadI18nMessages();

// Load modules
Vue.use(Vuex);

// Load common components globally
for (const component of CommonComponents) {
Vue.component(component.name, component.component);
}

// State
const store = new Vuex.Store({
modules: {
permissions: await new Permissions().getModule(),
},
});

const instance = new Vue({
render: (h) => h(PermissionsView),
store,
}).$mount("#permissions");

// Set title
try {
document.title = instance.i18n.extName;
} catch (e) {
console.error(e);
}
}

init();
Loading