mirror of
https://github.com/dscalzi/HeliosLauncher.git
synced 2024-12-22 19:52:14 -08:00
Compare commits
No commits in common. "2a99d72ddedd382781ec2b763f3678b2ffbb8a33" and "63d15b024e6d7ebc67c161992b7fff24e91187e6" have entirely different histories.
2a99d72dde
...
63d15b024e
@ -31,7 +31,6 @@
|
|||||||
<div id="main">
|
<div id="main">
|
||||||
<%- include('welcome') %>
|
<%- include('welcome') %>
|
||||||
<%- include('login') %>
|
<%- include('login') %>
|
||||||
<%- include('waiting') %>
|
|
||||||
<%- include('settings') %>
|
<%- include('settings') %>
|
||||||
<%- include('landing') %>
|
<%- include('landing') %>
|
||||||
</div>
|
</div>
|
||||||
|
@ -872,85 +872,6 @@ body, button {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
* *
|
|
||||||
* Waiting View (waiting.ejs) *
|
|
||||||
* *
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
#waitingContainer {
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
transition: filter 0.25s ease;
|
|
||||||
background: rgba(0, 0, 0, 0.50);
|
|
||||||
}
|
|
||||||
|
|
||||||
#waitingContent {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
width: 50%;
|
|
||||||
top: -10%;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.waitingSpinner:before {
|
|
||||||
transform: rotateX(60deg) rotateY(45deg) rotateZ(45deg);
|
|
||||||
animation: 750ms rotateBefore infinite linear reverse;
|
|
||||||
}
|
|
||||||
.waitingSpinner:after {
|
|
||||||
transform: rotateX(240deg) rotateY(45deg) rotateZ(45deg);
|
|
||||||
animation: 750ms rotateAfter infinite linear;
|
|
||||||
}
|
|
||||||
.waitingSpinner:before,
|
|
||||||
.waitingSpinner:after {
|
|
||||||
box-sizing: border-box;
|
|
||||||
content: '';
|
|
||||||
display: block;
|
|
||||||
position: fixed;
|
|
||||||
top: calc(50% - 5em);
|
|
||||||
/* left: 50%; */
|
|
||||||
margin-top: -5em;
|
|
||||||
margin-left: -5em;
|
|
||||||
width: 10em;
|
|
||||||
height: 10em;
|
|
||||||
transform-style: preserve-3d;
|
|
||||||
transform-origin: 50%;
|
|
||||||
transform: rotateY(50%);
|
|
||||||
perspective-origin: 50% 50%;
|
|
||||||
perspective: 340px;
|
|
||||||
background-size: 10em 10em;
|
|
||||||
background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+Cjxzdmcgd2lkdGg9IjI2NnB4IiBoZWlnaHQ9IjI5N3B4IiB2aWV3Qm94PSIwIDAgMjY2IDI5NyIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWxuczpza2V0Y2g9Imh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaC9ucyI+CiAgICA8dGl0bGU+c3Bpbm5lcjwvdGl0bGU+CiAgICA8ZGVzY3JpcHRpb24+Q3JlYXRlZCB3aXRoIFNrZXRjaCAoaHR0cDovL3d3dy5ib2hlbWlhbmNvZGluZy5jb20vc2tldGNoKTwvZGVzY3JpcHRpb24+CiAgICA8ZGVmcz48L2RlZnM+CiAgICA8ZyBpZD0iUGFnZS0xIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiBza2V0Y2g6dHlwZT0iTVNQYWdlIj4KICAgICAgICA8cGF0aCBkPSJNMTcxLjUwNzgxMywzLjI1MDAwMDM4IEMyMjYuMjA4MTgzLDEyLjg1NzcxMTEgMjk3LjExMjcyMiw3MS40OTEyODIzIDI1MC44OTU1OTksMTA4LjQxMDE1NSBDMjE2LjU4MjAyNCwxMzUuODIwMzEgMTg2LjUyODQwNSw5Ny4wNjI0OTY0IDE1Ni44MDA3NzQsODUuNzczNDM0NiBDMTI3LjA3MzE0Myw3NC40ODQzNzIxIDc2Ljg4ODQ2MzIsODQuMjE2MTQ2MiA2MC4xMjg5MDY1LDEwOC40MTAxNTMgQy0xNS45ODA0Njg1LDIxOC4yODEyNDcgMTQ1LjI3NzM0NCwyOTYuNjY3OTY4IDE0NS4yNzczNDQsMjk2LjY2Nzk2OCBDMTQ1LjI3NzM0NCwyOTYuNjY3OTY4IC0yNS40NDkyMTg3LDI1Ny4yNDIxOTggMy4zOTg0Mzc1LDEwOC40MTAxNTUgQzE2LjMwNzA2NjEsNDEuODExNDE3NCA4NC43Mjc1ODI5LC0xMS45OTIyOTg1IDE3MS41MDc4MTMsMy4yNTAwMDAzOCBaIiBpZD0iUGF0aC0xIiBmaWxsPSIjZmZmZmZmIiBza2V0Y2g6dHlwZT0iTVNTaGFwZUdyb3VwIj48L3BhdGg+CiAgICA8L2c+Cjwvc3ZnPg==);
|
|
||||||
}
|
|
||||||
|
|
||||||
#waitingTextContainer {
|
|
||||||
position: fixed;
|
|
||||||
top: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes rotateBefore {
|
|
||||||
from {
|
|
||||||
transform: rotateX(60deg) rotateY(45deg) rotateZ(0deg);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
transform: rotateX(60deg) rotateY(45deg) rotateZ(-360deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes rotateAfter {
|
|
||||||
from {
|
|
||||||
transform: rotateX(240deg) rotateY(45deg) rotateZ(0deg);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
transform: rotateX(240deg) rotateY(45deg) rotateZ(360deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* *
|
* *
|
||||||
* Settings View (sttings.ejs) *
|
* Settings View (sttings.ejs) *
|
||||||
|
@ -11,17 +11,15 @@
|
|||||||
// Requirements
|
// Requirements
|
||||||
const ConfigManager = require('./configmanager')
|
const ConfigManager = require('./configmanager')
|
||||||
const { LoggerUtil } = require('helios-core')
|
const { LoggerUtil } = require('helios-core')
|
||||||
const { RestResponseStatus } = require('helios-core/common')
|
|
||||||
const { MojangRestAPI, mojangErrorDisplayable, MojangErrorCode } = require('helios-core/mojang')
|
const { MojangRestAPI, mojangErrorDisplayable, MojangErrorCode } = require('helios-core/mojang')
|
||||||
const { MicrosoftAuth } = require('helios-core/microsoft')
|
const { RestResponseStatus } = require('helios-core/common')
|
||||||
const { AZURE_CLIENT_ID } = require('./ipcconstants')
|
|
||||||
|
|
||||||
const log = LoggerUtil.getLogger('AuthManager')
|
const log = LoggerUtil.getLogger('AuthManager')
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a Mojang account. This will authenticate the given credentials with Mojang's
|
* Add an account. This will authenticate the given credentials with Mojang's
|
||||||
* authserver. The resultant data will be stored as an auth account in the
|
* authserver. The resultant data will be stored as an auth account in the
|
||||||
* configuration database.
|
* configuration database.
|
||||||
*
|
*
|
||||||
@ -29,7 +27,7 @@ const log = LoggerUtil.getLogger('AuthManager')
|
|||||||
* @param {string} password The account password.
|
* @param {string} password The account password.
|
||||||
* @returns {Promise.<Object>} Promise which resolves the resolved authenticated account object.
|
* @returns {Promise.<Object>} Promise which resolves the resolved authenticated account object.
|
||||||
*/
|
*/
|
||||||
exports.addMojangAccount = async function(username, password) {
|
exports.addAccount = async function(username, password){
|
||||||
try {
|
try {
|
||||||
const response = await MojangRestAPI.authenticate(username, password, ConfigManager.getClientToken())
|
const response = await MojangRestAPI.authenticate(username, password, ConfigManager.getClientToken())
|
||||||
console.log(response)
|
console.log(response)
|
||||||
@ -37,7 +35,7 @@ exports.addMojangAccount = async function(username, password) {
|
|||||||
|
|
||||||
const session = response.data
|
const session = response.data
|
||||||
if(session.selectedProfile != null){
|
if(session.selectedProfile != null){
|
||||||
const ret = ConfigManager.addMojangAuthAccount(session.selectedProfile.id, session.accessToken, username, session.selectedProfile.name)
|
const ret = ConfigManager.addAuthAccount(session.selectedProfile.id, session.accessToken, username, session.selectedProfile.name)
|
||||||
if(ConfigManager.getClientToken() == null){
|
if(ConfigManager.getClientToken() == null){
|
||||||
ConfigManager.setClientToken(session.clientToken)
|
ConfigManager.setClientToken(session.clientToken)
|
||||||
}
|
}
|
||||||
@ -57,113 +55,14 @@ exports.addMojangAccount = async function(username, password) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const AUTH_MODE = { FULL: 0, MS_REFRESH: 1, MC_REFRESH: 2 }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform the full MS Auth flow in a given mode.
|
* Remove an account. This will invalidate the access token associated
|
||||||
*
|
|
||||||
* AUTH_MODE.FULL = Full authorization for a new account.
|
|
||||||
* AUTH_MODE.MS_REFRESH = Full refresh authorization.
|
|
||||||
* AUTH_MODE.MC_REFRESH = Refresh of the MC token, reusing the MS token.
|
|
||||||
*
|
|
||||||
* @param {string} entryCode FULL-AuthCode. MS_REFRESH=refreshToken, MC_REFRESH=accessToken
|
|
||||||
* @param {*} authMode The auth mode.
|
|
||||||
* @returns An object with all auth data. AccessToken object will be null when mode is MC_REFRESH.
|
|
||||||
*/
|
|
||||||
async function fullMicrosoftAuthFlow(entryCode, authMode) {
|
|
||||||
|
|
||||||
let accessTokenRaw
|
|
||||||
let accessToken
|
|
||||||
if(authMode !== AUTH_MODE.MC_REFRESH) {
|
|
||||||
const accessTokenResponse = await MicrosoftAuth.getAccessToken(entryCode, authMode === AUTH_MODE.MS_REFRESH, AZURE_CLIENT_ID)
|
|
||||||
if(accessTokenResponse.responseStatus === RestResponseStatus.ERROR) {
|
|
||||||
// TODO Fail.
|
|
||||||
return // TODO
|
|
||||||
}
|
|
||||||
accessToken = accessTokenResponse.data
|
|
||||||
accessTokenRaw = accessToken.access_token
|
|
||||||
} else {
|
|
||||||
accessTokenRaw = entryCode
|
|
||||||
}
|
|
||||||
|
|
||||||
const xblResponse = await MicrosoftAuth.getXBLToken(accessTokenRaw)
|
|
||||||
if(xblResponse.responseStatus === RestResponseStatus.ERROR) {
|
|
||||||
// TODO Fail.
|
|
||||||
return // TODO
|
|
||||||
}
|
|
||||||
const xstsResonse = await MicrosoftAuth.getXSTSToken(xblResponse.data)
|
|
||||||
if(xstsResonse.responseStatus === RestResponseStatus.ERROR) {
|
|
||||||
// TODO Fail.
|
|
||||||
return // TODO
|
|
||||||
}
|
|
||||||
const mcTokenResponse = await MicrosoftAuth.getMCAccessToken(xstsResonse.data)
|
|
||||||
if(mcTokenResponse.responseStatus === RestResponseStatus.ERROR) {
|
|
||||||
// TODO Fail.
|
|
||||||
return // TODO
|
|
||||||
}
|
|
||||||
const mcProfileResponse = await MicrosoftAuth.getMCProfile(mcTokenResponse.data.access_token)
|
|
||||||
if(mcProfileResponse.responseStatus === RestResponseStatus.ERROR) {
|
|
||||||
// TODO Fail.
|
|
||||||
return // TODO
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
accessToken,
|
|
||||||
accessTokenRaw,
|
|
||||||
xbl: xblResponse.data,
|
|
||||||
xsts: xstsResonse.data,
|
|
||||||
mcToken: mcTokenResponse.data,
|
|
||||||
mcProfile: mcProfileResponse.data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculate the expiry date. Advance the expiry time by 10 seconds
|
|
||||||
* to reduce the liklihood of working with an expired token.
|
|
||||||
*
|
|
||||||
* @param {number} nowMs Current time milliseconds.
|
|
||||||
* @param {number} epiresInS Expires in (seconds)
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
async function calculateExpiryDate(nowMs, epiresInS) {
|
|
||||||
return nowMs + ((epiresInS-10)*1000)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a Microsoft account. This will pass the provided auth code to Mojang's OAuth2.0 flow.
|
|
||||||
* The resultant data will be stored as an auth account in the configuration database.
|
|
||||||
*
|
|
||||||
* @param {string} authCode The authCode obtained from microsoft.
|
|
||||||
* @returns {Promise.<Object>} Promise which resolves the resolved authenticated account object.
|
|
||||||
*/
|
|
||||||
exports.addMicrosoftAccount = async function(authCode) {
|
|
||||||
|
|
||||||
const fullAuth = await fullMicrosoftAuthFlow(authCode, AUTH_MODE.FULL)
|
|
||||||
|
|
||||||
// Advance expiry by 10 seconds to avoid close calls.
|
|
||||||
const now = new Date().getTime()
|
|
||||||
|
|
||||||
const ret = ConfigManager.addMicrosoftAuthAccount(
|
|
||||||
fullAuth.mcProfile.id,
|
|
||||||
fullAuth.mcToken.access_token,
|
|
||||||
fullAuth.mcProfile.name,
|
|
||||||
calculateExpiryDate(now, fullAuth.mcToken.expires_in),
|
|
||||||
fullAuth.accessToken.access_token,
|
|
||||||
fullAuth.accessToken.refresh_token,
|
|
||||||
calculateExpiryDate(now, fullAuth.accessToken.expires_in)
|
|
||||||
)
|
|
||||||
ConfigManager.save()
|
|
||||||
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a Mojang account. This will invalidate the access token associated
|
|
||||||
* with the account and then remove it from the database.
|
* with the account and then remove it from the database.
|
||||||
*
|
*
|
||||||
* @param {string} uuid The UUID of the account to be removed.
|
* @param {string} uuid The UUID of the account to be removed.
|
||||||
* @returns {Promise.<void>} Promise which resolves to void when the action is complete.
|
* @returns {Promise.<void>} Promise which resolves to void when the action is complete.
|
||||||
*/
|
*/
|
||||||
exports.removeMojangAccount = async function(uuid){
|
exports.removeAccount = async function(uuid){
|
||||||
try {
|
try {
|
||||||
const authAcc = ConfigManager.getAuthAccount(uuid)
|
const authAcc = ConfigManager.getAuthAccount(uuid)
|
||||||
const response = await MojangRestAPI.invalidate(authAcc.accessToken, ConfigManager.getClientToken())
|
const response = await MojangRestAPI.invalidate(authAcc.accessToken, ConfigManager.getClientToken())
|
||||||
@ -181,33 +80,17 @@ exports.removeMojangAccount = async function(uuid){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a Microsoft account. It is expected that the caller will invoke the OAuth logout
|
|
||||||
* through the ipc renderer.
|
|
||||||
*
|
|
||||||
* @param {string} uuid The UUID of the account to be removed.
|
|
||||||
* @returns {Promise.<void>} Promise which resolves to void when the action is complete.
|
|
||||||
*/
|
|
||||||
exports.removeMicrosoftAccount = async function(uuid){
|
|
||||||
try {
|
|
||||||
ConfigManager.removeAuthAccount(uuid)
|
|
||||||
ConfigManager.save()
|
|
||||||
return Promise.resolve()
|
|
||||||
} catch (err){
|
|
||||||
log.error('Error while removing account', err)
|
|
||||||
return Promise.reject(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate the selected account with Mojang's authserver. If the account is not valid,
|
* Validate the selected account with Mojang's authserver. If the account is not valid,
|
||||||
* we will attempt to refresh the access token and update that value. If that fails, a
|
* we will attempt to refresh the access token and update that value. If that fails, a
|
||||||
* new login will be required.
|
* new login will be required.
|
||||||
*
|
*
|
||||||
|
* **Function is WIP**
|
||||||
|
*
|
||||||
* @returns {Promise.<boolean>} Promise which resolves to true if the access token is valid,
|
* @returns {Promise.<boolean>} Promise which resolves to true if the access token is valid,
|
||||||
* otherwise false.
|
* otherwise false.
|
||||||
*/
|
*/
|
||||||
async function validateSelectedMojangAccount(){
|
exports.validateSelected = async function(){
|
||||||
const current = ConfigManager.getSelectedAccount()
|
const current = ConfigManager.getSelectedAccount()
|
||||||
const response = await MojangRestAPI.validate(current.accessToken, ConfigManager.getClientToken())
|
const response = await MojangRestAPI.validate(current.accessToken, ConfigManager.getClientToken())
|
||||||
|
|
||||||
@ -217,7 +100,7 @@ async function validateSelectedMojangAccount(){
|
|||||||
const refreshResponse = await MojangRestAPI.refresh(current.accessToken, ConfigManager.getClientToken())
|
const refreshResponse = await MojangRestAPI.refresh(current.accessToken, ConfigManager.getClientToken())
|
||||||
if(refreshResponse.responseStatus === RestResponseStatus.SUCCESS) {
|
if(refreshResponse.responseStatus === RestResponseStatus.SUCCESS) {
|
||||||
const session = refreshResponse.data
|
const session = refreshResponse.data
|
||||||
ConfigManager.updateMojangAuthAccount(current.uuid, session.accessToken)
|
ConfigManager.updateAuthAccount(current.uuid, session.accessToken)
|
||||||
ConfigManager.save()
|
ConfigManager.save()
|
||||||
} else {
|
} else {
|
||||||
log.error('Error while validating selected profile:', refreshResponse.error)
|
log.error('Error while validating selected profile:', refreshResponse.error)
|
||||||
@ -233,83 +116,3 @@ async function validateSelectedMojangAccount(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate the selected account with Microsoft'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.<boolean>} Promise which resolves to true if the access token is valid,
|
|
||||||
* otherwise false.
|
|
||||||
*/
|
|
||||||
async function validateSelectedMicrosoftAccount(){
|
|
||||||
const current = ConfigManager.getSelectedAccount()
|
|
||||||
const now = new Date().getTime()
|
|
||||||
const mcExpiresAt = Date.parse(current.expiresAt)
|
|
||||||
const mcExpired = now >= mcExpiresAt
|
|
||||||
|
|
||||||
if(!mcExpired) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// MC token expired. Check MS token.
|
|
||||||
|
|
||||||
const msExpiresAt = Date.parse(current.microsoft.expires_at)
|
|
||||||
const msExpired = now >= msExpiresAt
|
|
||||||
|
|
||||||
if(msExpired) {
|
|
||||||
// MS expired, do full refresh.
|
|
||||||
try {
|
|
||||||
const res = await fullMicrosoftAuthFlow(current.microsoft.refresh_token, AUTH_MODE.MS_REFRESH)
|
|
||||||
|
|
||||||
ConfigManager.updateMicrosoftAuthAccount(
|
|
||||||
current.uuid,
|
|
||||||
res.mcToken.access_token,
|
|
||||||
res.accessToken.access_token,
|
|
||||||
res.accessToken.refresh_token,
|
|
||||||
calculateExpiryDate(now, res.accessToken.expires_in),
|
|
||||||
calculateExpiryDate(now, res.mcToken.expires_in)
|
|
||||||
)
|
|
||||||
ConfigManager.save()
|
|
||||||
return true
|
|
||||||
} catch(err) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Only MC expired, use existing MS token.
|
|
||||||
try {
|
|
||||||
const res = await fullMicrosoftAuthFlow(current.microsoft.access_token, AUTH_MODE.MC_REFRESH)
|
|
||||||
|
|
||||||
ConfigManager.updateMicrosoftAuthAccount(
|
|
||||||
current.uuid,
|
|
||||||
res.mcToken.access_token,
|
|
||||||
current.microsoft.access_token,
|
|
||||||
current.microsoft.refresh_token,
|
|
||||||
current.microsoft.expires_at,
|
|
||||||
calculateExpiryDate(now, res.mcToken.expires_in)
|
|
||||||
)
|
|
||||||
ConfigManager.save()
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
catch(err) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate the selected auth account.
|
|
||||||
*
|
|
||||||
* @returns {Promise.<boolean>} Promise which resolves to true if the access token is valid,
|
|
||||||
* otherwise false.
|
|
||||||
*/
|
|
||||||
exports.validateSelected = async function(){
|
|
||||||
const current = ConfigManager.getSelectedAccount()
|
|
||||||
|
|
||||||
if(current.type === 'microsoft') {
|
|
||||||
return await validateSelectedMicrosoftAccount()
|
|
||||||
} else {
|
|
||||||
return await validateSelectedMojangAccount()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -318,21 +318,20 @@ exports.getAuthAccount = function(uuid){
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the access token of an authenticated mojang account.
|
* Update the access token of an authenticated account.
|
||||||
*
|
*
|
||||||
* @param {string} uuid The uuid of the authenticated account.
|
* @param {string} uuid The uuid of the authenticated account.
|
||||||
* @param {string} accessToken The new Access Token.
|
* @param {string} accessToken The new Access Token.
|
||||||
*
|
*
|
||||||
* @returns {Object} The authenticated account object created by this action.
|
* @returns {Object} The authenticated account object created by this action.
|
||||||
*/
|
*/
|
||||||
exports.updateMojangAuthAccount = function(uuid, accessToken){
|
exports.updateAuthAccount = function(uuid, accessToken){
|
||||||
config.authenticationDatabase[uuid].accessToken = accessToken
|
config.authenticationDatabase[uuid].accessToken = accessToken
|
||||||
config.authenticationDatabase[uuid].type = 'mojang' // For gradual conversion.
|
|
||||||
return config.authenticationDatabase[uuid]
|
return config.authenticationDatabase[uuid]
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds an authenticated mojang account to the database to be stored.
|
* Adds an authenticated account to the database to be stored.
|
||||||
*
|
*
|
||||||
* @param {string} uuid The uuid of the authenticated account.
|
* @param {string} uuid The uuid of the authenticated account.
|
||||||
* @param {string} accessToken The accessToken of the authenticated account.
|
* @param {string} accessToken The accessToken of the authenticated account.
|
||||||
@ -341,10 +340,9 @@ exports.updateMojangAuthAccount = function(uuid, accessToken){
|
|||||||
*
|
*
|
||||||
* @returns {Object} The authenticated account object created by this action.
|
* @returns {Object} The authenticated account object created by this action.
|
||||||
*/
|
*/
|
||||||
exports.addMojangAuthAccount = function(uuid, accessToken, username, displayName){
|
exports.addAuthAccount = function(uuid, accessToken, username, displayName){
|
||||||
config.selectedAccount = uuid
|
config.selectedAccount = uuid
|
||||||
config.authenticationDatabase[uuid] = {
|
config.authenticationDatabase[uuid] = {
|
||||||
type: 'mojang',
|
|
||||||
accessToken,
|
accessToken,
|
||||||
username: username.trim(),
|
username: username.trim(),
|
||||||
uuid: uuid.trim(),
|
uuid: uuid.trim(),
|
||||||
@ -353,58 +351,6 @@ exports.addMojangAuthAccount = function(uuid, accessToken, username, displayName
|
|||||||
return config.authenticationDatabase[uuid]
|
return config.authenticationDatabase[uuid]
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the tokens of an authenticated microsoft account.
|
|
||||||
*
|
|
||||||
* @param {string} uuid The uuid of the authenticated account.
|
|
||||||
* @param {string} accessToken The new Access Token.
|
|
||||||
* @param {string} msAccessToken The new Microsoft Access Token
|
|
||||||
* @param {string} msRefreshToken The new Microsoft Refresh Token
|
|
||||||
* @param {date} msExpires The date when the microsoft access token expires
|
|
||||||
* @param {date} mcExpires The date when the mojang access token expires
|
|
||||||
*
|
|
||||||
* @returns {Object} The authenticated account object created by this action.
|
|
||||||
*/
|
|
||||||
exports.updateMicrosoftAuthAccount = function(uuid, accessToken, msAccessToken, msRefreshToken, msExpires, mcExpires) {
|
|
||||||
config.authenticationDatabase[uuid].accessToken = accessToken
|
|
||||||
config.authenticationDatabase[uuid].expiresAt = mcExpires
|
|
||||||
config.authenticationDatabase[uuid].microsoft.access_token = msAccessToken
|
|
||||||
config.authenticationDatabase[uuid].microsoft.refresh_token = msRefreshToken
|
|
||||||
config.authenticationDatabase[uuid].microsoft.expires_at = msExpires
|
|
||||||
return config.authenticationDatabase[uuid]
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds an authenticated microsoft account to the database to be stored.
|
|
||||||
*
|
|
||||||
* @param {string} uuid The uuid of the authenticated account.
|
|
||||||
* @param {string} accessToken The accessToken of the authenticated account.
|
|
||||||
* @param {string} name The in game name of the authenticated account.
|
|
||||||
* @param {date} mcExpires The date when the mojang access token expires
|
|
||||||
* @param {string} msAccessToken The microsoft access token
|
|
||||||
* @param {string} msRefreshToken The microsoft refresh token
|
|
||||||
* @param {date} msExpires The date when the microsoft access token expires
|
|
||||||
*
|
|
||||||
* @returns {Object} The authenticated account object created by this action.
|
|
||||||
*/
|
|
||||||
exports.addMicrosoftAuthAccount = function(uuid, accessToken, name, mcExpires, msAccessToken, msRefreshToken, msExpires) {
|
|
||||||
config.selectedAccount = uuid
|
|
||||||
config.authenticationDatabase[uuid] = {
|
|
||||||
type: 'microsoft',
|
|
||||||
accessToken,
|
|
||||||
username: name.trim(),
|
|
||||||
uuid: uuid.trim(),
|
|
||||||
displayName: name.trim(),
|
|
||||||
expiresAt: mcExpires,
|
|
||||||
microsoft: {
|
|
||||||
access_token: msAccessToken,
|
|
||||||
refresh_token: msRefreshToken,
|
|
||||||
expires_at: msExpires
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return config.authenticationDatabase[uuid]
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove an authenticated account from the database. If the account
|
* Remove an authenticated account from the database. If the account
|
||||||
* was also the selected account, a new one will be selected. If there
|
* was also the selected account, a new one will be selected. If there
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
exports.AZURE_CLIENT_ID = 'FILL-IN'
|
|
||||||
exports.MSFT_OPCODE = {
|
|
||||||
OPEN_LOGIN: 'MSFT_AUTH_OPEN_LOGIN',
|
|
||||||
OPEN_LOGOUT: 'MSFT_AUTH_OPEN_LOGOUT',
|
|
||||||
REPLY_LOGIN: 'MSFT_AUTH_REPLY_LOGIN',
|
|
||||||
REPLY_LOGOUT: 'MSFT_AUTH_REPLY_LOGOUT'
|
|
||||||
}
|
|
||||||
exports.MSFT_REPLY_TYPE = {
|
|
||||||
SUCCESS: 'MSFT_AUTH_REPLY_SUCCESS',
|
|
||||||
ERROR: 'MSFT_AUTH_REPLY_ERROR'
|
|
||||||
}
|
|
||||||
exports.MSFT_ERROR = {
|
|
||||||
ALREADY_OPEN: 'MSFT_AUTH_ERR_ALREADY_OPEN',
|
|
||||||
NOT_FINISHED: 'MSFT_AUTH_ERR_NOT_FINISHED'
|
|
||||||
}
|
|
@ -21,7 +21,7 @@ const launch_details_text = document.getElementById('launch_details_text')
|
|||||||
const server_selection_button = document.getElementById('server_selection_button')
|
const server_selection_button = document.getElementById('server_selection_button')
|
||||||
const user_text = document.getElementById('user_text')
|
const user_text = document.getElementById('user_text')
|
||||||
|
|
||||||
const loggerLanding = LoggerUtil1('%c[Landing]', 'color: #000668; font-weight: bold')
|
const loggerLanding = LoggerUtil('%c[Landing]', 'color: #000668; font-weight: bold')
|
||||||
|
|
||||||
/* Launch Progress Wrapper Functions */
|
/* Launch Progress Wrapper Functions */
|
||||||
|
|
||||||
@ -293,7 +293,7 @@ function asyncSystemScan(mcVersion, launchAfter = true){
|
|||||||
toggleLaunchArea(true)
|
toggleLaunchArea(true)
|
||||||
setLaunchPercentage(0, 100)
|
setLaunchPercentage(0, 100)
|
||||||
|
|
||||||
const loggerSysAEx = LoggerUtil1('%c[SysAEx]', 'color: #353232; font-weight: bold')
|
const loggerSysAEx = LoggerUtil('%c[SysAEx]', 'color: #353232; font-weight: bold')
|
||||||
|
|
||||||
const forkEnv = JSON.parse(JSON.stringify(process.env))
|
const forkEnv = JSON.parse(JSON.stringify(process.env))
|
||||||
forkEnv.CONFIG_DIRECT_PATH = ConfigManager.getLauncherDirectory()
|
forkEnv.CONFIG_DIRECT_PATH = ConfigManager.getLauncherDirectory()
|
||||||
@ -495,8 +495,8 @@ function dlAsync(login = true){
|
|||||||
toggleLaunchArea(true)
|
toggleLaunchArea(true)
|
||||||
setLaunchPercentage(0, 100)
|
setLaunchPercentage(0, 100)
|
||||||
|
|
||||||
const loggerAEx = LoggerUtil1('%c[AEx]', 'color: #353232; font-weight: bold')
|
const loggerAEx = LoggerUtil('%c[AEx]', 'color: #353232; font-weight: bold')
|
||||||
const loggerLaunchSuite = LoggerUtil1('%c[LaunchSuite]', 'color: #000668; font-weight: bold')
|
const loggerLaunchSuite = LoggerUtil('%c[LaunchSuite]', 'color: #000668; font-weight: bold')
|
||||||
|
|
||||||
const forkEnv = JSON.parse(JSON.stringify(process.env))
|
const forkEnv = JSON.parse(JSON.stringify(process.env))
|
||||||
forkEnv.CONFIG_DIRECT_PATH = ConfigManager.getLauncherDirectory()
|
forkEnv.CONFIG_DIRECT_PATH = ConfigManager.getLauncherDirectory()
|
||||||
|
@ -21,7 +21,7 @@ const loginForm = document.getElementById('loginForm')
|
|||||||
// Control variables.
|
// Control variables.
|
||||||
let lu = false, lp = false
|
let lu = false, lp = false
|
||||||
|
|
||||||
const loggerLogin = LoggerUtil1('%c[Login]', 'color: #000668; font-weight: bold')
|
const loggerLogin = LoggerUtil('%c[Login]', 'color: #000668; font-weight: bold')
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -189,7 +189,7 @@ loginButton.addEventListener('click', () => {
|
|||||||
// Show loading stuff.
|
// Show loading stuff.
|
||||||
loginLoading(true)
|
loginLoading(true)
|
||||||
|
|
||||||
AuthManager.addMojangAccount(loginUsername.value, loginPassword.value).then((value) => {
|
AuthManager.addAccount(loginUsername.value, loginPassword.value).then((value) => {
|
||||||
updateSelectedAccount(value)
|
updateSelectedAccount(value)
|
||||||
loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.loggingIn'), Lang.queryJS('login.success'))
|
loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.loggingIn'), Lang.queryJS('login.success'))
|
||||||
$('.circle-loader').toggleClass('load-complete')
|
$('.circle-loader').toggleClass('load-complete')
|
||||||
|
@ -4,7 +4,6 @@ const semver = require('semver')
|
|||||||
|
|
||||||
const { JavaGuard } = require('./assets/js/assetguard')
|
const { JavaGuard } = require('./assets/js/assetguard')
|
||||||
const DropinModUtil = require('./assets/js/dropinmodutil')
|
const DropinModUtil = require('./assets/js/dropinmodutil')
|
||||||
const { MSFT_OPCODE, MSFT_REPLY_TYPE, MSFT_ERROR } = require('./assets/js/ipcconstants')
|
|
||||||
|
|
||||||
const settingsState = {
|
const settingsState = {
|
||||||
invalid: new Set()
|
invalid: new Set()
|
||||||
@ -315,10 +314,7 @@ settingsNavDone.onclick = () => {
|
|||||||
* Account Management Tab
|
* Account Management Tab
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const msftLoginLogger = LoggerUtil.getLogger('Microsoft Login')
|
// Bind the add account button.
|
||||||
const msftLogoutLogger = LoggerUtil.getLogger('Microsoft Logout')
|
|
||||||
|
|
||||||
// Bind the add mojang account button.
|
|
||||||
document.getElementById('settingsAddMojangAccount').onclick = (e) => {
|
document.getElementById('settingsAddMojangAccount').onclick = (e) => {
|
||||||
switchView(getCurrentView(), VIEWS.login, 500, 500, () => {
|
switchView(getCurrentView(), VIEWS.login, 500, 500, () => {
|
||||||
loginViewOnCancel = VIEWS.settings
|
loginViewOnCancel = VIEWS.settings
|
||||||
@ -327,73 +323,6 @@ document.getElementById('settingsAddMojangAccount').onclick = (e) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bind the add microsoft account button.
|
|
||||||
document.getElementById('settingsAddMicrosoftAccount').onclick = (e) => {
|
|
||||||
switchView(getCurrentView(), VIEWS.waiting, 500, 500, () => {
|
|
||||||
ipcRenderer.send(MSFT_OPCODE.OPEN_LOGIN)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bind reply for Microsoft Login.
|
|
||||||
ipcRenderer.on(MSFT_OPCODE.REPLY_LOGIN, (_, ...arguments_) => {
|
|
||||||
if (arguments_[0] === MSFT_REPLY_TYPE.ERROR) {
|
|
||||||
switchView(getCurrentView(), VIEWS.settings, 500, 500, () => {
|
|
||||||
|
|
||||||
if(arguments_.length > 1 && arguments_[1] === MSFT_ERROR.NOT_FINISHED) {
|
|
||||||
// User cancelled.
|
|
||||||
msftLoginLogger.info('Login cancelled by user.')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unexpected error.
|
|
||||||
setOverlayContent(
|
|
||||||
'Something Went Wrong',
|
|
||||||
'Microsoft authentication failed. Please try again.',
|
|
||||||
'OK'
|
|
||||||
)
|
|
||||||
setOverlayHandler(() => {
|
|
||||||
toggleOverlay(false)
|
|
||||||
})
|
|
||||||
toggleOverlay(true)
|
|
||||||
})
|
|
||||||
} else if(arguments_[0] === MSFT_REPLY_TYPE.SUCCESS) {
|
|
||||||
const queryMap = arguments_[1]
|
|
||||||
|
|
||||||
// Error from request to Microsoft.
|
|
||||||
if (Object.prototype.hasOwnProperty.call(queryMap, 'error')) {
|
|
||||||
let error = queryMap.error
|
|
||||||
let errorDesc = queryMap.error_description
|
|
||||||
title = error
|
|
||||||
description = errorDesc
|
|
||||||
if (error === 'access_denied') {
|
|
||||||
// TODO Write custom error messages.
|
|
||||||
title = error
|
|
||||||
description = errorDesc
|
|
||||||
}
|
|
||||||
setOverlayContent(
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
'OK'
|
|
||||||
)
|
|
||||||
setOverlayHandler(() => {
|
|
||||||
toggleOverlay(false)
|
|
||||||
})
|
|
||||||
toggleOverlay(true)
|
|
||||||
} else {
|
|
||||||
|
|
||||||
msftLoginLogger.info('Acquired authCode, proceeding with authentication.')
|
|
||||||
|
|
||||||
const authCode = queryMap.code
|
|
||||||
AuthManager.addMicrosoftAccount(authCode).then(value => {
|
|
||||||
updateSelectedAccount(value)
|
|
||||||
switchView(getCurrentView(), VIEWS.settings, 500, 500, () => {
|
|
||||||
prepareSettings()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bind functionality for the account selection buttons. If another account
|
* Bind functionality for the account selection buttons. If another account
|
||||||
* is selected, the UI of the previously selected account will be updated.
|
* is selected, the UI of the previously selected account will be updated.
|
||||||
@ -452,7 +381,6 @@ function bindAuthAccountLogOut(){
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
let msAccDomElementCache
|
|
||||||
/**
|
/**
|
||||||
* Process a log out.
|
* Process a log out.
|
||||||
*
|
*
|
||||||
@ -463,15 +391,7 @@ function processLogOut(val, isLastAccount){
|
|||||||
const parent = val.closest('.settingsAuthAccount')
|
const parent = val.closest('.settingsAuthAccount')
|
||||||
const uuid = parent.getAttribute('uuid')
|
const uuid = parent.getAttribute('uuid')
|
||||||
const prevSelAcc = ConfigManager.getSelectedAccount()
|
const prevSelAcc = ConfigManager.getSelectedAccount()
|
||||||
const targetAcc = ConfigManager.getAuthAccount(uuid)
|
AuthManager.removeAccount(uuid).then(() => {
|
||||||
if(targetAcc.type === 'microsoft') {
|
|
||||||
msAccDomElementCache = parent
|
|
||||||
switchView(getCurrentView(), VIEWS.waiting, 500, 500, () => {
|
|
||||||
ipcRenderer.send(MSFT_OPCODE.OPEN_LOGOUT, uuid, isLastAccount)
|
|
||||||
})
|
|
||||||
// TODO ADD LOGIC FOR LAST ACCOUNT - SAME AS SOLUTION FOR FIRST TIME LOGIN!
|
|
||||||
} else {
|
|
||||||
AuthManager.removeMojangAccount(uuid).then(() => {
|
|
||||||
if(!isLastAccount && uuid === prevSelAcc.uuid){
|
if(!isLastAccount && uuid === prevSelAcc.uuid){
|
||||||
const selAcc = ConfigManager.getSelectedAccount()
|
const selAcc = ConfigManager.getSelectedAccount()
|
||||||
refreshAuthAccountSelected(selAcc.uuid)
|
refreshAuthAccountSelected(selAcc.uuid)
|
||||||
@ -483,57 +403,6 @@ function processLogOut(val, isLastAccount){
|
|||||||
parent.remove()
|
parent.remove()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Bind reply for Microsoft Logout.
|
|
||||||
ipcRenderer.on(MSFT_OPCODE.REPLY_LOGOUT, (_, ...arguments_) => {
|
|
||||||
if (arguments_[0] === MSFT_REPLY_TYPE.ERROR) {
|
|
||||||
switchView(getCurrentView(), VIEWS.settings, 500, 500, () => {
|
|
||||||
|
|
||||||
if(arguments_.length > 1 && arguments_[1] === MSFT_ERROR.NOT_FINISHED) {
|
|
||||||
// User cancelled.
|
|
||||||
msftLogoutLogger.info('Logout cancelled by user.')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unexpected error.
|
|
||||||
setOverlayContent(
|
|
||||||
'Something Went Wrong',
|
|
||||||
'Microsoft logout failed. Please try again.',
|
|
||||||
'OK'
|
|
||||||
)
|
|
||||||
setOverlayHandler(() => {
|
|
||||||
toggleOverlay(false)
|
|
||||||
})
|
|
||||||
toggleOverlay(true)
|
|
||||||
})
|
|
||||||
} else if(arguments_[0] === MSFT_REPLY_TYPE.SUCCESS) {
|
|
||||||
|
|
||||||
const uuid = arguments_[1]
|
|
||||||
const isLastAccount = arguments_[2]
|
|
||||||
const prevSelAcc = ConfigManager.getSelectedAccount()
|
|
||||||
|
|
||||||
msftLogoutLogger.info('Logout Successful. uuid:', uuid)
|
|
||||||
|
|
||||||
AuthManager.removeMicrosoftAccount(uuid)
|
|
||||||
.then(() => {
|
|
||||||
if(!isLastAccount && uuid === prevSelAcc.uuid){
|
|
||||||
const selAcc = ConfigManager.getSelectedAccount()
|
|
||||||
refreshAuthAccountSelected(selAcc.uuid)
|
|
||||||
updateSelectedAccount(selAcc)
|
|
||||||
validateSelectedAccount()
|
|
||||||
}
|
|
||||||
if(msAccDomElementCache) {
|
|
||||||
msAccDomElementCache.remove()
|
|
||||||
msAccDomElementCache = null
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
switchView(getCurrentView(), VIEWS.settings, 500, 500)
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refreshes the status of the selected account on the auth account
|
* Refreshes the status of the selected account on the auth account
|
||||||
|
@ -18,8 +18,7 @@ const VIEWS = {
|
|||||||
landing: '#landingContainer',
|
landing: '#landingContainer',
|
||||||
login: '#loginContainer',
|
login: '#loginContainer',
|
||||||
settings: '#settingsContainer',
|
settings: '#settingsContainer',
|
||||||
welcome: '#welcomeContainer',
|
welcome: '#welcomeContainer'
|
||||||
waiting: '#waitingContainer'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The currently shown view container.
|
// The currently shown view container.
|
||||||
@ -336,7 +335,7 @@ async function validateSelectedAccount(){
|
|||||||
loginViewOnCancel = getCurrentView()
|
loginViewOnCancel = getCurrentView()
|
||||||
if(accLen > 0){
|
if(accLen > 0){
|
||||||
loginViewCancelHandler = () => {
|
loginViewCancelHandler = () => {
|
||||||
ConfigManager.addMojangAuthAccount(selectedAcc.uuid, selectedAcc.accessToken, selectedAcc.username, selectedAcc.displayName)
|
ConfigManager.addAuthAccount(selectedAcc.uuid, selectedAcc.accessToken, selectedAcc.username, selectedAcc.displayName)
|
||||||
ConfigManager.save()
|
ConfigManager.save()
|
||||||
validateSelectedAccount()
|
validateSelectedAccount()
|
||||||
}
|
}
|
||||||
|
@ -9,12 +9,11 @@ const $ = require('jquery')
|
|||||||
const {ipcRenderer, shell, webFrame} = require('electron')
|
const {ipcRenderer, shell, webFrame} = require('electron')
|
||||||
const remote = require('@electron/remote')
|
const remote = require('@electron/remote')
|
||||||
const isDev = require('./assets/js/isdev')
|
const isDev = require('./assets/js/isdev')
|
||||||
const { LoggerUtil } = require('helios-core')
|
const LoggerUtil = require('./assets/js/loggerutil')
|
||||||
const LoggerUtil1 = require('./assets/js/loggerutil')
|
|
||||||
|
|
||||||
const loggerUICore = LoggerUtil1('%c[UICore]', 'color: #000668; font-weight: bold')
|
const loggerUICore = LoggerUtil('%c[UICore]', 'color: #000668; font-weight: bold')
|
||||||
const loggerAutoUpdater = LoggerUtil1('%c[AutoUpdater]', 'color: #000668; font-weight: bold')
|
const loggerAutoUpdater = LoggerUtil('%c[AutoUpdater]', 'color: #000668; font-weight: bold')
|
||||||
const loggerAutoUpdaterSuccess = LoggerUtil1('%c[AutoUpdater]', 'color: #209b07; font-weight: bold')
|
const loggerAutoUpdaterSuccess = LoggerUtil('%c[AutoUpdater]', 'color: #209b07; font-weight: bold')
|
||||||
|
|
||||||
// Log deprecation and process warnings.
|
// Log deprecation and process warnings.
|
||||||
process.traceProcessWarnings = true
|
process.traceProcessWarnings = true
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
<div id="waitingContainer" style="display: none;">
|
|
||||||
<div id="waitingContent">
|
|
||||||
<div class="waitingSpinner"></div>
|
|
||||||
<div id="waitingTextContainer">
|
|
||||||
<h2>Waiting for Microsoft..</h2>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
109
index.js
109
index.js
@ -10,7 +10,6 @@ const isDev = require('./app/assets/js/isdev')
|
|||||||
const path = require('path')
|
const path = require('path')
|
||||||
const semver = require('semver')
|
const semver = require('semver')
|
||||||
const { pathToFileURL } = require('url')
|
const { pathToFileURL } = require('url')
|
||||||
const { AZURE_CLIENT_ID, MSFT_OPCODE, MSFT_REPLY_TYPE, MSFT_ERROR } = require('./app/assets/js/ipcconstants')
|
|
||||||
|
|
||||||
// Setup auto updater.
|
// Setup auto updater.
|
||||||
function initAutoUpdater(event, data) {
|
function initAutoUpdater(event, data) {
|
||||||
@ -89,114 +88,6 @@ ipcMain.on('distributionIndexDone', (event, res) => {
|
|||||||
// https://electronjs.org/docs/tutorial/offscreen-rendering
|
// https://electronjs.org/docs/tutorial/offscreen-rendering
|
||||||
app.disableHardwareAcceleration()
|
app.disableHardwareAcceleration()
|
||||||
|
|
||||||
|
|
||||||
const REDIRECT_URI_PREFIX = 'https://login.microsoftonline.com/common/oauth2/nativeclient?'
|
|
||||||
|
|
||||||
// Microsoft Auth Login
|
|
||||||
let msftAuthWindow
|
|
||||||
let msftAuthSuccess
|
|
||||||
ipcMain.on(MSFT_OPCODE.OPEN_LOGIN, (ipcEvent) => {
|
|
||||||
if (msftAuthWindow) {
|
|
||||||
ipcEvent.reply(MSFT_OPCODE.REPLY_LOGIN, MSFT_REPLY_TYPE.ERROR, MSFT_ERROR.ALREADY_OPEN)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
msftAuthSuccess = false
|
|
||||||
msftAuthWindow = new BrowserWindow({
|
|
||||||
title: 'Microsoft Login',
|
|
||||||
backgroundColor: '#222222',
|
|
||||||
width: 520,
|
|
||||||
height: 600,
|
|
||||||
frame: true,
|
|
||||||
icon: getPlatformIcon('SealCircle')
|
|
||||||
})
|
|
||||||
|
|
||||||
msftAuthWindow.on('closed', () => {
|
|
||||||
msftAuthWindow = undefined
|
|
||||||
})
|
|
||||||
|
|
||||||
msftAuthWindow.on('close', () => {
|
|
||||||
if(!msftAuthSuccess) {
|
|
||||||
ipcEvent.reply(MSFT_OPCODE.REPLY_LOGIN, MSFT_REPLY_TYPE.ERROR, MSFT_ERROR.NOT_FINISHED)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
msftAuthWindow.webContents.on('did-navigate', (_, uri) => {
|
|
||||||
if (uri.startsWith(REDIRECT_URI_PREFIX)) {
|
|
||||||
let queries = uri.substring(REDIRECT_URI_PREFIX.length).split('#', 1).toString().split('&')
|
|
||||||
let queryMap = {}
|
|
||||||
|
|
||||||
queries.forEach(query => {
|
|
||||||
const [name, value] = query.split('=')
|
|
||||||
queryMap[name] = decodeURI(value)
|
|
||||||
})
|
|
||||||
|
|
||||||
ipcEvent.reply(MSFT_OPCODE.REPLY_LOGIN, MSFT_REPLY_TYPE.SUCCESS, queryMap)
|
|
||||||
|
|
||||||
msftAuthSuccess = true
|
|
||||||
msftAuthWindow.close()
|
|
||||||
msftAuthWindow = null
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
msftAuthWindow.removeMenu()
|
|
||||||
msftAuthWindow.loadURL(`https://login.microsoftonline.com/consumers/oauth2/v2.0/authorize?prompt=select_account&client_id=${AZURE_CLIENT_ID}&response_type=code&scope=XboxLive.signin%20offline_access&redirect_uri=https://login.microsoftonline.com/common/oauth2/nativeclient`)
|
|
||||||
})
|
|
||||||
|
|
||||||
// Microsoft Auth Logout
|
|
||||||
let msftLogoutWindow
|
|
||||||
let msftLogoutSuccess
|
|
||||||
let msftLogoutSuccessSent
|
|
||||||
ipcMain.on(MSFT_OPCODE.OPEN_LOGOUT, (ipcEvent, uuid, isLastAccount) => {
|
|
||||||
if (msftLogoutWindow) {
|
|
||||||
ipcEvent.reply(MSFT_OPCODE.REPLY_LOGOUT, MSFT_REPLY_TYPE.ERROR, MSFT_ERROR.ALREADY_OPEN)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
msftLogoutSuccess = false
|
|
||||||
msftLogoutSuccessSent = false
|
|
||||||
msftLogoutWindow = new BrowserWindow({
|
|
||||||
title: 'Microsoft Logout',
|
|
||||||
backgroundColor: '#222222',
|
|
||||||
width: 520,
|
|
||||||
height: 600,
|
|
||||||
frame: true,
|
|
||||||
icon: getPlatformIcon('SealCircle')
|
|
||||||
})
|
|
||||||
|
|
||||||
msftLogoutWindow.on('closed', () => {
|
|
||||||
msftLogoutWindow = undefined
|
|
||||||
})
|
|
||||||
|
|
||||||
msftLogoutWindow.on('close', () => {
|
|
||||||
if(!msftLogoutSuccess) {
|
|
||||||
ipcEvent.reply(MSFT_OPCODE.REPLY_LOGOUT, MSFT_REPLY_TYPE.ERROR, MSFT_ERROR.NOT_FINISHED)
|
|
||||||
} else if(!msftLogoutSuccessSent) {
|
|
||||||
msftLogoutSuccessSent = true
|
|
||||||
ipcEvent.reply(MSFT_OPCODE.REPLY_LOGOUT, MSFT_REPLY_TYPE.SUCCESS, uuid, isLastAccount)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
msftLogoutWindow.webContents.on('did-navigate', (_, uri) => {
|
|
||||||
if(uri.startsWith('https://login.microsoftonline.com/common/oauth2/v2.0/logoutsession')) {
|
|
||||||
msftLogoutSuccess = true
|
|
||||||
setTimeout(() => {
|
|
||||||
if(!msftLogoutSuccessSent) {
|
|
||||||
msftLogoutSuccessSent = true
|
|
||||||
ipcEvent.reply(MSFT_OPCODE.REPLY_LOGOUT, MSFT_REPLY_TYPE.SUCCESS, uuid, isLastAccount)
|
|
||||||
}
|
|
||||||
|
|
||||||
if(msftLogoutWindow) {
|
|
||||||
msftLogoutWindow.close()
|
|
||||||
msftLogoutWindow = null
|
|
||||||
}
|
|
||||||
}, 5000)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
msftLogoutWindow.removeMenu()
|
|
||||||
msftLogoutWindow.loadURL('https://login.microsoftonline.com/common/oauth2/v2.0/logout')
|
|
||||||
})
|
|
||||||
|
|
||||||
// Keep a global reference of the window object, if you don't, the window will
|
// Keep a global reference of the window object, if you don't, the window will
|
||||||
// be closed automatically when the JavaScript object is garbage collected.
|
// be closed automatically when the JavaScript object is garbage collected.
|
||||||
let win
|
let win
|
||||||
|
Loading…
Reference in New Issue
Block a user