From ecb64db62a73bce75dc5114544467cbc4b609595 Mon Sep 17 00:00:00 2001 From: Natsumi Date: Wed, 23 Dec 2020 01:19:09 +1300 Subject: [PATCH] Multi Login --- html/src/app.js | 102 ++++++++++++++++++++++++++++++++++++++------- html/src/index.pug | 50 +++++++++++++++------- 2 files changed, 120 insertions(+), 32 deletions(-) diff --git a/html/src/app.js b/html/src/app.js index f7416849..b074434d 100644 --- a/html/src/app.js +++ b/html/src/app.js @@ -386,6 +386,9 @@ import gameLogService from './service/gamelog.js' } return data; } + if ((status === 401) && (data.error.message === '"Missing Credentials"') && (this.pendingGetRequests.size <= 1)) { + this.$emit('AUTOLOGIN'); + } if (data.error === Object(data.error)) { this.$throw( data.error.status_code || status, @@ -880,10 +883,14 @@ import gameLogService from './service/gamelog.js' } */ API.login = function (params) { - var { username, password } = params; + var { username, password, saveCredentials } = params; username = encodeURIComponent(username); password = encodeURIComponent(password); var auth = btoa(`${username}:${password}`); + if (saveCredentials) { + delete params.saveCredentials; + $app.saveCredentials = params; + } return this.call(`auth/user?apiKey=${this.cachedConfig.clientApiKey}`, { method: 'GET', headers: { @@ -3394,20 +3401,6 @@ import gameLogService from './service/gamelog.js' if (--this.nextRefresh <= 0) { this.nextRefresh = 60; API.getCurrentUser().catch((err1) => { - if (err1.status_code === 401) { - API.getConfig().then((args) => { - API.login({ - username: this.loginForm.username, - password: this.loginForm.password - }).catch((err2) => { - if (err2.status_code === 401) { - API.logout(); - } - throw err2; - }); - return args; - }); - } throw err1; }); } @@ -3627,10 +3620,81 @@ import gameLogService from './service/gamelog.js' $app.resetGameLog(); }); + API.$on('LOGIN', function (args) { + var savedCredentialsArray = {}; + if (configRepository.getString('savedCredentials') !== null) { + var savedCredentialsArray = JSON.parse(configRepository.getString('savedCredentials')); + } + if ($app.saveCredentials) { + var credentialsToSave = { user: args.ref, loginParmas: $app.saveCredentials }; + savedCredentialsArray[args.ref.username] = credentialsToSave; + delete $app.saveCredentials; + } else { + if (savedCredentialsArray[args.ref.username] !== undefined) { + savedCredentialsArray[args.ref.username].user = args.ref; + } + } + $app.loginForm.savedCredentials = savedCredentialsArray; + var jsonCredentialsArray = JSON.stringify(savedCredentialsArray); + configRepository.setString('savedCredentials', jsonCredentialsArray); + $app.loginForm.lastUserLoggedIn = args.ref.username; + configRepository.setString('lastUserLoggedIn', args.ref.username); + }); + + $app.methods.relogin = function (loginParmas) { + this.loginForm.loading = true; + return API.getConfig().catch((err) => { + this.loginForm.loading = false; + throw err; + }).then((args) => { + API.login({ + username: loginParmas.username, + password: loginParmas.password + }).catch((err2) => { + API.logout(); + throw err2; + }).finally(() => { + this.loginForm.loading = false; + }); + }); + }; + + $app.methods.deleteSavedLogin = function (username) { + var savedCredentialsArray = JSON.parse(configRepository.getString('savedCredentials')); + delete savedCredentialsArray[username]; + $app.loginForm.savedCredentials = savedCredentialsArray; + var jsonCredentialsArray = JSON.stringify(savedCredentialsArray); + configRepository.setString('savedCredentials', jsonCredentialsArray); + new Noty({ + type: 'success', + text: 'Account removed.' + }).show(); + }; + + API.$on('AUTOLOGIN', function () { + if ($app.isAutoLogin) { + var user = $app.loginForm.savedCredentials[$app.loginForm.lastUserLoggedIn] + if (user !== undefined) { + $app.relogin({ + username: user.loginParmas.username, + password: user.loginParmas.password + }).then((args) => { + new Noty({ + type: 'success', + text: 'Automatically logged in.' + }).show(); + }); + } + } + }); + $app.data.loginForm = { loading: true, username: '', password: '', + saveCredentials: false, + savedCredentials: ((configRepository.getString('lastUserLoggedIn') !== null) ? JSON.parse(configRepository.getString('savedCredentials')) : {}), + lastUserLoggedIn: configRepository.getString('lastUserLoggedIn'), rules: { username: [ { @@ -3658,8 +3722,11 @@ import gameLogService from './service/gamelog.js' }).then((args) => { API.login({ username: this.loginForm.username, - password: this.loginForm.password + password: this.loginForm.password, + saveCredentials: this.loginForm.saveCredentials }).finally(() => { + this.loginForm.username = ''; + this.loginForm.password = ''; this.loginForm.loading = false; }); return args; @@ -5640,15 +5707,18 @@ import gameLogService from './service/gamelog.js' $app.data.isStartAtWindowsStartup = configRepository.getBool('VRCX_StartAtWindowsStartup'); $app.data.isStartAsMinimizedState = (VRCXStorage.Get('VRCX_StartAsMinimizedState') === 'true'); $app.data.isCloseToTray = configRepository.getBool('VRCX_CloseToTray'); + $app.data.isAutoLogin= configRepository.getBool('VRCX_AutoLogin'); var saveVRCXWindowOption = function () { configRepository.setBool('VRCX_StartAtWindowsStartup', this.isStartAtWindowsStartup); VRCXStorage.Set('VRCX_StartAsMinimizedState', this.isStartAsMinimizedState.toString()); configRepository.setBool('VRCX_CloseToTray', this.isCloseToTray); AppApi.SetStartup(this.isStartAtWindowsStartup); + configRepository.setBool('VRCX_AutoLogin', this.isAutoLogin); }; $app.watch.isStartAtWindowsStartup = saveVRCXWindowOption; $app.watch.isStartAsMinimizedState = saveVRCXWindowOption; $app.watch.isCloseToTray = saveVRCXWindowOption; + $app.watch.isAutoLogin = saveVRCXWindowOption; if (!configRepository.getString('VRCX_notificationTimeout')) { $app.data.notificationTimeout = 3000; configRepository.setString('VRCX_notificationTimeout', $app.data.notificationTimeout); diff --git a/html/src/index.pug b/html/src/index.pug index bade183c..7f86dc47 100644 --- a/html/src/index.pug +++ b/html/src/index.pug @@ -16,21 +16,36 @@ html //- login .x-login-container(v-show="!API.isLoggedIn") - div(style="width:300px;margin:auto") - el-form(ref="loginForm" :model="loginForm" :rules="loginForm.rules" v-loading="loginForm.loading" @submit.native.prevent="login()") - el-form-item(label="Username or Email" prop="username" required) - el-input(v-model="loginForm.username" name="username" placeholder="Username or Email" clearable) - el-form-item(label="Password" prop="password" required) - el-input(type="password" v-model="loginForm.password" name="password" placeholder="Password" clearable show-password) - el-form-item(style="margin-top:35px") - el-button(native-type="submit" type="primary" :loading="loginForm.loading" style="width:100%") Login - el-form-item - el-button(:loading="loginForm.loading" style="width:100%" @click="loginWithSteam()") Login with Steam - div(style="text-align:center;font-size:12px") - p © 2019-2020 #[a(href="https://github.com/pypy-vrc" target="_blank") pypy] (mina#5656) - p VRCX is an assistant application for provide information about manage friendship. this application uses unofficial VRChat API (VRCSDK). - p VRCX isn't endorsed by VRChat and doesn't reflect the views or opinions of VRChat or anyone officially involved in producing or managing VRChat. VRChat is trademark of VRChat Inc. VRChat © VRChat Inc. - p pypy is not responsible for any problems caused by VRCX. Use at your own risk! + div(style="width:300px;margin:auto" v-loading="loginForm.loading") + div(style="margin:15px" v-if="Object.keys(loginForm.savedCredentials).length !== 0") + h2(style="font-weight:bold;text-align:center;margin:0") Saved Accounts + .x-friend-list(style="margin-top:10px") + .x-friend-item(v-for="user in loginForm.savedCredentials" :key="user.user.id") + .x-friend-item(@click="relogin(user.loginParmas)" style="width:202px;padding:0") + .avatar + img(v-if="displayVRCPlusIconsAsAvatar && user.user.userIcon" v-lazy="user.user.userIcon") + img(v-else v-lazy="user.user.currentAvatarThumbnailImageUrl") + .detail + span.name(v-text="user.user.displayName") + span.extra(v-text="user.user.username") + el-button(type="default" @click="deleteSavedLogin(user.user.username)" size="mini" icon="el-icon-delete" circle) + div(style="margin:15px") + h2(style="font-weight:bold;text-align:center;margin:0") Login + el-form(ref="loginForm" :model="loginForm" :rules="loginForm.rules" @submit.native.prevent="login()") + el-form-item(label="Username or Email" prop="username" required) + el-input(v-model="loginForm.username" name="username" placeholder="Username or Email" clearable) + el-form-item(label="Password" prop="password" required) + el-input(type="password" v-model="loginForm.password" name="password" placeholder="Password" clearable show-password) + el-checkbox(v-model="loginForm.saveCredentials") Save Credentials + el-form-item(style="margin-top:35px") + el-button(native-type="submit" type="primary" :loading="loginForm.loading" style="width:100%") Login + el-form-item + el-button(:loading="loginForm.loading" style="width:100%" @click="loginWithSteam()") Login with Steam + div(style="text-align:center;font-size:12px") + p © 2019-2020 #[a(href="https://github.com/pypy-vrc" target="_blank") pypy] (mina#5656) + p VRCX is an assistant application for provide information about manage friendship. this application uses unofficial VRChat API (VRCSDK). + p VRCX isn't endorsed by VRChat and doesn't reflect the views or opinions of VRChat or anyone officially involved in producing or managing VRChat. VRChat is trademark of VRChat Inc. VRChat © VRChat Inc. + p pypy is not responsible for any problems caused by VRCX. Use at your own risk! //- menu .x-menu-container @@ -572,7 +587,7 @@ html el-radio(label="Friends" v-model="notificationOnlineOfflineFilter") Friends el-radio(label="Off" v-model="notificationOnlineOfflineFilter") Off div(style="margin-top:30px") - span(style="font-weight:bold") Window + span(style="font-weight:bold") Application div(style="font-size:12px;margin-top:5px") span(style="display:inline-block;min-width:150px") Start at Windows startup el-switch(v-model="isStartAtWindowsStartup") @@ -582,6 +597,9 @@ html div(style="font-size:12px;margin-top:5px") span(style="display:inline-block;min-width:150px") Close to tray el-switch(v-model="isCloseToTray") + div(style="font-size:12px;margin-top:5px") + span(style="display:inline-block;min-width:150px") Auto login + el-switch(v-model="isAutoLogin") div(style="margin-top:45px;border-top:1px solid #eee;padding-top:30px") span(style="font-weight:bold") Legal Notice div(style="margin-top:5px;font-size:12px")