diff --git a/app/assets/js/authmanager.js b/app/assets/js/authmanager.js index 1cf85d2..612396d 100644 --- a/app/assets/js/authmanager.js +++ b/app/assets/js/authmanager.js @@ -72,8 +72,9 @@ exports.addMojangAccount = async function(username, password){ * @param {string} skirdaToken * */ exports.addSkirdaAccount = async function(uuid, accessToken, username, displayName, skirdaToken){ - ConfigManager.addSkirdaAccount(uuid, accessToken, username, displayName, skirdaToken) + const ret = ConfigManager.addSkirdaAccount(uuid, accessToken, username, displayName, skirdaToken) ConfigManager.save() + return ret } exports.addOfflineAccount = async function(usernameOffline){ @@ -293,6 +294,40 @@ async function validateSelectedMojangAccount(){ } } +} +// require('./scripts/loginSkirdaDiscord') +/** + * Validate the selected account with Skirda's authserver. If the account is not valid, + * we will attempt to refresh the access token and update that value. If that fails, a + * new login will be required. + * + * @returns {Promise.} Promise which resolves to true if the access token is valid, + * otherwise false. + */ +async function validateSelectedSkirdaAccount(){ + const current = ConfigManager.getSelectedAccount() + const result = await SkirdaDiscordAuth.ValidateAccount(current.accessToken) + // const response = await MojangRestAPI.validate(current.accessToken, ConfigManager.getClientToken()) + // const isValid = response.data + if(!result){ + const refreshResponse = await MojangRestAPI.refresh(current.accessToken, ConfigManager.getClientToken()) + if(refreshResponse.responseStatus === RestResponseStatus.SUCCESS) { + const session = refreshResponse.data + ConfigManager.updateMojangAuthAccount(current.uuid, session.accessToken) + ConfigManager.save() + } else { + log.error('Error while validating selected profile:', refreshResponse.error) + log.info('Account access token is invalid.') + return false + } + log.info('Account access token validated.') + return true + } else { + log.info('Account access token validated.') + return true + } + + } /** @@ -367,10 +402,14 @@ async function validateSelectedMicrosoftAccount(){ exports.validateSelected = async function(){ const current = ConfigManager.getSelectedAccount() - if(current.type === 'microsoft') { - return await validateSelectedMicrosoftAccount() - } else { - return await validateSelectedMojangAccount() + switch (current.type) { + case 'mojang': + return await validateSelectedMojangAccount() + // break + case 'microsoft': + return await validateSelectedMicrosoftAccount() + // break + case 'skirda': + return await validateSelectedSkirdaAccount() } - } diff --git a/app/assets/js/scripts/landing.js b/app/assets/js/scripts/landing.js index 3bce85e..591f1f8 100644 --- a/app/assets/js/scripts/landing.js +++ b/app/assets/js/scripts/landing.js @@ -144,6 +144,7 @@ document.getElementById('avatarOverlay').onclick = async e => { // Bind selected account function updateSelectedAccount(authUser){ let username = Lang.queryJS('landing.selectedAccount.noAccountSelected') + console.log(authUser) if(authUser != null){ if(authUser.displayName != null){ username = authUser.displayName diff --git a/app/assets/js/scripts/loginSkirdaDiscord.js b/app/assets/js/scripts/loginSkirdaDiscord.js index 050eb43..963d4f1 100644 --- a/app/assets/js/scripts/loginSkirdaDiscord.js +++ b/app/assets/js/scripts/loginSkirdaDiscord.js @@ -2,8 +2,14 @@ // const fs = require('fs') // const {addSkirdaAccount} = require('configmanager') // const auth_api_url = 'http://192.168.88.10:8083' -const auth_api_url = 'http://skirda-auth.brzezinski.ru' +const auth_api_url = 'http://localhost:8083' +// const auth_api_url = 'http://skirda-auth.brzezinski.ru' +function uuidv4() { + return '10000000-1000-4000-8000-100000000000'.replace(/[018]/g, c => + (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16) + ) +} class SkirdaDiscordAuth{ /** * @typedef {Object} DiscordRedirectAuth @@ -12,9 +18,9 @@ class SkirdaDiscordAuth{ * * @return {Promise} * */ - temp_installId = '26c175e2-71bd-4d80-9553-cc1575fc8ef9' - async Init(){ - const resp = await fetch(`${auth_api_url}/v1/auth/discord/init?installId=${this.temp_installId}`) + static temp_installId = uuidv4() + static async Init(){ + const resp = await fetch(`${auth_api_url}/v1/auth/discord/init?installId=${SkirdaDiscordAuth.temp_installId}`) if (resp.statusCode !== 200){ return await resp.text() @@ -28,15 +34,13 @@ class SkirdaDiscordAuth{ // * @param timeout {number} Timeout to poll in seconds * @return {SkirdaUserResp | string} Result of OAuth login */ - async CyclePolling(requestId){ + static async CyclePolling(requestId){ for (let i = 0; i < 15; i++) { - const resp = await this._poll(requestId) - - // console.log(resp) + const resp = await SkirdaDiscordAuth._poll(requestId) switch (resp.status){ case 204: - await this._sleep(4000) + await SkirdaDiscordAuth._sleep(4000) continue case 200: return await resp.json() @@ -60,7 +64,7 @@ class SkirdaDiscordAuth{ * @param jwtToken {string} JWT Token for auth * @return {YggProfile | string} Result of auth */ - async YggdrasilAuth(jwtToken){ + static async YggdrasilAuth(jwtToken){ const resp = await fetch(`${auth_api_url}/yggdrasil/skirda/authenticate`, { headers:{ 'Content-Type': 'application/json', @@ -85,49 +89,90 @@ class SkirdaDiscordAuth{ * @param requestId {string} * @return {Response} * */ - async _poll(requestId){ - const resp = await fetch(`${auth_api_url}/v1/auth/discord/periodicPolling?installId=${this.temp_installId}&requestId=${requestId}`) + static async _poll(requestId){ + const resp = await fetch(`${auth_api_url}/v1/auth/discord/periodicPolling?installId=${SkirdaDiscordAuth.temp_installId}&requestId=${requestId}`) return resp } - _sleepSetTimeout_ctrl + static _sleepSetTimeout_ctrl /** * @param ms {number} * @return {boolean} */ - async _sleep(ms) { + static async _sleep(ms) { clearInterval(this._sleepSetTimeout_ctrl) return new Promise(resolve => this._sleepSetTimeout_ctrl = setTimeout(resolve, ms)) } + + static async ValidateAccount(jwtToken) { + const resp = await fetch(`${auth_api_url}/v1/auth/refresh`,{ + headers:{ + 'Content-Type': 'application/json', + 'Authorization': jwtToken + } + }) + // console.log(resp, resp.statusCode) + return resp.status === 200 + } } -const skAuth = new SkirdaDiscordAuth() +// const skAuth = new SkirdaDiscordAuth() const loginSkirdaDiscordButton = document.getElementById('loginSkirdaDiscordInitAuth') - +/** + * @return boolean + * */ async function InitSkirdaDiscordLogin (){ - const res = await skAuth.Init() + const res = await SkirdaDiscordAuth.Init() + let redir + try { + redir = JSON.parse(res) + } catch (e) { + SpawnError(Lang.queryJS('login.error.unknown')) + return + } + + // console.log(redir) - const redir = JSON.parse(res) //FIXME - console.log(redir) const resOpenUrl = await shell.openExternal(redir.redirectUrl) - const skirdaAuth = await skAuth.CyclePolling(redir.requestId) + const skirdaAuth = await SkirdaDiscordAuth.CyclePolling(redir.requestId) //TODO validate resp - console.log(skirdaAuth) - // skirdaAuth.skirdaUserId = '2a5fd868-1ac5-4ccf-a22f-183822de2d61' + // console.log(skirdaAuth) - const yggAuth = await skAuth.YggdrasilAuth(skirdaAuth.token) - //TODO validate resp - const yggAuthRes = JSON.parse(yggAuth) - console.log(yggAuthRes) + if (typeof skirdaAuth.token !== 'string'){ + SpawnError(Lang.queryJS('login.error.unknown')) + return + } + + const yggAuth = await SkirdaDiscordAuth.YggdrasilAuth(skirdaAuth.token) + let yggAuthRes + try { + yggAuthRes = JSON.parse(yggAuth) + } catch (e) { + SpawnError(Lang.queryJS('login.error.unknown')) + return + } + // console.log(yggAuthRes) - AuthManager.addSkirdaAccount(yggAuthRes.profile.id, skirdaAuth.token, skirdaAuth.skirdaUserId, yggAuthRes.profile.name, skirdaAuth.token) + AuthManager.addSkirdaAccount(yggAuthRes.profile.id, skirdaAuth.token, skirdaAuth.skirdaUserId, yggAuthRes.profile.name, skirdaAuth.token).then((value) => { + updateSelectedAccount(value) + }) setTimeout(() => { + switchView(VIEWS.loginSkirdaDiscord, VIEWS.landing, 500, 500) }, 1000) } + +function SpawnError(actualDisplayableError){ + setOverlayContent(actualDisplayableError.title, actualDisplayableError.desc, Lang.queryJS('login.tryAgain')) + setOverlayHandler(() => { + formDisabled(false) + toggleOverlay(false) + }) + toggleOverlay(true) +} \ No newline at end of file diff --git a/app/assets/js/scripts/settings.js b/app/assets/js/scripts/settings.js index 46a7b84..554c194 100644 --- a/app/assets/js/scripts/settings.js +++ b/app/assets/js/scripts/settings.js @@ -667,7 +667,7 @@ function populateAuthAccounts(){ authKeys.forEach((val) => { const acc = authAccounts[val] - console.log(acc) + // console.log(acc) const accHtml = `