MSA
This commit is contained in:
parent
779a9a54ec
commit
d8a4d0903a
@ -858,6 +858,16 @@ body, button {
|
|||||||
border-width: 0 2px 2px 0;
|
border-width: 0 2px 2px 0;
|
||||||
transform: rotate(45deg);
|
transform: rotate(45deg);
|
||||||
}
|
}
|
||||||
|
#loginMSButton {
|
||||||
|
border-color: transparent;
|
||||||
|
background-color: transparent;
|
||||||
|
cursor: pointer;
|
||||||
|
font-family: 'NanumGothicBold';
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 3px;
|
||||||
|
color: rgba(255, 255, 255, 0.75);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
#login_filter {
|
#login_filter {
|
||||||
|
@ -12,9 +12,64 @@
|
|||||||
const ConfigManager = require('./configmanager')
|
const ConfigManager = require('./configmanager')
|
||||||
const LoggerUtil = require('./loggerutil')
|
const LoggerUtil = require('./loggerutil')
|
||||||
const Mojang = require('./mojang')
|
const Mojang = require('./mojang')
|
||||||
|
const Microsoft = require('./microsoft')
|
||||||
const logger = LoggerUtil('%c[AuthManager]', 'color: #a02d2a; font-weight: bold')
|
const logger = LoggerUtil('%c[AuthManager]', 'color: #a02d2a; font-weight: bold')
|
||||||
const loggerSuccess = LoggerUtil('%c[AuthManager]', 'color: #209b07; font-weight: bold')
|
const loggerSuccess = LoggerUtil('%c[AuthManager]', 'color: #209b07; font-weight: bold')
|
||||||
|
|
||||||
|
async function validateSelectedMojang() {
|
||||||
|
const current = ConfigManager.getSelectedAccount()
|
||||||
|
const isValid = await Mojang.validate(current.accessToken, ConfigManager.getClientToken())
|
||||||
|
if(!isValid){
|
||||||
|
try {
|
||||||
|
const session = await Mojang.refresh(current.accessToken, ConfigManager.getClientToken())
|
||||||
|
ConfigManager.updateAuthAccount(current.uuid, session.accessToken)
|
||||||
|
ConfigManager.save()
|
||||||
|
} catch(err) {
|
||||||
|
logger.debug('Error while validating selected profile:', err)
|
||||||
|
if(err && err.error === 'ForbiddenOperationException'){
|
||||||
|
// What do we do?
|
||||||
|
}
|
||||||
|
logger.log('Account access token is invalid.')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
loggerSuccess.log('Account access token validated.')
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
loggerSuccess.log('Account access token validated.')
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function validateSelectedMicrosoft() {
|
||||||
|
try {
|
||||||
|
const current = ConfigManager.getSelectedAccount()
|
||||||
|
const now = new Date().getTime()
|
||||||
|
const MCExpiresAt = Date.parse(current.expiresAt)
|
||||||
|
const MCExpired = now > MCExpiresAt
|
||||||
|
|
||||||
|
if(MCExpired) {
|
||||||
|
const MSExpiresAt = Date.parse(ConfigManager.getMicrosoftAuth().expires_at)
|
||||||
|
const MSExpired = now > MSExpiresAt
|
||||||
|
|
||||||
|
if (MSExpired) {
|
||||||
|
const newAccessToken = await Microsoft.refreshAccessToken(ConfigManager.getMicrosoftAuth)
|
||||||
|
ConfigManager.updateMicrosoftAuth(newAccessToken.access_token, newAccessToken.expires_at)
|
||||||
|
ConfigManager.save()
|
||||||
|
}
|
||||||
|
const newMCAccessToken = await Microsoft.authMinecraft(ConfigManager.getMicrosoftAuth().access_token)
|
||||||
|
ConfigManager.updateAuthAccount(current.uuid, newMCAccessToken.access_token, newMCAccessToken.expires_at)
|
||||||
|
ConfigManager.save()
|
||||||
|
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
return Promise.reject(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exports
|
||||||
// Functions
|
// Functions
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -78,22 +133,31 @@ exports.validateSelected = async function(){
|
|||||||
const current = ConfigManager.getSelectedAccount()
|
const current = ConfigManager.getSelectedAccount()
|
||||||
const isValid = await Mojang.validate(current.accessToken, ConfigManager.getClientToken())
|
const isValid = await Mojang.validate(current.accessToken, ConfigManager.getClientToken())
|
||||||
if(!isValid){
|
if(!isValid){
|
||||||
try {
|
try{
|
||||||
const session = await Mojang.refresh(current.accessToken, ConfigManager.getClientToken())
|
if (ConfigManager.getSelectedAccount() === 'microsoft') {
|
||||||
ConfigManager.updateAuthAccount(current.uuid, session.accessToken)
|
const validate = await validateSelectedMicrosoft()
|
||||||
ConfigManager.save()
|
return validate
|
||||||
} catch(err) {
|
} else {
|
||||||
logger.debug('Error while validating selected profile:', err)
|
const validate = await validateSelectedMojang()
|
||||||
if(err && err.error === 'ForbiddenOperationException'){
|
return validate
|
||||||
// What do we do?
|
|
||||||
}
|
}
|
||||||
logger.log('Account access token is invalid.')
|
} catch (error) {
|
||||||
return false
|
return Promise.reject(error)
|
||||||
}
|
}
|
||||||
loggerSuccess.log('Account access token validated.')
|
}
|
||||||
return true
|
}
|
||||||
} else {
|
|
||||||
loggerSuccess.log('Account access token validated.')
|
exports.addMSAccount = async authCode => {
|
||||||
return true
|
try {
|
||||||
|
const accessToken = await Microsoft.getAccessToken(authCode)
|
||||||
|
ConfigManager.setMicrosoftAuth(accessToken)
|
||||||
|
const MCAccessToken = await Microsoft.authMinecraft(accessToken.access_token)
|
||||||
|
const MCProfile = await Microsoft.getMCProfile(MCAccessToken.access_token)
|
||||||
|
const ret = ConfigManager.addAuthAccount(MCProfile.id, MCAccessToken.access_token, MCProfile.name, MCProfile.name, MCAccessToken.expires_at, 'microsoft')
|
||||||
|
ConfigManager.save()
|
||||||
|
|
||||||
|
return ret
|
||||||
|
} catch(error) {
|
||||||
|
return Promise.reject(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -103,7 +103,8 @@ const DEFAULT_CONFIG = {
|
|||||||
selectedServer: null, // Resolved
|
selectedServer: null, // Resolved
|
||||||
selectedAccount: null,
|
selectedAccount: null,
|
||||||
authenticationDatabase: {},
|
authenticationDatabase: {},
|
||||||
modConfigurations: []
|
modConfigurations: [],
|
||||||
|
microsoftAuth: {}
|
||||||
}
|
}
|
||||||
|
|
||||||
let config = null
|
let config = null
|
||||||
@ -327,6 +328,7 @@ exports.getAuthAccount = function(uuid){
|
|||||||
*/
|
*/
|
||||||
exports.updateAuthAccount = function(uuid, accessToken){
|
exports.updateAuthAccount = function(uuid, accessToken){
|
||||||
config.authenticationDatabase[uuid].accessToken = accessToken
|
config.authenticationDatabase[uuid].accessToken = accessToken
|
||||||
|
config.authenticationDatabase[uuid].expiresAt = expiresAt
|
||||||
return config.authenticationDatabase[uuid]
|
return config.authenticationDatabase[uuid]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -340,17 +342,18 @@ exports.updateAuthAccount = function(uuid, accessToken){
|
|||||||
*
|
*
|
||||||
* @returns {Object} The authenticated account object created by this action.
|
* @returns {Object} The authenticated account object created by this action.
|
||||||
*/
|
*/
|
||||||
exports.addAuthAccount = function(uuid, accessToken, username, displayName){
|
exports.addAuthAccount = function(uuid, accessToken, username, displayName, expiresAt = null, type = 'mojang'){
|
||||||
config.selectedAccount = uuid
|
config.selectedAccount = uuid
|
||||||
config.authenticationDatabase[uuid] = {
|
config.authenticationDatabase[uuid] = {
|
||||||
accessToken,
|
accessToken,
|
||||||
username: username.trim(),
|
username: username.trim(),
|
||||||
uuid: uuid.trim(),
|
uuid: uuid.trim(),
|
||||||
displayName: displayName.trim()
|
displayName: displayName.trim(),
|
||||||
|
expiresAt: expiresAt,
|
||||||
|
type: type
|
||||||
}
|
}
|
||||||
return config.authenticationDatabase[uuid]
|
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
|
||||||
@ -685,4 +688,19 @@ exports.getAllowPrerelease = function(def = false){
|
|||||||
*/
|
*/
|
||||||
exports.setAllowPrerelease = function(allowPrerelease){
|
exports.setAllowPrerelease = function(allowPrerelease){
|
||||||
config.settings.launcher.allowPrerelease = allowPrerelease
|
config.settings.launcher.allowPrerelease = allowPrerelease
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exports.setMicrosoftAuth = microsoftAuth => {
|
||||||
|
config.microsoftAuth = microsoftAuth
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.getMicrosoftAuth = () => {
|
||||||
|
return config.microsoftAuth
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.updateMicrosoftAuth = (accessToken, expiresAt) => {
|
||||||
|
config.microsoftAuth.access_token = accessToken
|
||||||
|
config.microsoftAuth.expires_at = expiresAt
|
||||||
|
|
||||||
|
return config.microsoftAuth
|
||||||
|
}
|
191
app/assets/js/microsoft.js
Normal file
191
app/assets/js/microsoft.js
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
// Requirements
|
||||||
|
const request = require('request')
|
||||||
|
// const logger = require('./loggerutil')('%c[Microsoft]', 'color: #01a6f0; font-weight: bold')
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
const clientId = 'Client ID(Azure)'
|
||||||
|
const tokenUri = 'https://login.microsoftonline.com/consumers/oauth2/v2.0/token'
|
||||||
|
const authXBLUri = 'https://user.auth.xboxlive.com/user/authenticate'
|
||||||
|
const authXSTSUri = 'https://xsts.auth.xboxlive.com/xsts/authorize'
|
||||||
|
const authMCUri = 'https://api.minecraftservices.com/authentication/login_with_xbox'
|
||||||
|
const profileURI ='https://api.minecraftservices.com/minecraft/profile'
|
||||||
|
|
||||||
|
// Functions
|
||||||
|
function requestPromise(uri, options) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
request(uri, options, (error, response, body) => {
|
||||||
|
if (error) {
|
||||||
|
reject(error)
|
||||||
|
} else if (response.statusCode !== 200){
|
||||||
|
reject([response.statusCode, response.statusMessage, response])
|
||||||
|
} else {
|
||||||
|
resolve(response)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function getXBLToken(accessToken) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const data = new Object()
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
method: 'post',
|
||||||
|
json: {
|
||||||
|
Properties: {
|
||||||
|
AuthMethod: 'RPS',
|
||||||
|
SiteName: 'user.auth.xboxlive.com',
|
||||||
|
RpsTicket: `d=${accessToken}`
|
||||||
|
},
|
||||||
|
RelyingParty: 'http://auth.xboxlive.com',
|
||||||
|
TokenType: 'JWT'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
requestPromise(authXBLUri, options).then(response => {
|
||||||
|
const body = response.body
|
||||||
|
|
||||||
|
data.token = body.Token
|
||||||
|
data.uhs = body.DisplayClaims.xui[0].uhs
|
||||||
|
|
||||||
|
resolve(data)
|
||||||
|
}).catch(error => {
|
||||||
|
reject(error)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function getXSTSToken(XBLToken) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const options = {
|
||||||
|
method: 'post',
|
||||||
|
json: {
|
||||||
|
Properties: {
|
||||||
|
SandboxId: 'RETAIL',
|
||||||
|
UserTokens: [XBLToken]
|
||||||
|
},
|
||||||
|
RelyingParty: 'rp://api.minecraftservices.com/',
|
||||||
|
TokenType: 'JWT'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
requestPromise(authXSTSUri, options).then(response => {
|
||||||
|
const body = response.body
|
||||||
|
|
||||||
|
resolve(body.Token)
|
||||||
|
}).catch(error => {
|
||||||
|
reject(error)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMCAccessToken(UHS, XSTSToken) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const data = new Object()
|
||||||
|
const expiresAt = new Date()
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
method: 'post',
|
||||||
|
json: {
|
||||||
|
identityToken: `XBL3.0 x=${UHS};${XSTSToken}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
requestPromise(authMCUri, options).then(response => {
|
||||||
|
const body = response.body
|
||||||
|
|
||||||
|
expiresAt.setSeconds(expiresAt.getSeconds() + body.expires_in)
|
||||||
|
data.access_token = body.access_token
|
||||||
|
data.expires_at = expiresAt
|
||||||
|
|
||||||
|
resolve(data)
|
||||||
|
}).catch(error => {
|
||||||
|
reject(error)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exports
|
||||||
|
exports.getAccessToken = authCode => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const expiresAt = new Date()
|
||||||
|
const data = new Object()
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
method: 'post',
|
||||||
|
formData: {
|
||||||
|
client_id: clientId,
|
||||||
|
code: authCode,
|
||||||
|
scope: 'XboxLive.signin',
|
||||||
|
redirect_uri: 'https://login.microsoftonline.com/common/oauth2/nativeclient',
|
||||||
|
grant_type: 'authorization_code'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
requestPromise(tokenUri, options).then(response => {
|
||||||
|
const body = JSON.parse(response.body)
|
||||||
|
expiresAt.setSeconds(expiresAt.getSeconds() + body.expires_in)
|
||||||
|
data.expires_at = expiresAt
|
||||||
|
data.access_token = body.access_token
|
||||||
|
data.refresh_token = body.refresh_token
|
||||||
|
|
||||||
|
resolve(data)
|
||||||
|
}).catch(error => {
|
||||||
|
reject(error)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.refreshAccessToken = refreshToken => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const expiresAt = new Date()
|
||||||
|
const data = new Object()
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
method: 'post',
|
||||||
|
formData: {
|
||||||
|
client_id: clientId,
|
||||||
|
refresh_token: refreshToken,
|
||||||
|
scope: 'XboxLive.signin',
|
||||||
|
redirect_uri: 'https://login.microsoftonline.com/common/oauth2/nativeclient',
|
||||||
|
grant_type: 'refresh_token'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
requestPromise(tokenUri, options).then(response => {
|
||||||
|
const body = JSON.parse(response.body)
|
||||||
|
expiresAt.setSeconds(expiresAt.getSeconds() + body.expires_in)
|
||||||
|
data.expires_at = expiresAt
|
||||||
|
data.access_token = body.access_token
|
||||||
|
|
||||||
|
resolve(data)
|
||||||
|
}).catch(error => {
|
||||||
|
reject(error)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.authMinecraft = async accessToken => {
|
||||||
|
try {
|
||||||
|
const XBLToken = await getXBLToken(accessToken)
|
||||||
|
const XSTSToken = await getXSTSToken(XBLToken.token)
|
||||||
|
const MCToken = await getMCAccessToken(XBLToken.uhs, XSTSToken)
|
||||||
|
|
||||||
|
return MCToken
|
||||||
|
} catch (error) {
|
||||||
|
Promise.reject(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.getMCProfile = MCAccessToken => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const options = {
|
||||||
|
method: 'get',
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${MCAccessToken}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
requestPromise(profileURI, options).then(response => {
|
||||||
|
const body = JSON.parse(response.body)
|
||||||
|
|
||||||
|
resolve(body)
|
||||||
|
}).catch(error => {
|
||||||
|
reject(error)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
@ -17,6 +17,7 @@ const checkmarkContainer = document.getElementById('checkmarkContainer')
|
|||||||
const loginRememberOption = document.getElementById('loginRememberOption')
|
const loginRememberOption = document.getElementById('loginRememberOption')
|
||||||
const loginButton = document.getElementById('loginButton')
|
const loginButton = document.getElementById('loginButton')
|
||||||
const loginForm = document.getElementById('loginForm')
|
const loginForm = document.getElementById('loginForm')
|
||||||
|
const loginMSButton = document.getElementById('loginMSButton')
|
||||||
|
|
||||||
// Control variables.
|
// Control variables.
|
||||||
let lu = false, lp = false
|
let lu = false, lp = false
|
||||||
@ -297,4 +298,72 @@ loginButton.addEventListener('click', () => {
|
|||||||
loggerLogin.log('Error while logging in.', err)
|
loggerLogin.log('Error while logging in.', err)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
loginMSButton.addEventListener('click', (event) => {
|
||||||
|
ipcRenderer.send('openMSALoginWindow', 'open')
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcRenderer.on('MSALoginWindowReply', (event, ...args) => {
|
||||||
|
if (args[0] === 'error') {
|
||||||
|
setOverlayContent('LOGIN FAIL', 'Theres a window already open!', 'OK')
|
||||||
|
setOverlayHandler(() => {
|
||||||
|
toggleOverlay(false)
|
||||||
|
})
|
||||||
|
toggleOverlay(true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const queryMap = args[0]
|
||||||
|
if(queryMap.has('error')) {
|
||||||
|
let error = queryMap.get('error')
|
||||||
|
let errorDesc = queryMap.get('error_description')
|
||||||
|
setOverlayContent(error, errorDesc, 'OK')
|
||||||
|
setOverlayHandler(() => {
|
||||||
|
toggleOverlay(false)
|
||||||
|
})
|
||||||
|
toggleOverlay(true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable form.
|
||||||
|
formDisabled(true)
|
||||||
|
|
||||||
|
// Show loading stuff.
|
||||||
|
loginLoading(true)
|
||||||
|
|
||||||
|
const authCode = queryMap.get('code')
|
||||||
|
AuthManager.addMSAccount(authCode).then(account => {
|
||||||
|
updateSelectedAccount(account)
|
||||||
|
loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.loggingIn'), Lang.queryJS('login.success'))
|
||||||
|
$('.circle-loader').toggleClass('load-complete')
|
||||||
|
$('.checkmark').toggle()
|
||||||
|
setTimeout(() => {
|
||||||
|
switchView(VIEWS.login, loginViewOnSuccess, 500, 500, () => {
|
||||||
|
// Temporary workaround
|
||||||
|
if(loginViewOnSuccess === VIEWS.settings){
|
||||||
|
prepareSettings()
|
||||||
|
}
|
||||||
|
loginViewOnSuccess = VIEWS.landing // Reset this for good measure.
|
||||||
|
loginCancelEnabled(false) // Reset this for good measure.
|
||||||
|
loginViewCancelHandler = null // Reset this for good measure.
|
||||||
|
loginUsername.value = ''
|
||||||
|
loginPassword.value = ''
|
||||||
|
$('.circle-loader').toggleClass('load-complete')
|
||||||
|
$('.checkmark').toggle()
|
||||||
|
loginLoading(false)
|
||||||
|
loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.success'), Lang.queryJS('login.login'))
|
||||||
|
formDisabled(false)
|
||||||
|
})
|
||||||
|
}, 1000)
|
||||||
|
}).catch(error => {
|
||||||
|
loginLoading(false)
|
||||||
|
setOverlayContent('ERROR!', 'Report Plz!', Lang.queryJS('login.tryAgain'))
|
||||||
|
setOverlayHandler(() => {
|
||||||
|
formDisabled(false)
|
||||||
|
toggleOverlay(false)
|
||||||
|
})
|
||||||
|
toggleOverlay(true)
|
||||||
|
loggerLogin.error(error)
|
||||||
|
})
|
||||||
})
|
})
|
@ -9,6 +9,7 @@
|
|||||||
<form id="loginForm">
|
<form id="loginForm">
|
||||||
<img id="loginImageSeal" src="assets/images/SealCircle.png"/>
|
<img id="loginImageSeal" src="assets/images/SealCircle.png"/>
|
||||||
<span id="loginSubheader">MINECRAFT LOGIN</span>
|
<span id="loginSubheader">MINECRAFT LOGIN</span>
|
||||||
|
<button id="loginMSButton">OR Microsoft Login</button>
|
||||||
<div class="loginFieldContainer">
|
<div class="loginFieldContainer">
|
||||||
<svg id="profileSVG" class="loginSVG" viewBox="40 37 65.36 61.43">
|
<svg id="profileSVG" class="loginSVG" viewBox="40 37 65.36 61.43">
|
||||||
<g>
|
<g>
|
||||||
|
47
index.js
47
index.js
@ -8,6 +8,8 @@ const path = require('path')
|
|||||||
const semver = require('semver')
|
const semver = require('semver')
|
||||||
const url = require('url')
|
const url = require('url')
|
||||||
|
|
||||||
|
const redirectUriPrefix = 'https://login.microsoftonline.com/common/oauth2/nativeclient?'
|
||||||
|
|
||||||
// Setup auto updater.
|
// Setup auto updater.
|
||||||
function initAutoUpdater(event, data) {
|
function initAutoUpdater(event, data) {
|
||||||
|
|
||||||
@ -85,6 +87,49 @@ ipcMain.on('distributionIndexDone', (event, res) => {
|
|||||||
// https://electronjs.org/docs/tutorial/offscreen-rendering
|
// https://electronjs.org/docs/tutorial/offscreen-rendering
|
||||||
app.disableHardwareAcceleration()
|
app.disableHardwareAcceleration()
|
||||||
|
|
||||||
|
let MSALoginWindow = null
|
||||||
|
|
||||||
|
// Open the Microsoft Account Login window
|
||||||
|
ipcMain.on('openMSALoginWindow', (ipcEvent, args) => {
|
||||||
|
if(MSALoginWindow != null){
|
||||||
|
ipcEvent.sender.send('MSALoginWindowNotification', 'error', 'AlreadyOpenException')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
MSALoginWindow = new BrowserWindow({
|
||||||
|
minWidth: 600,
|
||||||
|
minHeight: 400,
|
||||||
|
width: 600,
|
||||||
|
height: 400,
|
||||||
|
contextIsolation: false
|
||||||
|
})
|
||||||
|
|
||||||
|
MSALoginWindow.on('closed', () => {
|
||||||
|
MSALoginWindow = null
|
||||||
|
})
|
||||||
|
|
||||||
|
MSALoginWindow.webContents.on('did-navigate', (event, uri, responseCode, statusText) => {
|
||||||
|
if(uri.startsWith(redirectUriPrefix)) {
|
||||||
|
let querys = uri.substring(redirectUriPrefix.length).split('#', 1).toString().split('&')
|
||||||
|
let queryMap = new Map()
|
||||||
|
|
||||||
|
querys.forEach(query => {
|
||||||
|
let arr = query.split('=')
|
||||||
|
queryMap.set(arr[0], decodeURI(arr[1]))
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcEvent.reply('MSALoginWindowReply', queryMap)
|
||||||
|
|
||||||
|
MSALoginWindow.close()
|
||||||
|
MSALoginWindow = null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
MSALoginWindow.removeMenu()
|
||||||
|
MSALoginWindow.loadURL('https://login.microsoftonline.com/consumers/oauth2/v2.0/authorize?client_id=a621aefe-b326-4c67-8688-34746ccd9bd2&response_type=code&scope=XboxLive.signin%20offline_access&redirect_uri=https://login.microsoftonline.com/common/oauth2/nativeclient')
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// https://github.com/electron/electron/issues/18397
|
// https://github.com/electron/electron/issues/18397
|
||||||
app.allowRendererProcessReuse = true
|
app.allowRendererProcessReuse = true
|
||||||
|
|
||||||
@ -147,6 +192,8 @@ function createMenu() {
|
|||||||
accelerator: 'Command+Q',
|
accelerator: 'Command+Q',
|
||||||
click: () => {
|
click: () => {
|
||||||
app.quit()
|
app.quit()
|
||||||
|
if(MSALoginWindow !== null) MSALoginWindow.close()
|
||||||
|
MSALoginWindow = null
|
||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user