mirror of
https://github.com/FreeTubeApp/FreeTube
synced 2025-01-23 18:21:00 +01:00
Password protect settings (#2932)
* Hide unsubscribe button on channel list if this is set in parental controls. * Fix github linting errors * Removed trailing whitespace. * Reverted yarn.lock change * Remove package-lock.json * Added support for password protecting settings. * Push password handling code inside password-settings component. * Added incorrect password message * Replace update method with watch. * Use updateSettingsPassword to commit value to database. * Move password settings to the bottom (review comment) * Moved unlock into separate component (review feedback) * Styling password dialog * Removed incorrect (and unused) prop value - review comment. * Removed unused component imports Co-authored-by: Simon Epstein <simon.epstein@67bricks.com>
This commit is contained in:
parent
79cd65c312
commit
dbb54737c4
@ -8,6 +8,11 @@ export default Vue.extend({
|
||||
'ft-tooltip': FtTooltip
|
||||
},
|
||||
props: {
|
||||
inputType: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'text'
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
required: true
|
||||
@ -97,6 +102,11 @@ export default Vue.extend({
|
||||
if (val !== oldVal) {
|
||||
this.updateVisibleDataList()
|
||||
}
|
||||
},
|
||||
value(val, oldVal) {
|
||||
if (val !== oldVal) {
|
||||
this.inputData = val
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted: function () {
|
||||
@ -264,6 +274,10 @@ export default Vue.extend({
|
||||
this.inputData = text
|
||||
},
|
||||
|
||||
focus() {
|
||||
this.$refs.input.focus()
|
||||
},
|
||||
|
||||
...mapActions([
|
||||
'getYoutubeUrlInfo'
|
||||
])
|
||||
|
@ -43,7 +43,7 @@
|
||||
v-model="inputData"
|
||||
:list="idDataList"
|
||||
class="ft-input"
|
||||
type="text"
|
||||
:type="inputType"
|
||||
:placeholder="placeholder"
|
||||
:disabled="disabled"
|
||||
:spellcheck="spellcheck"
|
||||
|
10
src/renderer/components/password-dialog/password-dialog.css
Normal file
10
src/renderer/components/password-dialog/password-dialog.css
Normal file
@ -0,0 +1,10 @@
|
||||
.card {
|
||||
position: relative;
|
||||
width: 85%;
|
||||
height: 25%;
|
||||
margin: auto;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.passwordInput {
|
||||
width: 100%;
|
||||
}
|
58
src/renderer/components/password-dialog/password-dialog.js
Normal file
58
src/renderer/components/password-dialog/password-dialog.js
Normal file
@ -0,0 +1,58 @@
|
||||
import Vue from 'vue'
|
||||
import { mapActions } from 'vuex'
|
||||
import FtCard from '../ft-card/ft-card.vue'
|
||||
import FtInput from '../ft-input/ft-input.vue'
|
||||
import FtFlexBox from '../ft-flex-box/ft-flex-box.vue'
|
||||
import FtPrompt from '../ft-prompt/ft-prompt.vue'
|
||||
|
||||
export default Vue.extend({
|
||||
name: 'PasswordDialog',
|
||||
components: {
|
||||
'ft-input': FtInput,
|
||||
'ft-card': FtCard,
|
||||
'ft-flex-box': FtFlexBox,
|
||||
'ft-prompt': FtPrompt,
|
||||
},
|
||||
emits: ['settingsUnlocked'],
|
||||
data: function() {
|
||||
return {
|
||||
password: '',
|
||||
showIncorrectPassword: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
getStoredPassword: function() {
|
||||
return this.$store.getters.getSettingsPassword
|
||||
},
|
||||
incorrectPassword: function() {
|
||||
return this.password !== '' && !this.unlocked
|
||||
},
|
||||
unlocked: function() {
|
||||
return this.getStoredPassword === '' || this.password === this.getStoredPassword
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
unlocked(val, oldVal) {
|
||||
if (val !== oldVal) {
|
||||
this.propagateUnlockStatus()
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted: function () {
|
||||
this.propagateUnlockStatus()
|
||||
this.$refs.password.focus()
|
||||
},
|
||||
methods: {
|
||||
handleLock: function () {
|
||||
this.password = ''
|
||||
this.showIncorrectPassword = false
|
||||
},
|
||||
propagateUnlockStatus: function() {
|
||||
this.$emit('settingsUnlocked', this.unlocked)
|
||||
},
|
||||
...mapActions([
|
||||
'updateSettingsPassword'
|
||||
]),
|
||||
|
||||
}
|
||||
})
|
31
src/renderer/components/password-dialog/password-dialog.vue
Normal file
31
src/renderer/components/password-dialog/password-dialog.vue
Normal file
@ -0,0 +1,31 @@
|
||||
<template>
|
||||
<div>
|
||||
<ft-card
|
||||
class="card"
|
||||
>
|
||||
<h3>{{ $t("Settings.Password Dialog.Enter Password To Unlock") }}</h3>
|
||||
|
||||
<ft-flex-box>
|
||||
<ft-input
|
||||
ref="password"
|
||||
:placeholder="$t('Settings.Password Dialog.Password')"
|
||||
:show-action-button="false"
|
||||
input-type="password"
|
||||
class="passwordInput"
|
||||
:value="password"
|
||||
@input="e => password = e"
|
||||
/>
|
||||
</ft-flex-box>
|
||||
<ft-prompt
|
||||
v-if="showIncorrectPassword"
|
||||
:label="$t('Settings.Password Dialog.Password Incorrect')"
|
||||
:option-names="[$t('Ok')]"
|
||||
:option-values="['ok']"
|
||||
@click="handleLock"
|
||||
/>
|
||||
</ft-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./password-dialog.js" />
|
||||
<style scoped src="./password-dialog.css" />
|
@ -0,0 +1,58 @@
|
||||
import Vue from 'vue'
|
||||
import { mapActions } from 'vuex'
|
||||
import FtSettingsSection from '../ft-settings-section/ft-settings-section.vue'
|
||||
import FtInput from '../ft-input/ft-input.vue'
|
||||
import FtFlexBox from '../ft-flex-box/ft-flex-box.vue'
|
||||
import FtButton from '../ft-button/ft-button.vue'
|
||||
|
||||
export default Vue.extend({
|
||||
name: 'PasswordSettings',
|
||||
components: {
|
||||
'ft-settings-section': FtSettingsSection,
|
||||
'ft-input': FtInput,
|
||||
'ft-flex-box': FtFlexBox,
|
||||
'ft-button': FtButton,
|
||||
},
|
||||
emits: ['settingsUnlocked'],
|
||||
data: function() {
|
||||
return {
|
||||
password: '',
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
getStoredPassword: function() {
|
||||
return this.$store.getters.getSettingsPassword
|
||||
},
|
||||
hasStoredPassword: function() {
|
||||
return this.getStoredPassword !== ''
|
||||
},
|
||||
unlocked: function() {
|
||||
return this.getStoredPassword === '' || this.password === this.getStoredPassword
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
unlocked(val, oldVal) {
|
||||
if (val !== oldVal) {
|
||||
this.propagateUnlockStatus()
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
handleSetPassword: function () {
|
||||
this.updateSettingsPassword(this.password)
|
||||
this.password = ''
|
||||
},
|
||||
handleRemovePassword: function () {
|
||||
this.updateSettingsPassword('')
|
||||
this.password = ''
|
||||
},
|
||||
propagateUnlockStatus: function() {
|
||||
this.$emit('settingsUnlocked', this.unlocked)
|
||||
},
|
||||
|
||||
...mapActions([
|
||||
'updateSettingsPassword'
|
||||
]),
|
||||
|
||||
}
|
||||
})
|
@ -0,0 +1,36 @@
|
||||
<template>
|
||||
<ft-settings-section
|
||||
:title="$t('Settings.Password Settings.Password Settings')"
|
||||
>
|
||||
<div>
|
||||
<ft-flex-box
|
||||
v-if="hasStoredPassword"
|
||||
class="settingsFlexStart460px"
|
||||
>
|
||||
<ft-button
|
||||
:label="$t('Settings.Password Settings.Remove Password')"
|
||||
@click="handleRemovePassword"
|
||||
/>
|
||||
</ft-flex-box>
|
||||
<ft-flex-box
|
||||
v-else
|
||||
class="settingsFlexStart460px"
|
||||
>
|
||||
<ft-input
|
||||
:placeholder="$t('Settings.Password Settings.Set Password To Prevent Access')"
|
||||
:show-action-button="false"
|
||||
:show-label="true"
|
||||
input-type="password"
|
||||
:value="password"
|
||||
@input="e => password = e"
|
||||
/>
|
||||
<ft-button
|
||||
:label="$t('Settings.Password Settings.Set Password')"
|
||||
@click="handleSetPassword"
|
||||
/>
|
||||
</ft-flex-box>
|
||||
</div>
|
||||
</ft-settings-section>
|
||||
</template>
|
||||
|
||||
<script src="./password-settings.js" />
|
@ -274,7 +274,8 @@ const state = {
|
||||
screenshotAskPath: false,
|
||||
screenshotFolderPath: '',
|
||||
screenshotFilenamePattern: '%Y%M%D-%H%N%S',
|
||||
fetchSubscriptionsAutomatically: true
|
||||
fetchSubscriptionsAutomatically: true,
|
||||
settingsPassword: ''
|
||||
}
|
||||
|
||||
const stateWithSideEffects = {
|
||||
|
@ -12,6 +12,8 @@ import ProxySettings from '../../components/proxy-settings/proxy-settings.vue'
|
||||
import SponsorBlockSettings from '../../components/sponsor-block-settings/sponsor-block-settings.vue'
|
||||
import ParentControlSettings from '../../components/parental-control-settings/parental-control-settings.vue'
|
||||
import ExperimentalSettings from '../../components/experimental-settings/experimental-settings.vue'
|
||||
import PasswordSettings from '../../components/password-settings/password-settings.vue'
|
||||
import PasswordDialog from '../../components/password-dialog/password-dialog.vue'
|
||||
|
||||
export default Vue.extend({
|
||||
name: 'Settings',
|
||||
@ -28,11 +30,23 @@ export default Vue.extend({
|
||||
'sponsor-block-settings': SponsorBlockSettings,
|
||||
'download-settings': DownloadSettings,
|
||||
'parental-control-settings': ParentControlSettings,
|
||||
'experimental-settings': ExperimentalSettings
|
||||
'experimental-settings': ExperimentalSettings,
|
||||
'password-settings': PasswordSettings,
|
||||
'password-dialog': PasswordDialog,
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
settingsUnlocked: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
usingElectron: function () {
|
||||
return process.env.IS_ELECTRON
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
handleSettingsUnlocked: function (n) {
|
||||
this.settingsUnlocked = n
|
||||
},
|
||||
}
|
||||
})
|
||||
|
@ -1,30 +1,41 @@
|
||||
<template>
|
||||
<div>
|
||||
<general-settings />
|
||||
<hr>
|
||||
<theme-settings />
|
||||
<hr>
|
||||
<player-settings />
|
||||
<hr>
|
||||
<external-player-settings v-if="usingElectron" />
|
||||
<hr v-if="usingElectron">
|
||||
<subscription-settings />
|
||||
<hr>
|
||||
<distraction-settings />
|
||||
<hr>
|
||||
<privacy-settings />
|
||||
<hr>
|
||||
<data-settings />
|
||||
<hr>
|
||||
<proxy-settings />
|
||||
<hr>
|
||||
<download-settings v-if="usingElectron" />
|
||||
<hr v-if="usingElectron">
|
||||
<parental-control-settings />
|
||||
<hr>
|
||||
<sponsor-block-settings />
|
||||
<hr v-if="usingElectron">
|
||||
<experimental-settings v-if="usingElectron" />
|
||||
<div v-if="settingsUnlocked">
|
||||
<general-settings />
|
||||
<hr>
|
||||
<theme-settings />
|
||||
<hr>
|
||||
<player-settings />
|
||||
<hr>
|
||||
<external-player-settings v-if="usingElectron" />
|
||||
<hr v-if="usingElectron">
|
||||
<subscription-settings />
|
||||
<hr>
|
||||
<distraction-settings />
|
||||
<hr>
|
||||
<privacy-settings />
|
||||
<hr>
|
||||
<data-settings />
|
||||
<hr>
|
||||
<proxy-settings />
|
||||
<hr>
|
||||
<download-settings v-if="usingElectron" />
|
||||
<hr v-if="usingElectron">
|
||||
<parental-control-settings />
|
||||
<hr>
|
||||
<sponsor-block-settings />
|
||||
<hr v-if="usingElectron">
|
||||
<experimental-settings v-if="usingElectron" />
|
||||
<hr>
|
||||
<password-settings
|
||||
@settingsUnlocked="handleSettingsUnlocked"
|
||||
/>
|
||||
</div>
|
||||
<div v-else>
|
||||
<password-dialog
|
||||
@settingsUnlocked="handleSettingsUnlocked"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -414,6 +414,16 @@ Settings:
|
||||
Experimental Settings: Experimental Settings
|
||||
Warning: These settings are experimental, they make cause crashes while enabled. Making backups is highly recommended. Use at your own risk!
|
||||
Replace HTTP Cache: Replace HTTP Cache
|
||||
Password Dialog:
|
||||
Password: Password
|
||||
Enter Password To Unlock: Enter password to unlock settings
|
||||
Password Incorrect: Password Incorrect
|
||||
Unlock: Unlock
|
||||
Password Settings:
|
||||
Password Settings: Password Settings
|
||||
Set Password To Prevent Access: Set a password to prevent access to settings
|
||||
Set Password: Set Password
|
||||
Remove Password: Remove Password
|
||||
About:
|
||||
#On About page
|
||||
About: About
|
||||
@ -825,3 +835,4 @@ Screenshot Error: Screenshot failed. {error}
|
||||
|
||||
Yes: Yes
|
||||
No: No
|
||||
Ok: Ok
|
||||
|
Loading…
x
Reference in New Issue
Block a user