Skip to content

Commit

Permalink
Added login skip feature
Browse files Browse the repository at this point in the history
Modified button, tracking credentials saved and login skipped outside LoginPage, disabling command execution which uses login objects.
  • Loading branch information
megastary committed Aug 7, 2020
1 parent 2ea234d commit b98a701
Show file tree
Hide file tree
Showing 12 changed files with 283 additions and 134 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "lazy-admin",
"version": "0.4.2",
"version": "0.4.3",
"description": "GUI for PowerShell scripts to simplify day to day IT tasks.",
"productName": "Lazy Admin",
"cordovaId": "eu.houby-studio.lazy-admin",
Expand Down Expand Up @@ -50,4 +50,4 @@
"browserslist": [
"last 1 version, not dead, ie >= 11"
]
}
}
2 changes: 1 addition & 1 deletion scripts-definitions/base-module-example.json
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,7 @@
"icon": "mdi-powershell",
"returns": "PSObject",
"insidePsSession": false,
"usesLoginObjects": false,
"usesLoginObjects": true,
"friendlyName": {
"default": "Nothing really",
"en-us": "Nothing really",
Expand Down
4 changes: 3 additions & 1 deletion src/i18n/cs-cz/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ export default {
usernameRequired: 'Zadejte přihlašovací jméno!', // Used in: LoginPage.vue
password: 'Heslo', // Used in: LoginPage.vue
passwordRequired: 'Zadejte přihlašovací heslo!', // Used in: LoginPage.vue
login: 'Vstoupit', // Used in: LoginPage.vue
login: 'Přihlásit', // Used in: LoginPage.vue
loginSkip: 'Přeskočit', // Used in: LoginPage.vue
language: 'Jazyk', // Used in: LoginPage.vue
changeUser: 'Jiný uživatel', // Used in: LoginPage.vue
install: 'Instalovat', // Used in: LoginPage.vue, FullLayout.vue
Expand All @@ -14,6 +15,7 @@ export default {
pwshMissing: 'Nelze nalézt PowerShell Core. Používá se záložní Windows PowerShell.', // Used in: LoginPage.vue
wrongUsernameOrPassword: 'Špatné přihlašovací jméno nebo heslo.', // Used in: LoginPage.vue
foundsavedCredential: 'Nalezeny přihlašovací údaje pro uživatele {usr}.', // Used in: LoginPage.vue
failedToLogin: 'Nepodařilo se přihlásení s neznámou chybou.', // Used in: LoginPage.vue
search: 'Vyhledat', // Used in: FullLayout.vue
history: 'Historie', // Used in: FullLayout.vue
visibleGroups: 'Zobrazované příkazy', // Used in: FullLayout.vue
Expand Down
2 changes: 2 additions & 0 deletions src/i18n/en-us/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export default {
password: 'Password', // Used in: LoginPage.vue
passwordRequired: 'Login password is required!', // Used in: LoginPage.vue
login: 'Login', // Used in: LoginPage.vue
loginSkip: 'Skip', // Used in: LoginPage.vue
language: 'Language', // Used in: LoginPage.vue
changeUser: 'Change User', // Used in: LoginPage.vue
install: 'Install', // Used in: LoginPage.vue, FullLayout.vue
Expand All @@ -14,6 +15,7 @@ export default {
pwshMissing: 'Couldn\'t find PowerShell Core, default. Using fallback Windows PowerShell.', // Used in: LoginPage.vue
wrongUsernameOrPassword: 'Wrong username or password.', // Used in: LoginPage.vue
foundsavedCredential: 'Found stored credentials for user {usr}.', // Used in: LoginPage.vue
failedToLogin: 'Login failed with unknown error.', // Used in: LoginPage.vue
search: 'Search', // Used in: FullLayout.vue
history: 'History', // Used in: FullLayout.vue
visibleGroups: 'Shown commands', // Used in: FullLayout.vue
Expand Down
45 changes: 45 additions & 0 deletions src/layouts/FullLayout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,51 @@
/>
</div>
</div>
<!-- TOOLS RELATED TO APP NAVIGATION -->
<q-toolbar-title class="q-px-none">
<q-icon name="navigation" /> Control
</q-toolbar-title>
<div class="row text-center">
<div class="col-xs-12 col-sm-6 col-md-3">
<q-btn
to="/"
color="primary"
label="Log out"
style="width: 90%"
class="q-mb-sm"
no-wrap
/>
</div>
<div class="col-xs-12 col-sm-6 col-md-3">
<div class="text-h6">
<q-btn
color="primary"
label="-"
style="width: 90%"
class="q-mb-sm"
no-wrap
/>
</div>
</div>
<div class="col-xs-12 col-sm-6 col-md-3">
<q-btn
color="primary"
label="-"
style="width: 90%"
class="q-mb-sm"
no-wrap
/>
</div>
<div class="col-xs-12 col-sm-6 col-md-3">
<q-btn
color="primary"
label="-"
style="width: 90%"
class="q-mb-sm"
no-wrap
/>
</div>
</div>
</q-card-section>
<q-page-sticky
:offset="[0, 0]"
Expand Down
126 changes: 86 additions & 40 deletions src/pages/LoginPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,24 @@
class="q-pa-lg shadow-1"
>
<q-form
@submit="login"
@submit="showSkipLogin ? skipLogin() : login()"
ref="loginform"
class="q-gutter-md"
>
<q-card-section>

<q-input
square
filled
v-model="username"
type="text"
ref="username"
:disable="credentialsSaved"
:label="$t('username')"
:class="shake"
:rules="showSkipLogin ? [ val => val.length >= 0 ] : [ val => val && val.length > 0 || $t('usernameRequired') ]"
type="text"
ref="username"
square
filled
lazy-rules
no-error-icon
:rules="[ val => val && val.length > 0 || $t('usernameRequired') ]"
>
<template v-slot:append>
<q-icon name="person" />
Expand All @@ -36,51 +36,55 @@
mode="out-in"
>
<div
style="q-gutter-md"
v-if="credentialsSaved"
style="q-gutter-md"
>
<q-btn
:label="$t('changeUser')"
@click="credentialsSaved = false"
unelevated
color="light"
size="lg"
class="full-width"
:label="$t('changeUser')"
@click="credentialsSaved = false"
/>
</div>

<q-input
square
filled
v-model="password"
v-else
v-model="password"
:type="isPwd ? 'password' : 'text'"
:label="$t('password')"
:rules="showSkipLogin ? [ val => val.length >= 0 ] : [ val => val && val.length > 0 || $t('passwordRequired') ]"
square
filled
lazy-rules
no-error-icon
:rules="[ val => val && val.length > 0 || $t('passwordRequired') ]"
>
<template v-slot:append>
<q-icon
:name="isPwd ? 'visibility_off' : 'visibility'"
class="cursor-pointer"
@click="isPwd = !isPwd"
class="cursor-pointer"
/>
</template>
</q-input>
</transition>
</q-card-section>
<q-card-actions class="q-px-md">
<q-btn
autofocus
unelevated
<q-btn-dropdown
v-model="showSkipLogin"
:label="showSkipLogin ? $t('loginSkip') : $t('login')"
:disable="loginButtonDisabled"
@input="resetValidation"
dropdown-icon="mdi-skip-next"
color="primary"
size="lg"
class="full-width"
type="submit"
ref="login"
:label="$t('login')"
:disable="loginButtonDisabled"
unelevated
persistent
split
/>
</q-card-actions>
</q-form>
Expand Down Expand Up @@ -111,8 +115,8 @@ export default {
username: '',
password: '',
loginButtonDisabled: false,
showSkipLogin: false,
shakeUsername: false,
credentialsSaved: false,
isPwd: true,
langOptions: [
{ value: 'en-us', label: 'English' },
Expand All @@ -121,7 +125,7 @@ export default {
}
},
computed: {
...mapGetters('lazystore', ['getLanguage']),
...mapGetters('lazystore', ['getLanguage', 'getLoginSkipped', 'getCredentialsSaved']),
shake: {
get () {
// Add classes to trigger animations on username field when username is found in credential store
Expand All @@ -130,18 +134,66 @@ export default {
},
language: {
get () {
// retrieve language settings from mapped getter
return this.getLanguage
},
set (val) {
// set selected language to store
this.$store.dispatch('lazystore/setLanguage', val)
}
},
loginSkipped: {
get () {
return this.getLoginSkipped
},
set (val) {
this.$store.dispatch('lazystore/setLoginSkipped', val)
}
},
credentialsSaved: {
get () {
return this.getCredentialsSaved
},
set (val) {
this.$store.dispatch('lazystore/setCredentialsSaved', val)
}
}
},
methods: {
resetForm (credentialsProvided) {
this.loginButtonDisabled = false
this.credentialsSaved = false
this.username = ''
this.password = ''
this.$refs.loginform.resetValidation()
this.$refs.username.focus()
this.$q.notify({
timeout: 5000,
multiLine: false,
type: 'negative',
icon: 'error',
message: credentialsProvided ? this.$t('wrongUsernameOrPassword') : this.$t('failedToLogin'),
actions: [
{ label: this.$t('dismiss'), color: 'white' }
]
})
},
resetValidation () {
this.$refs.loginform.resetValidation()
},
skipLogin () {
this.loginButtonDisabled = true
this.loginSkipped = true
console.log('Skipping login, certain commands may be unavailable.')
this.$pwsh.shell.addCommand(`$Global:CredentialObject = [System.Management.Automation.PSCredential]::Empty`)
this.$pwsh.shell.invoke().then(output => {
this.$router.push({ path: '/scripts' })
}).catch(e => {
console.error(`Failed to create empty Credential Object. Error message: ${e}`)
this.resetForm(false)
})
},
login () {
this.loginButtonDisabled = true // Disable button during login attempt
this.loginSkipped = false
// Invoke function with either credential object or username and password
if (this.credentialsSaved) {
console.log(`Creating new PowerShell session with saved credentials for user "${this.username}".`)
Expand All @@ -159,28 +211,18 @@ export default {
}
if (data.error) {
console.error(`Failed to create new PowerShell session with supplied credentials. Error message: ${output}`)
this.loginButtonDisabled = false
this.credentialsSaved = false
this.username = ''
this.password = ''
this.$refs.loginform.resetValidation()
this.$refs.username.focus()
this.$q.notify({
timeout: 5000,
multiLine: false,
type: 'negative',
icon: 'error',
message: this.$t('wrongUsernameOrPassword'),
actions: [
{ label: this.$t('dismiss'), color: 'white' }
]
})
this.resetForm(true)
} else {
console.log(data.output) // Should write 'New Powershell session created succesfully.' from PS Function output
// Route to main screen
if (!this.credentialsSaved) {
this.$pwsh.shell.addCommand(`if (Get-Command New-StoredCredential -ErrorAction SilentlyContinue) {New-StoredCredential -Target 'Lazy Admin' -UserName '${this.username}' -Password '${this.password}' -Comment 'Administrator credentials for Lazy Admin Utility.' -Type Generic -Persist LocalMachine | Out-Null}`)
this.$pwsh.shell.invoke()
this.$pwsh.shell.invoke().then(o => {
console.log('Succesfully saved credentials to Credential Manager.')
this.credentialsSaved = true
}).catch(e => {
console.error(`Failed to save credentials to Credential Manager. Error message: ${e}`)
})
}
// Succesfully created session, push login and session commands to private pwsh variable
if (this.credentialsSaved) {
Expand All @@ -190,6 +232,9 @@ export default {
}
this.$router.push({ path: '/scripts' })
}
}).catch(e => {
console.error(`Failed to create new PowerShell session with supplied credentials. Error message: ${e}`)
this.resetForm(false)
})
},
pwshFallbackNotify () {
Expand Down Expand Up @@ -218,6 +263,7 @@ export default {
this.$q.loading.show()
// Insert throttle to button functions
this.login = throttle(this.login, 800)
this.skipLogin = throttle(this.skipLogin, 800)
console.log(`Application started by user ${this.$q.electron.remote.process.env.USERDOMAIN}\\${this.$q.electron.remote.process.env.USERNAME} on computer ${this.$q.electron.remote.process.env.COMPUTERNAME}`)
// Try to load saved credentials from Credential Manager
this.$pwsh.shell.addCommand(GetSavedCredentials)
Expand Down
Loading

0 comments on commit b98a701

Please sign in to comment.