diff --git a/src/components/app/AppButton.tsx b/src/components/app/AppButton.tsx index 4d415d5..0b512ef 100644 --- a/src/components/app/AppButton.tsx +++ b/src/components/app/AppButton.tsx @@ -22,9 +22,7 @@ interface AppButtonPropsInterface { } @Component({ - components: { - AppIcon - } + components: { AppIcon } }) export default class AppButton extends Vue implements AppButtonPropsInterface { @Prop({ type: String }) label!: string diff --git a/src/components/app/AppColorSelector.tsx b/src/components/app/AppColorSelector.tsx index 430bd73..a86c2b5 100644 --- a/src/components/app/AppColorSelector.tsx +++ b/src/components/app/AppColorSelector.tsx @@ -1,7 +1,4 @@ import { Component, Prop, Vue } from 'vue-property-decorator' - -// eslint-disable-next-line @typescript-eslint/ban-ts-ignore -// @ts-ignore import { Chrome } from 'vue-color' @Component({ diff --git a/src/components/app/AppSlider.tsx b/src/components/app/AppSlider.tsx index fc989a0..1843cfa 100644 --- a/src/components/app/AppSlider.tsx +++ b/src/components/app/AppSlider.tsx @@ -1,9 +1,7 @@ import { Component, Prop, Vue } from 'vue-property-decorator' - -// eslint-disable-next-line @typescript-eslint/ban-ts-ignore -// @ts-ignore import noUiSlider from 'nouislider' import { Debounce } from '@/utils/helper' + @Component export default class AppSlider extends Vue { @Prop({ type: [Number], default: '' }) value!: number | string diff --git a/src/components/base/ShutdownMenu.tsx b/src/components/base/ShutdownMenu.tsx index 962b761..3b8d8d6 100644 --- a/src/components/base/ShutdownMenu.tsx +++ b/src/components/base/ShutdownMenu.tsx @@ -1,8 +1,8 @@ import { Component, Vue } from 'vue-property-decorator' import AppIcon from '@/components/app/AppIcon.vue' -import { appWindow } from '@/models/lightdm' import { systemActionsObject } from '@/utils/helper' +import { LightdmHandler } from '@/utils/lightdm' @Component({ components: { AppIcon } @@ -12,17 +12,17 @@ export default class ShutdownMenu extends Vue { return [ { icon: 'restart', - show: appWindow.lightdm.can_restart, + show: LightdmHandler.canRestart, callback: systemActionsObject.restart }, { icon: 'suspend', - show: appWindow.lightdm.can_suspend, + show: LightdmHandler.canSuspend, callback: systemActionsObject.suspend }, { icon: 'hibernate', - show: appWindow.lightdm.can_hibernate, + show: LightdmHandler.canHibernate, callback: systemActionsObject.hibernate } ].filter(({ show }) => show) diff --git a/src/components/base/UserInput.tsx b/src/components/base/UserInput.tsx index 7aedd22..8f32974 100644 --- a/src/components/base/UserInput.tsx +++ b/src/components/base/UserInput.tsx @@ -14,23 +14,23 @@ export default class UserInput extends Vue { return AppModule.currentUser } - get passwordValue() { + get passwordValue(): string { return AppModule.password } - get showPassword() { + get showPassword(): boolean { return AppModule.showPassword } - login() { + login(): void { AppModule.login() } - handleKeyup(event: InputEvent) { + handleKeyup(event: KeyboardEvent): void { AppModule.SET_STATE_APP({ key: 'password', value: (event.target as HTMLInputElement)?.value || '' }) } - openSettings(event: Event) { + openSettings(event: Event): void { event.preventDefault() event.stopPropagation() @@ -49,7 +49,7 @@ export default class UserInput extends Vue { autofocus ref='password' class='mousetrap' - placeholder={ this.$t('text.password') } + placeholder={ this.$t('text.password').toString() } onKeyup={this.handleKeyup} value={this.passwordValue} readonly={this.logging} diff --git a/src/main.ts b/src/main.ts index 5fdc5ec..e561d0d 100644 --- a/src/main.ts +++ b/src/main.ts @@ -4,9 +4,6 @@ import App from './App' import router from './router' import store from './store' import '@/plugins/components' - -// eslint-disable-next-line @typescript-eslint/ban-ts-ignore -// @ts-ignore import VueI18n from 'vue-i18n' import './style/index.styl' diff --git a/src/models/lightdm.ts b/src/models/lightdm.ts index 62d89c0..147c3ad 100644 --- a/src/models/lightdm.ts +++ b/src/models/lightdm.ts @@ -1,16 +1,4 @@ -/* eslint-disable camelcase */ -export interface ExpandedWindow { - lightdm: Lightdm; - authentication_complete(): void; - lightdmLogin( - username: string, - password: string, - callback: () => void, - ): void; - lightdmStart(desktop: string): void; - show_prompt(text: string, type?: any): void; - show_message(text: string, type: any): void; -} +import { Greeter, Signal } from 'nody-greeter-types' export interface Lightdm { can_suspend: boolean; @@ -24,6 +12,7 @@ export interface Lightdm { users: LightdmUsers[]; languages: LightdmLanguage[]; language: string; + has_guest_account: boolean; start_authentication(username: string): void; authenticate(username: string): void; cancel_authentication(): void; @@ -52,4 +41,15 @@ export interface LightdmSession { comment?: string; } -export const appWindow = (window as unknown) as Window & ExpandedWindow +declare global { + interface Window { + authentication_complete(): void; + lightdmLogin( + username: string, + password: string, + callback: () => void, + ): void; + show_prompt(text: string, type?: string): void; + show_message(text: string, type: any): void; + } +} diff --git a/src/store/app.ts b/src/store/app.ts index a52d799..be70501 100644 --- a/src/store/app.ts +++ b/src/store/app.ts @@ -17,9 +17,11 @@ import { AppInputThemeGeneral } from '@/models/app' -import { appWindow, LightdmSession, LightdmUsers } from '@/models/lightdm' +import { LightdmSession, LightdmUsers } from '@/models/lightdm' import { isDifferentRoute, parseQueryValue, randomize, randomizeSettingsTheme } from '@/utils/helper' import { AppThemes, defaultTheme } from '@/utils/constant' +import { version } from '@/../package.json' +import { LightdmHandler } from '@/utils/lightdm' export interface AppState extends AppSettings { themes: AppTheme[]; @@ -32,16 +34,16 @@ export interface AppState extends AppSettings { @Module({ dynamic: true, store, name: 'app' }) class App extends VuexModule implements AppState { - version = '2.0.1' + version = version currentTheme = '' currentOs = 'arch-linux' - desktop = appWindow?.lightdm?.sessions[0].key || 'i3' - username = appWindow?.lightdm?.users[0].username || 'User name' + desktop = LightdmHandler.defaultSession + username = LightdmHandler?.username password = '' defaultColor = '#6BBBED' - users = appWindow?.lightdm?.users || [] - desktops = appWindow?.lightdm?.sessions || [] + users = LightdmHandler?.users + desktops = LightdmHandler?.sessions showPassword = false generateRandomThemes = false themes = AppThemes @@ -53,6 +55,10 @@ class App extends VuexModule implements AppState { 'only-ui': false } + get isAdvancedGreeted() { + return LightdmHandler.isNode + } + // TODO: replace this on localStorageSettings get getMainSettings(): AppSettings { const { @@ -183,9 +189,7 @@ class App extends VuexModule implements AppState { @Action login() { - appWindow.lightdmLogin(this.username, this.password, () => { - appWindow.lightdmStart(this.currentDesktop?.key || appWindow?.lightdm?.sessions[0].key || 'i3') - }) + LightdmHandler.login(this.username, this.password, this.currentDesktop?.key) } @Action @@ -317,14 +321,14 @@ class App extends VuexModule implements AppState { this.syncBodyClassWithStore({ settings, query }) } - const isExistDE = appWindow?.lightdm?.sessions.find(({ key }) => key === settings.desktop) + const isExistDE = window.lightdm?.sessions.find(({ key }) => key === settings.desktop) if (isExistDE === undefined) { - settings.desktop = appWindow?.lightdm?.sessions[0].key || 'openbox' + settings.desktop = window.lightdm?.sessions[0].key || 'openbox' } - const isExistUser = appWindow?.lightdm?.users.find(({ username }) => username === settings.username) + const isExistUser = window.lightdm?.users.find(({ username }) => username === settings.username) if (isExistUser === undefined) { - settings.username = appWindow?.lightdm?.users[0].username || 'Warinyourself' + settings.username = window.lightdm?.users[0].username || 'Warinyourself' } this.SET_STATE_APP({ key: 'currentOs', value: settings.currentOs || 'arch-linux' }) diff --git a/src/utils/helper.ts b/src/utils/helper.ts index 04c86f6..9c7ff50 100644 --- a/src/utils/helper.ts +++ b/src/utils/helper.ts @@ -1,10 +1,10 @@ import { AppInputButton, AppInputThemeGeneral, AppInputThemeSlider, AppInputThemeValue, AppTheme } from '@/models/app' -import { appWindow } from '@/models/lightdm' import { AppModule } from '@/store/app' import { PageModule } from '@/store/page' import { debounce, DebounceSettings } from 'lodash' import { RawLocation } from 'vue-router' import router from '../router' +import { LightdmHandler } from '@/utils/lightdm' const isFinalBuild = process.env.VUE_APP_VIEW === 'build' export const modKey = 'ctrl' @@ -122,7 +122,7 @@ export function buildSystemDialog(callbackName: systemActionsType) { actions: [ { title: 'text.yes', - callback: appWindow.lightdm[callbackName] + callback: LightdmHandler[callbackName] }, { title: 'text.no', diff --git a/src/utils/lightdm.ts b/src/utils/lightdm.ts index 3cdf911..420405e 100644 --- a/src/utils/lightdm.ts +++ b/src/utils/lightdm.ts @@ -1,14 +1,12 @@ -/* eslint-disable camelcase */ -import { appWindow } from '@/models/lightdm' +import { Lightdm } from '@/models/lightdm' +import { Greeter } from 'nody-greeter-types' const DEBUG_PASSWORD = 'password' - -const lightdmDebug = appWindow.lightdm === undefined -let password: string -let completeCallback: undefined | (() => void) +const lightdmDebug = window.lightdm === undefined +const localLight = window.lightdm as unknown as Lightdm if (lightdmDebug) { - appWindow.lightdm = { + window.lightdm = { is_authenticated: false, authentication_user: undefined, default_session: 'plasma-shell', @@ -72,26 +70,28 @@ if (lightdmDebug) { } ], language: 'American English', - start_authentication: (username) => { + start_authentication: (username: string) => { console.log(`Starting authenticating here: '${username}'`) - appWindow.lightdm.respond(password) + const inputNode = document.getElementById('password') as HTMLInputElement + + localLight.respond(inputNode?.value || '') }, - authenticate: (username) => { + authenticate: (username: string) => { console.log(`Starting authenticating user: '${username}'`) }, cancel_authentication: () => { console.log('Auth cancelled') }, - respond: (password) => { + respond: (password: string) => { console.log(`Password provided : '${password}'`) if (password === DEBUG_PASSWORD) { - appWindow.lightdm.is_authenticated = true + localLight.is_authenticated = true } - appWindow.authentication_complete() + window.authentication_complete() }, - login(user, session) { + login(user: string, session: string) { alert(`Logged with '${user}' (Session: '${session}') !`) }, shutdown() { @@ -106,55 +106,198 @@ if (lightdmDebug) { restart: () => { alert('(DEBUG: System is rebooting)') } - } + } as any } -appWindow.lightdmLogin = (username, pass, callback) => { - completeCallback = callback - password = pass - console.log(`lightdmLogin ${username}, ${pass}`) +const isNode = 'batteryData' in window && window.lightdm - appWindow.lightdm.start_authentication(username) -} +class LightdmWebkit { + protected _inputErrorTimer!: null | NodeJS.Timeout + + // get session() { + // return '' + // } -appWindow.lightdmStart = desktop => { - if (appWindow.lightdm) { - appWindow.lightdm.login(appWindow.lightdm.authentication_user || '', desktop) + get defaultSession() { + return this.sessions[0]?.key || window.lightdm?.default_session || 'i3' + } + + get isNode() { + return isNode + } + + get sessions() { + return window.lightdm?.sessions || [] + } + + get hasGuestAccount() { + return window.lightdm?.has_guest_account + } + + get users() { + return window.lightdm?.users || [] + } + + get username() { + return this.users[0]?.username || 'Username' + } + + get languages() { + return window.lightdm?.languages } -} -let inputErrorTimer: null | any + get canRestart() { + return window.lightdm?.can_restart + } -appWindow.authentication_complete = () => { - if (appWindow?.lightdm?.is_authenticated && completeCallback) { - completeCallback() - } else { - appWindow.lightdm.cancel_authentication() + get canShutdown() { + return window.lightdm?.can_shutdown + } + + get canSuspend() { + return window.lightdm?.can_suspend + } + + get canHibernate() { + return window.lightdm?.can_hibernate + } + + shutdown() { + return window.lightdm?.shutdown() + } + hibernate() { + return window.lightdm?.hibernate() + } + + suspend() { + return window.lightdm?.suspend() + } + + restart() { + return window.lightdm?.restart() + } + + protected _setInputError() { const inputNode = document.getElementById('password') if (!inputNode) return inputNode.classList.add('password-input--error') - if (inputErrorTimer) { - clearTimeout(inputErrorTimer) + if (this._inputErrorTimer) { + clearTimeout(this._inputErrorTimer) } - inputErrorTimer = setTimeout(() => { + this._inputErrorTimer = setTimeout(() => { inputNode.classList.remove('password-input--error') - inputErrorTimer = null + this._inputErrorTimer = null }, 10000) } } -appWindow.show_prompt = (text, _type) => { - if (text === 'Password: ') { - if (appWindow.lightdm) { - appWindow.lightdm.respond(password) +class LightdmPython extends LightdmWebkit { + private _password = '' + private _completeCallback!: () => void + + constructor() { + super() + this.init() + } + + get light() { + return window.lightdm as unknown as Lightdm + } + + public login(username: string, password: string, session?: string): void { + this.lightdmLogin(username, password, () => this.lightdmStart(session || this.defaultSession)) + } + + private lightdmStart(session: string): void { + this.light.login(this.light.authentication_user || '', session) + } + + private lightdmLogin(username: string, password: string, callback: () => void) { + this._completeCallback = callback + this._password = password + + this.light.start_authentication(username) + } + + private init() { + window.authentication_complete = () => { + if (window.lightdm?.is_authenticated && this._completeCallback) { + this._completeCallback() + } else { + this.light.cancel_authentication() + this._setInputError() + } + } + + window.show_message = (text) => { + alert(text) + } + + window.show_prompt = (text) => { + if (text === 'Password: ') { + if (window.lightdm) { + window.lightdm.respond(this._password) + } + } } } } -appWindow.show_message = (text, type) => { - alert(text) +class LightdmNode extends LightdmWebkit { + private _username!: string + private _password!: string + private _session!: undefined | string + + constructor() { + super() + this.init() + } + + get light() { + return window.lightdm as Greeter + } + + public login(username: string, password: string, session?: string): void { + this._username = username + this._password = password + this._session = session + + this.light.authenticate(null) + } + + public setAuthenticationDone(): void { + this.light.authentication_complete.connect(() => { + if (this.light.is_authenticated) { + this.light.start_session(this._session || this.light.default_session) + } else { + this._authenticationFailed() + } + }) + } + + public _authenticationFailed(): void { + this.light.cancel_authentication() + } + + public setSignalHandler(): void { + this.light.show_prompt.connect((_message, type) => { + if (!window.lightdm) return + if (type === 0) { + window.lightdm.respond(this._username) + } else if (type === 1 && window.lightdm.in_authentication) { + window.lightdm.respond(this._password) + } + }) + } + + public init(): void { + this.setSignalHandler() + this.setAuthenticationDone() + } } + +export const LightdmHandler = isNode ? new LightdmNode() : new LightdmPython() diff --git a/tsconfig.json b/tsconfig.json index 2b8536c..6e42300 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -16,7 +16,7 @@ "webpack-env", "node", ], - "typeRoots": ["./node_modules/@types", "./types/application"], + "typeRoots": ["./node_modules/@types", "./types/application", "nody-greeter-types"], "paths": { "@/*": [ "./src/*"