From e72fb04303d49570f1088142ac8eeb4ca57f4c83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Go=CC=88sta?= Date: Sun, 3 Oct 2021 01:34:05 +0200 Subject: [PATCH] feat: moonraker user authorization --- .gitignore | 1 + src/api/moonraker.ts | 57 +++++++ src/api/moonraker.types.ts | 40 +++++ src/components/TheConnectingDialog.vue | 29 +++- src/components/panels/FarmPrinterPanel.vue | 58 ++++++- .../panels/Machine/ConfigFilesPanel.vue | 2 +- src/components/panels/Machine/UsersPanel.vue | 106 +++++++++++++ src/components/ui/LoginForm.vue | 76 +++++++++ src/locales/en.json | 26 ++- src/main.ts | 2 + src/pages/Machine.vue | 7 +- src/plugins/interceptors.ts | 40 +++++ src/plugins/webSocketClient.ts | 16 +- src/store/auth/actions.ts | 80 ++++++++++ src/store/auth/getters.ts | 9 ++ src/store/auth/index.ts | 24 +++ src/store/auth/mutations.ts | 44 ++++++ src/store/auth/types.ts | 42 +++++ src/store/farm/printer/actions.ts | 148 +++++++++++------- src/store/farm/printer/getters.ts | 23 ++- src/store/farm/printer/index.ts | 4 +- src/store/farm/printer/types.ts | 4 +- src/store/index.ts | 2 + src/store/server/actions.ts | 5 +- src/store/socket/actions.ts | 6 +- src/store/types.ts | 4 +- 26 files changed, 768 insertions(+), 87 deletions(-) create mode 100644 src/api/moonraker.ts create mode 100644 src/api/moonraker.types.ts create mode 100644 src/components/panels/Machine/UsersPanel.vue create mode 100644 src/components/ui/LoginForm.vue create mode 100644 src/plugins/interceptors.ts create mode 100644 src/store/auth/actions.ts create mode 100644 src/store/auth/getters.ts create mode 100644 src/store/auth/index.ts create mode 100644 src/store/auth/mutations.ts create mode 100644 src/store/auth/types.ts diff --git a/.gitignore b/.gitignore index 635094a58..fcf1fe2ea 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ docker/config/*.cfg docker/config/*.conf docker/config/.mainsail.json docker/config/.theme +*.iml diff --git a/src/api/moonraker.ts b/src/api/moonraker.ts new file mode 100644 index 000000000..6e1485492 --- /dev/null +++ b/src/api/moonraker.ts @@ -0,0 +1,57 @@ +import axios from 'axios' +import store from '@/store' + +import { + MoonrakerApiResponse, MoonrakerCreateUserResponse, MoonrakerDeleteUserResponse, + MoonrakerLoginResponse, + MoonrakerUser, + MoonrakerUsersResponse +} from '@/api/moonraker.types' + +async function login(baseUrl: string, username: string, password: string): Promise { + const url = baseUrl + '/access/login' + const response = await axios.post>(url, { + username, + password + }) + return response.data.result +} + +export async function getOneshotToken(baseUrl: string): Promise { + const url = `${baseUrl}/access/oneshot_token` + const response = await axios.get>(url, {}) + return response.data.result +} + +async function getUserlist(baseUrl: string): Promise { + const url = baseUrl + '/access/users/list' + const result = await axios.get>(url, {}) + return result.data.result.users +} + +async function deleteUser(baseUrl: string, username: string): Promise { + const url = store.getters['socket/getUrl'] + '/access/user' + const response = await axios.delete>(url, { + data: { + username + } + }) + return response.data.result +} + +async function createUser(baseUrl: string, username: string, password: string): Promise { + const url = baseUrl + '/access/user' + const response = await axios.post>(url, { + username: username, + password: password + }, {}) + return response.data.result +} + +export const MoonrakerApi = { + login, + createUser, + deleteUser, + getOneshotToken, + getUserlist +} diff --git a/src/api/moonraker.types.ts b/src/api/moonraker.types.ts new file mode 100644 index 000000000..088e9ba20 --- /dev/null +++ b/src/api/moonraker.types.ts @@ -0,0 +1,40 @@ +export interface MoonrakerApiResponse { + result: T +} + +export interface MoonrakerDeleteUserResponse { + username: string + action: 'user_deleted' +} + +export interface MoonrakerCreateUserResponse { + username: string + password: string +} + +export interface MoonrakerLoginResponse { + username: string + token: string + refresh_token: string + action: 'user_logged_in' +} + +export interface MoonrakerLogoutResponse { + username: string; + action: 'user_logged_out' +} + +export interface MoonrakerUsersResponse { + users: MoonrakerUser[] +} + +export interface MoonrakerUser { + username: string + created_on: number +} + +export interface RefreshTokenResponse { + username: string; + token: string; + action: 'user_jwt_refresh' +} diff --git a/src/components/TheConnectingDialog.vue b/src/components/TheConnectingDialog.vue index e78c42b21..a7c0ac63a 100644 --- a/src/components/TheConnectingDialog.vue +++ b/src/components/TheConnectingDialog.vue @@ -1,5 +1,4 @@ + + + + + + + + + + + + + + + @@ -122,17 +137,20 @@ import { FarmPrinterState } from '@/store/farm/printer/types' import Mjpegstreamer from '@/components/webcams/Mjpegstreamer.vue' import MjpegstreamerAdaptive from '@/components/webcams/MjpegstreamerAdaptive.vue' import MainsailLogo from '@/components/ui/MainsailLogo.vue' +import LoginForm from '@/components/ui/LoginForm.vue' +import {UserCredentials} from '@/store/auth/types' @Component({ components: { 'webcam-mjpegstreamer': Mjpegstreamer, 'webcam-mjpegstreamer-adaptive': MjpegstreamerAdaptive, - 'mainsail-logo': MainsailLogo + 'mainsail-logo': MainsailLogo, + LoginForm } }) export default class FarmPrinterPanel extends Mixins(BaseMixin) { private imageHeight = 200; - + private showLogin = false @Prop({ type: Object, required: true }) printer!: FarmPrinterState @Ref() readonly imageDiv!: Vue @@ -166,6 +184,10 @@ export default class FarmPrinterPanel extends Mixins(BaseMixin) { return this.$store.getters['farm/'+this.printer._namespace+'/getStatus'] } + get reqiresLogin() { + return this.$store.getters['farm/'+this.printer._namespace+'/getRequiresLogin'] + } + get printer_current_filename() { return this.$store.getters['farm/'+this.printer._namespace+'/getCurrentFilename'] } @@ -201,11 +223,33 @@ export default class FarmPrinterPanel extends Mixins(BaseMixin) { return false } + get getButtonText(): string { + if (this.printer.socket.isConnected) { + return 'Panels.FarmPrinterPanel.SwitchToPrinter' + } + if (this.printer.socket.requiresLogin) { + return 'Panels.FarmPrinterPanel.Login' + } + + return 'Panels.FarmPrinterPanel.ReconnectToPrinter' + } + clickPrinter() { - if (this.printer.socket.isConnected) + if (this.printer.socket.requiresLogin) { + this.showLogin = true + return + } + if (this.printer.socket.isConnected) { this.$store.dispatch('changePrinter', { printer: this.printer._namespace }) - else - this.$store.dispatch('farm/'+this.printer._namespace+'/reconnect') + return + } + this.$store.dispatch('farm/'+this.printer._namespace+'/reconnect') + } + + login(user: UserCredentials) { + this.$store.dispatch('farm/'+this.printer._namespace+'/login', user).then(() => { + this.showLogin = this.printer.socket.loginFailed + }) } mounted() { @@ -224,4 +268,4 @@ export default class FarmPrinterPanel extends Mixins(BaseMixin) { } } - \ No newline at end of file + diff --git a/src/components/panels/Machine/ConfigFilesPanel.vue b/src/components/panels/Machine/ConfigFilesPanel.vue index 363dbe5c1..608edc25a 100644 --- a/src/components/panels/Machine/ConfigFilesPanel.vue +++ b/src/components/panels/Machine/ConfigFilesPanel.vue @@ -4,7 +4,7 @@