mirror of
https://github.com/dscalzi/HeliosLauncher.git
synced 2024-12-22 11:42:14 -08:00
Compare commits
5 Commits
f119985211
...
d560ef09d1
Author | SHA1 | Date | |
---|---|---|---|
|
d560ef09d1 | ||
|
3a36ce7094 | ||
|
ad47617cd0 | ||
|
2fdb217e64 | ||
|
c1d36d2b03 |
20
.github/workflows/build.yml
vendored
20
.github/workflows/build.yml
vendored
@ -14,16 +14,22 @@ jobs:
|
|||||||
- name: Check out Git repository
|
- name: Check out Git repository
|
||||||
uses: actions/checkout@v1
|
uses: actions/checkout@v1
|
||||||
|
|
||||||
- name: Install Node.js, NPM and Yarn
|
- name: Set up Node
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: 16
|
node-version: 16
|
||||||
|
|
||||||
- name: Build/release Electron app
|
- name: Set up Python
|
||||||
uses: samuelmeuli/action-electron-builder@v1
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
github_token: ${{ secrets.github_token }}
|
python-version: 3.x
|
||||||
|
|
||||||
# If the commit is tagged with a version (e.g. "v1.0.0"),
|
- name: Install Dependencies
|
||||||
# release the app after building
|
run: npm ci
|
||||||
release: ${{ startsWith(github.ref, 'refs/tags/v') }}
|
shell: bash
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.github_token }}
|
||||||
|
run: npm run dist
|
||||||
|
shell: bash
|
@ -16,13 +16,6 @@ const ConfigManager = require('./configmanager')
|
|||||||
const DistroManager = require('./distromanager')
|
const DistroManager = require('./distromanager')
|
||||||
const isDev = require('./isdev')
|
const isDev = require('./isdev')
|
||||||
|
|
||||||
// Constants
|
|
||||||
// const PLATFORM_MAP = {
|
|
||||||
// win32: '-windows-x64.tar.gz',
|
|
||||||
// darwin: '-macosx-x64.tar.gz',
|
|
||||||
// linux: '-linux-x64.tar.gz'
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Classes
|
// Classes
|
||||||
|
|
||||||
/** Class representing a base asset. */
|
/** Class representing a base asset. */
|
||||||
@ -475,15 +468,15 @@ class JavaGuard extends EventEmitter {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else if(verOb.major >= 16) {
|
||||||
|
// TODO Make this logic better. Make java 16 required.
|
||||||
// Java 9+
|
// Java 9+
|
||||||
if(Util.mcVersionAtLeast('1.13', this.mcVersion)){
|
if(Util.mcVersionAtLeast('1.17', this.mcVersion)){
|
||||||
console.log('Java 9+ not yet tested.')
|
meta.version = verOb
|
||||||
/* meta.version = verOb
|
|
||||||
++checksum
|
++checksum
|
||||||
if(checksum === goal){
|
if(checksum === goal){
|
||||||
break
|
break
|
||||||
} */
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Space included so we get only the vendor.
|
// Space included so we get only the vendor.
|
||||||
|
@ -10,10 +10,11 @@
|
|||||||
*/
|
*/
|
||||||
// Requirements
|
// Requirements
|
||||||
const ConfigManager = require('./configmanager')
|
const ConfigManager = require('./configmanager')
|
||||||
const LoggerUtil = require('./loggerutil')
|
const { LoggerUtil } = require('helios-core')
|
||||||
const Mojang = require('./mojang')
|
const { MojangRestAPI, mojangErrorDisplayable, MojangErrorCode } = require('helios-core/mojang')
|
||||||
const logger = LoggerUtil('%c[AuthManager]', 'color: #a02d2a; font-weight: bold')
|
const { RestResponseStatus } = require('helios-core/common')
|
||||||
const loggerSuccess = LoggerUtil('%c[AuthManager]', 'color: #209b07; font-weight: bold')
|
|
||||||
|
const log = LoggerUtil.getLogger('AuthManager')
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
|
|
||||||
@ -28,20 +29,29 @@ const loggerSuccess = LoggerUtil('%c[AuthManager]', 'color: #209b07; font-weight
|
|||||||
*/
|
*/
|
||||||
exports.addAccount = async function(username, password){
|
exports.addAccount = async function(username, password){
|
||||||
try {
|
try {
|
||||||
const session = await Mojang.authenticate(username, password, ConfigManager.getClientToken())
|
const response = await MojangRestAPI.authenticate(username, password, ConfigManager.getClientToken())
|
||||||
if(session.selectedProfile != null){
|
console.log(response)
|
||||||
const ret = ConfigManager.addAuthAccount(session.selectedProfile.id, session.accessToken, username, session.selectedProfile.name)
|
if(response.responseStatus === RestResponseStatus.SUCCESS) {
|
||||||
if(ConfigManager.getClientToken() == null){
|
|
||||||
ConfigManager.setClientToken(session.clientToken)
|
const session = response.data
|
||||||
|
if(session.selectedProfile != null){
|
||||||
|
const ret = ConfigManager.addAuthAccount(session.selectedProfile.id, session.accessToken, username, session.selectedProfile.name)
|
||||||
|
if(ConfigManager.getClientToken() == null){
|
||||||
|
ConfigManager.setClientToken(session.clientToken)
|
||||||
|
}
|
||||||
|
ConfigManager.save()
|
||||||
|
return ret
|
||||||
|
} else {
|
||||||
|
return Promise.reject(mojangErrorDisplayable(MojangErrorCode.ERROR_NOT_PAID))
|
||||||
}
|
}
|
||||||
ConfigManager.save()
|
|
||||||
return ret
|
|
||||||
} else {
|
} else {
|
||||||
throw new Error('NotPaidAccount')
|
return Promise.reject(mojangErrorDisplayable(response.mojangErrorCode))
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (err){
|
} catch (err){
|
||||||
return Promise.reject(err)
|
log.error(err)
|
||||||
|
return Promise.reject(mojangErrorDisplayable(MojangErrorCode.UNKNOWN))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,11 +65,17 @@ exports.addAccount = async function(username, password){
|
|||||||
exports.removeAccount = async function(uuid){
|
exports.removeAccount = async function(uuid){
|
||||||
try {
|
try {
|
||||||
const authAcc = ConfigManager.getAuthAccount(uuid)
|
const authAcc = ConfigManager.getAuthAccount(uuid)
|
||||||
await Mojang.invalidate(authAcc.accessToken, ConfigManager.getClientToken())
|
const response = await MojangRestAPI.invalidate(authAcc.accessToken, ConfigManager.getClientToken())
|
||||||
ConfigManager.removeAuthAccount(uuid)
|
if(response.responseStatus === RestResponseStatus.SUCCESS) {
|
||||||
ConfigManager.save()
|
ConfigManager.removeAuthAccount(uuid)
|
||||||
return Promise.resolve()
|
ConfigManager.save()
|
||||||
|
return Promise.resolve()
|
||||||
|
} else {
|
||||||
|
log.error('Error while removing account', response.error)
|
||||||
|
return Promise.reject(response.error)
|
||||||
|
}
|
||||||
} catch (err){
|
} catch (err){
|
||||||
|
log.error('Error while removing account', err)
|
||||||
return Promise.reject(err)
|
return Promise.reject(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -76,24 +92,27 @@ exports.removeAccount = async function(uuid){
|
|||||||
*/
|
*/
|
||||||
exports.validateSelected = async function(){
|
exports.validateSelected = async function(){
|
||||||
const current = ConfigManager.getSelectedAccount()
|
const current = ConfigManager.getSelectedAccount()
|
||||||
const isValid = await Mojang.validate(current.accessToken, ConfigManager.getClientToken())
|
const response = await MojangRestAPI.validate(current.accessToken, ConfigManager.getClientToken())
|
||||||
if(!isValid){
|
|
||||||
try {
|
if(response.responseStatus === RestResponseStatus.SUCCESS) {
|
||||||
const session = await Mojang.refresh(current.accessToken, ConfigManager.getClientToken())
|
const isValid = response.data
|
||||||
ConfigManager.updateAuthAccount(current.uuid, session.accessToken)
|
if(!isValid){
|
||||||
ConfigManager.save()
|
const refreshResponse = await MojangRestAPI.refresh(current.accessToken, ConfigManager.getClientToken())
|
||||||
} catch(err) {
|
if(refreshResponse.responseStatus === RestResponseStatus.SUCCESS) {
|
||||||
logger.debug('Error while validating selected profile:', err)
|
const session = refreshResponse.data
|
||||||
if(err && err.error === 'ForbiddenOperationException'){
|
ConfigManager.updateAuthAccount(current.uuid, session.accessToken)
|
||||||
// What do we do?
|
ConfigManager.save()
|
||||||
|
} else {
|
||||||
|
log.error('Error while validating selected profile:', refreshResponse.error)
|
||||||
|
log.info('Account access token is invalid.')
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
logger.log('Account access token is invalid.')
|
log.info('Account access token validated.')
|
||||||
return false
|
return true
|
||||||
|
} else {
|
||||||
|
log.info('Account access token validated.')
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
loggerSuccess.log('Account access token validated.')
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
loggerSuccess.log('Account access token validated.')
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
// Work in progress
|
// Work in progress
|
||||||
const logger = require('./loggerutil')('%c[DiscordWrapper]', 'color: #7289da; font-weight: bold')
|
const logger = require('./loggerutil')('%c[DiscordWrapper]', 'color: #7289da; font-weight: bold')
|
||||||
|
|
||||||
const {Client} = require('discord-rpc')
|
const {Client} = require('discord-rpc-patch')
|
||||||
|
|
||||||
let client
|
let client
|
||||||
let activity
|
let activity
|
||||||
|
@ -1,271 +0,0 @@
|
|||||||
/**
|
|
||||||
* Mojang
|
|
||||||
*
|
|
||||||
* This module serves as a minimal wrapper for Mojang's REST api.
|
|
||||||
*
|
|
||||||
* @module mojang
|
|
||||||
*/
|
|
||||||
// Requirements
|
|
||||||
const request = require('request')
|
|
||||||
const logger = require('./loggerutil')('%c[Mojang]', 'color: #a02d2a; font-weight: bold')
|
|
||||||
|
|
||||||
// Constants
|
|
||||||
const minecraftAgent = {
|
|
||||||
name: 'Minecraft',
|
|
||||||
version: 1
|
|
||||||
}
|
|
||||||
const authpath = 'https://authserver.mojang.com'
|
|
||||||
const statuses = [
|
|
||||||
{
|
|
||||||
service: 'session.minecraft.net',
|
|
||||||
status: 'grey',
|
|
||||||
name: 'Multiplayer Session Service',
|
|
||||||
essential: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
service: 'authserver.mojang.com',
|
|
||||||
status: 'grey',
|
|
||||||
name: 'Authentication Service',
|
|
||||||
essential: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
service: 'textures.minecraft.net',
|
|
||||||
status: 'grey',
|
|
||||||
name: 'Minecraft Skins',
|
|
||||||
essential: false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
service: 'api.mojang.com',
|
|
||||||
status: 'grey',
|
|
||||||
name: 'Public API',
|
|
||||||
essential: false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
service: 'minecraft.net',
|
|
||||||
status: 'grey',
|
|
||||||
name: 'Minecraft.net',
|
|
||||||
essential: false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
service: 'account.mojang.com',
|
|
||||||
status: 'grey',
|
|
||||||
name: 'Mojang Accounts Website',
|
|
||||||
essential: false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
// Functions
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a Mojang status color to a hex value. Valid statuses
|
|
||||||
* are 'green', 'yellow', 'red', and 'grey'. Grey is a custom status
|
|
||||||
* to our project which represents an unknown status.
|
|
||||||
*
|
|
||||||
* @param {string} status A valid status code.
|
|
||||||
* @returns {string} The hex color of the status code.
|
|
||||||
*/
|
|
||||||
exports.statusToHex = function(status){
|
|
||||||
switch(status.toLowerCase()){
|
|
||||||
case 'green':
|
|
||||||
return '#a5c325'
|
|
||||||
case 'yellow':
|
|
||||||
return '#eac918'
|
|
||||||
case 'red':
|
|
||||||
return '#c32625'
|
|
||||||
case 'grey':
|
|
||||||
default:
|
|
||||||
return '#848484'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the status of Mojang's services.
|
|
||||||
* The response is condensed into a single object. Each service is
|
|
||||||
* a key, where the value is an object containing a status and name
|
|
||||||
* property.
|
|
||||||
*
|
|
||||||
* @see http://wiki.vg/Mojang_API#API_Status
|
|
||||||
*/
|
|
||||||
exports.status = function(){
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
request.get('https://status.mojang.com/check',
|
|
||||||
{
|
|
||||||
json: true,
|
|
||||||
timeout: 2500
|
|
||||||
},
|
|
||||||
function(error, response, body){
|
|
||||||
|
|
||||||
if(error || response.statusCode !== 200){
|
|
||||||
logger.warn('Unable to retrieve Mojang status.')
|
|
||||||
logger.debug('Error while retrieving Mojang statuses:', error)
|
|
||||||
//reject(error || response.statusCode)
|
|
||||||
for(let i=0; i<statuses.length; i++){
|
|
||||||
statuses[i].status = 'grey'
|
|
||||||
}
|
|
||||||
resolve(statuses)
|
|
||||||
} else {
|
|
||||||
for(let i=0; i<body.length; i++){
|
|
||||||
const key = Object.keys(body[i])[0]
|
|
||||||
inner:
|
|
||||||
for(let j=0; j<statuses.length; j++){
|
|
||||||
if(statuses[j].service === key) {
|
|
||||||
statuses[j].status = body[i][key]
|
|
||||||
break inner
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
resolve(statuses)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Authenticate a user with their Mojang credentials.
|
|
||||||
*
|
|
||||||
* @param {string} username The user's username, this is often an email.
|
|
||||||
* @param {string} password The user's password.
|
|
||||||
* @param {string} clientToken The launcher's Client Token.
|
|
||||||
* @param {boolean} requestUser Optional. Adds user object to the reponse.
|
|
||||||
* @param {Object} agent Optional. Provided by default. Adds user info to the response.
|
|
||||||
*
|
|
||||||
* @see http://wiki.vg/Authentication#Authenticate
|
|
||||||
*/
|
|
||||||
exports.authenticate = function(username, password, clientToken, requestUser = true, agent = minecraftAgent){
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
|
|
||||||
const body = {
|
|
||||||
agent,
|
|
||||||
username,
|
|
||||||
password,
|
|
||||||
requestUser
|
|
||||||
}
|
|
||||||
if(clientToken != null){
|
|
||||||
body.clientToken = clientToken
|
|
||||||
}
|
|
||||||
|
|
||||||
request.post(authpath + '/authenticate',
|
|
||||||
{
|
|
||||||
json: true,
|
|
||||||
body
|
|
||||||
},
|
|
||||||
function(error, response, body){
|
|
||||||
if(error){
|
|
||||||
logger.error('Error during authentication.', error)
|
|
||||||
reject(error)
|
|
||||||
} else {
|
|
||||||
if(response.statusCode === 200){
|
|
||||||
resolve(body)
|
|
||||||
} else {
|
|
||||||
reject(body || {code: 'ENOTFOUND'})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate an access token. This should always be done before launching.
|
|
||||||
* The client token should match the one used to create the access token.
|
|
||||||
*
|
|
||||||
* @param {string} accessToken The access token to validate.
|
|
||||||
* @param {string} clientToken The launcher's client token.
|
|
||||||
*
|
|
||||||
* @see http://wiki.vg/Authentication#Validate
|
|
||||||
*/
|
|
||||||
exports.validate = function(accessToken, clientToken){
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
request.post(authpath + '/validate',
|
|
||||||
{
|
|
||||||
json: true,
|
|
||||||
body: {
|
|
||||||
accessToken,
|
|
||||||
clientToken
|
|
||||||
}
|
|
||||||
},
|
|
||||||
function(error, response, body){
|
|
||||||
if(error){
|
|
||||||
logger.error('Error during validation.', error)
|
|
||||||
reject(error)
|
|
||||||
} else {
|
|
||||||
if(response.statusCode === 403){
|
|
||||||
resolve(false)
|
|
||||||
} else {
|
|
||||||
// 204 if valid
|
|
||||||
resolve(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invalidates an access token. The clientToken must match the
|
|
||||||
* token used to create the provided accessToken.
|
|
||||||
*
|
|
||||||
* @param {string} accessToken The access token to invalidate.
|
|
||||||
* @param {string} clientToken The launcher's client token.
|
|
||||||
*
|
|
||||||
* @see http://wiki.vg/Authentication#Invalidate
|
|
||||||
*/
|
|
||||||
exports.invalidate = function(accessToken, clientToken){
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
request.post(authpath + '/invalidate',
|
|
||||||
{
|
|
||||||
json: true,
|
|
||||||
body: {
|
|
||||||
accessToken,
|
|
||||||
clientToken
|
|
||||||
}
|
|
||||||
},
|
|
||||||
function(error, response, body){
|
|
||||||
if(error){
|
|
||||||
logger.error('Error during invalidation.', error)
|
|
||||||
reject(error)
|
|
||||||
} else {
|
|
||||||
if(response.statusCode === 204){
|
|
||||||
resolve()
|
|
||||||
} else {
|
|
||||||
reject(body)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Refresh a user's authentication. This should be used to keep a user logged
|
|
||||||
* in without asking them for their credentials again. A new access token will
|
|
||||||
* be generated using a recent invalid access token. See Wiki for more info.
|
|
||||||
*
|
|
||||||
* @param {string} accessToken The old access token.
|
|
||||||
* @param {string} clientToken The launcher's client token.
|
|
||||||
* @param {boolean} requestUser Optional. Adds user object to the reponse.
|
|
||||||
*
|
|
||||||
* @see http://wiki.vg/Authentication#Refresh
|
|
||||||
*/
|
|
||||||
exports.refresh = function(accessToken, clientToken, requestUser = true){
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
request.post(authpath + '/refresh',
|
|
||||||
{
|
|
||||||
json: true,
|
|
||||||
body: {
|
|
||||||
accessToken,
|
|
||||||
clientToken,
|
|
||||||
requestUser
|
|
||||||
}
|
|
||||||
},
|
|
||||||
function(error, response, body){
|
|
||||||
if(error){
|
|
||||||
logger.error('Error during refresh.', error)
|
|
||||||
reject(error)
|
|
||||||
} else {
|
|
||||||
if(response.statusCode === 200){
|
|
||||||
resolve(body)
|
|
||||||
} else {
|
|
||||||
reject(body)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
@ -96,6 +96,16 @@ class ProcessBuilder {
|
|||||||
return child
|
return child
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the platform specific classpath separator. On windows, this is a semicolon.
|
||||||
|
* On Unix, this is a colon.
|
||||||
|
*
|
||||||
|
* @returns {string} The classpath separator for the current operating system.
|
||||||
|
*/
|
||||||
|
static getClasspathSeparator() {
|
||||||
|
return process.platform === 'win32' ? ';' : ':'
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if an optional mod is enabled from its configuration value. If the
|
* Determine if an optional mod is enabled from its configuration value. If the
|
||||||
* configuration value is null, the required object will be used to
|
* configuration value is null, the required object will be used to
|
||||||
@ -339,7 +349,7 @@ class ProcessBuilder {
|
|||||||
|
|
||||||
// Classpath Argument
|
// Classpath Argument
|
||||||
args.push('-cp')
|
args.push('-cp')
|
||||||
args.push(this.classpathArg(mods, tempNativePath).join(process.platform === 'win32' ? ';' : ':'))
|
args.push(this.classpathArg(mods, tempNativePath).join(ProcessBuilder.getClasspathSeparator()))
|
||||||
|
|
||||||
// Java Arguments
|
// Java Arguments
|
||||||
if(process.platform === 'darwin'){
|
if(process.platform === 'darwin'){
|
||||||
@ -377,6 +387,19 @@ class ProcessBuilder {
|
|||||||
// JVM Arguments First
|
// JVM Arguments First
|
||||||
let args = this.versionData.arguments.jvm
|
let args = this.versionData.arguments.jvm
|
||||||
|
|
||||||
|
// Debug securejarhandler
|
||||||
|
// args.push('-Dbsl.debug=true')
|
||||||
|
|
||||||
|
if(this.forgeData.arguments.jvm != null) {
|
||||||
|
for(const argStr of this.forgeData.arguments.jvm) {
|
||||||
|
args.push(argStr
|
||||||
|
.replaceAll('${library_directory}', this.libPath)
|
||||||
|
.replaceAll('${classpath_separator}', ProcessBuilder.getClasspathSeparator())
|
||||||
|
.replaceAll('${version_name}', this.forgeData.id)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//args.push('-Dlog4j.configurationFile=D:\\WesterosCraft\\game\\common\\assets\\log_configs\\client-1.12.xml')
|
//args.push('-Dlog4j.configurationFile=D:\\WesterosCraft\\game\\common\\assets\\log_configs\\client-1.12.xml')
|
||||||
|
|
||||||
// Java Arguments
|
// Java Arguments
|
||||||
@ -489,7 +512,7 @@ class ProcessBuilder {
|
|||||||
val = args[i].replace(argDiscovery, this.launcherVersion)
|
val = args[i].replace(argDiscovery, this.launcherVersion)
|
||||||
break
|
break
|
||||||
case 'classpath':
|
case 'classpath':
|
||||||
val = this.classpathArg(mods, tempNativePath).join(process.platform === 'win32' ? ';' : ':')
|
val = this.classpathArg(mods, tempNativePath).join(ProcessBuilder.getClasspathSeparator())
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if(val != null){
|
if(val != null){
|
||||||
@ -647,9 +670,13 @@ class ProcessBuilder {
|
|||||||
classpathArg(mods, tempNativePath){
|
classpathArg(mods, tempNativePath){
|
||||||
let cpArgs = []
|
let cpArgs = []
|
||||||
|
|
||||||
// Add the version.jar to the classpath.
|
if(!Util.mcVersionAtLeast('1.17', this.server.getMinecraftVersion())) {
|
||||||
const version = this.versionData.id
|
// Add the version.jar to the classpath.
|
||||||
cpArgs.push(path.join(this.commonDir, 'versions', version, version + '.jar'))
|
// Must not be added to the classpath for Forge 1.17+.
|
||||||
|
const version = this.versionData.id
|
||||||
|
cpArgs.push(path.join(this.commonDir, 'versions', version, version + '.jar'))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if(this.usingLiteLoader){
|
if(this.usingLiteLoader){
|
||||||
cpArgs.push(this.llPath)
|
cpArgs.push(this.llPath)
|
||||||
@ -788,6 +815,15 @@ class ProcessBuilder {
|
|||||||
let libs = []
|
let libs = []
|
||||||
for(let sm of mdl.getSubModules()){
|
for(let sm of mdl.getSubModules()){
|
||||||
if(sm.getType() === DistroManager.Types.Library){
|
if(sm.getType() === DistroManager.Types.Library){
|
||||||
|
|
||||||
|
// TODO Add as file or something.
|
||||||
|
const x = sm.getIdentifier()
|
||||||
|
console.log(x)
|
||||||
|
if(x.includes(':universal') || x.includes(':slim') || x.includes(':extra') || x.includes(':srg') || x.includes(':client')) {
|
||||||
|
console.log('SKIPPING ' + x)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
libs.push(sm.getArtifact().getPath())
|
libs.push(sm.getArtifact().getPath())
|
||||||
}
|
}
|
||||||
// If this module has submodules, we need to resolve the libraries for those.
|
// If this module has submodules, we need to resolve the libraries for those.
|
||||||
|
@ -5,13 +5,12 @@
|
|||||||
const cp = require('child_process')
|
const cp = require('child_process')
|
||||||
const crypto = require('crypto')
|
const crypto = require('crypto')
|
||||||
const { URL } = require('url')
|
const { URL } = require('url')
|
||||||
const { getServerStatus } = require('helios-core')
|
const { MojangRestAPI, getServerStatus } = require('helios-core/mojang')
|
||||||
|
|
||||||
// Internal Requirements
|
// Internal Requirements
|
||||||
const DiscordWrapper = require('./assets/js/discordwrapper')
|
const DiscordWrapper = require('./assets/js/discordwrapper')
|
||||||
const Mojang = require('./assets/js/mojang')
|
|
||||||
const ProcessBuilder = require('./assets/js/processbuilder')
|
const ProcessBuilder = require('./assets/js/processbuilder')
|
||||||
const ServerStatus = require('./assets/js/serverstatus')
|
const { RestResponseStatus } = require('helios-core/common')
|
||||||
|
|
||||||
// Launch Elements
|
// Launch Elements
|
||||||
const launch_content = document.getElementById('launch_content')
|
const launch_content = document.getElementById('launch_content')
|
||||||
@ -166,55 +165,57 @@ const refreshMojangStatuses = async function(){
|
|||||||
let tooltipEssentialHTML = ''
|
let tooltipEssentialHTML = ''
|
||||||
let tooltipNonEssentialHTML = ''
|
let tooltipNonEssentialHTML = ''
|
||||||
|
|
||||||
try {
|
const response = await MojangRestAPI.status()
|
||||||
const statuses = await Mojang.status()
|
let statuses
|
||||||
greenCount = 0
|
if(response.responseStatus === RestResponseStatus.SUCCESS) {
|
||||||
greyCount = 0
|
statuses = response.data
|
||||||
|
} else {
|
||||||
for(let i=0; i<statuses.length; i++){
|
|
||||||
const service = statuses[i]
|
|
||||||
|
|
||||||
if(service.essential){
|
|
||||||
tooltipEssentialHTML += `<div class="mojangStatusContainer">
|
|
||||||
<span class="mojangStatusIcon" style="color: ${Mojang.statusToHex(service.status)};">•</span>
|
|
||||||
<span class="mojangStatusName">${service.name}</span>
|
|
||||||
</div>`
|
|
||||||
} else {
|
|
||||||
tooltipNonEssentialHTML += `<div class="mojangStatusContainer">
|
|
||||||
<span class="mojangStatusIcon" style="color: ${Mojang.statusToHex(service.status)};">•</span>
|
|
||||||
<span class="mojangStatusName">${service.name}</span>
|
|
||||||
</div>`
|
|
||||||
}
|
|
||||||
|
|
||||||
if(service.status === 'yellow' && status !== 'red'){
|
|
||||||
status = 'yellow'
|
|
||||||
} else if(service.status === 'red'){
|
|
||||||
status = 'red'
|
|
||||||
} else {
|
|
||||||
if(service.status === 'grey'){
|
|
||||||
++greyCount
|
|
||||||
}
|
|
||||||
++greenCount
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if(greenCount === statuses.length){
|
|
||||||
if(greyCount === statuses.length){
|
|
||||||
status = 'grey'
|
|
||||||
} else {
|
|
||||||
status = 'green'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (err) {
|
|
||||||
loggerLanding.warn('Unable to refresh Mojang service status.')
|
loggerLanding.warn('Unable to refresh Mojang service status.')
|
||||||
loggerLanding.debug(err)
|
statuses = MojangRestAPI.getDefaultStatuses()
|
||||||
|
}
|
||||||
|
|
||||||
|
greenCount = 0
|
||||||
|
greyCount = 0
|
||||||
|
|
||||||
|
for(let i=0; i<statuses.length; i++){
|
||||||
|
const service = statuses[i]
|
||||||
|
|
||||||
|
if(service.essential){
|
||||||
|
tooltipEssentialHTML += `<div class="mojangStatusContainer">
|
||||||
|
<span class="mojangStatusIcon" style="color: ${MojangRestAPI.statusToHex(service.status)};">•</span>
|
||||||
|
<span class="mojangStatusName">${service.name}</span>
|
||||||
|
</div>`
|
||||||
|
} else {
|
||||||
|
tooltipNonEssentialHTML += `<div class="mojangStatusContainer">
|
||||||
|
<span class="mojangStatusIcon" style="color: ${MojangRestAPI.statusToHex(service.status)};">•</span>
|
||||||
|
<span class="mojangStatusName">${service.name}</span>
|
||||||
|
</div>`
|
||||||
|
}
|
||||||
|
|
||||||
|
if(service.status === 'yellow' && status !== 'red'){
|
||||||
|
status = 'yellow'
|
||||||
|
} else if(service.status === 'red'){
|
||||||
|
status = 'red'
|
||||||
|
} else {
|
||||||
|
if(service.status === 'grey'){
|
||||||
|
++greyCount
|
||||||
|
}
|
||||||
|
++greenCount
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if(greenCount === statuses.length){
|
||||||
|
if(greyCount === statuses.length){
|
||||||
|
status = 'grey'
|
||||||
|
} else {
|
||||||
|
status = 'green'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('mojangStatusEssentialContainer').innerHTML = tooltipEssentialHTML
|
document.getElementById('mojangStatusEssentialContainer').innerHTML = tooltipEssentialHTML
|
||||||
document.getElementById('mojangStatusNonEssentialContainer').innerHTML = tooltipNonEssentialHTML
|
document.getElementById('mojangStatusNonEssentialContainer').innerHTML = tooltipNonEssentialHTML
|
||||||
document.getElementById('mojang_status_icon').style.color = Mojang.statusToHex(status)
|
document.getElementById('mojang_status_icon').style.color = MojangRestAPI.statusToHex(status)
|
||||||
}
|
}
|
||||||
|
|
||||||
const refreshServerStatus = async function(fade = false){
|
const refreshServerStatus = async function(fade = false){
|
||||||
|
@ -154,79 +154,6 @@ function formDisabled(v){
|
|||||||
loginRememberOption.disabled = v
|
loginRememberOption.disabled = v
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses an error and returns a user-friendly title and description
|
|
||||||
* for our error overlay.
|
|
||||||
*
|
|
||||||
* @param {Error | {cause: string, error: string, errorMessage: string}} err A Node.js
|
|
||||||
* error or Mojang error response.
|
|
||||||
*/
|
|
||||||
function resolveError(err){
|
|
||||||
// Mojang Response => err.cause | err.error | err.errorMessage
|
|
||||||
// Node error => err.code | err.message
|
|
||||||
if(err.cause != null && err.cause === 'UserMigratedException') {
|
|
||||||
return {
|
|
||||||
title: Lang.queryJS('login.error.userMigrated.title'),
|
|
||||||
desc: Lang.queryJS('login.error.userMigrated.desc')
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if(err.error != null){
|
|
||||||
if(err.error === 'ForbiddenOperationException'){
|
|
||||||
if(err.errorMessage != null){
|
|
||||||
if(err.errorMessage === 'Invalid credentials. Invalid username or password.'){
|
|
||||||
return {
|
|
||||||
title: Lang.queryJS('login.error.invalidCredentials.title'),
|
|
||||||
desc: Lang.queryJS('login.error.invalidCredentials.desc')
|
|
||||||
}
|
|
||||||
} else if(err.errorMessage === 'Invalid credentials.'){
|
|
||||||
return {
|
|
||||||
title: Lang.queryJS('login.error.rateLimit.title'),
|
|
||||||
desc: Lang.queryJS('login.error.rateLimit.desc')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Request errors (from Node).
|
|
||||||
if(err.code != null){
|
|
||||||
if(err.code === 'ENOENT'){
|
|
||||||
// No Internet.
|
|
||||||
return {
|
|
||||||
title: Lang.queryJS('login.error.noInternet.title'),
|
|
||||||
desc: Lang.queryJS('login.error.noInternet.desc')
|
|
||||||
}
|
|
||||||
} else if(err.code === 'ENOTFOUND'){
|
|
||||||
// Could not reach server.
|
|
||||||
return {
|
|
||||||
title: Lang.queryJS('login.error.authDown.title'),
|
|
||||||
desc: Lang.queryJS('login.error.authDown.desc')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(err.message != null){
|
|
||||||
if(err.message === 'NotPaidAccount'){
|
|
||||||
return {
|
|
||||||
title: Lang.queryJS('login.error.notPaid.title'),
|
|
||||||
desc: Lang.queryJS('login.error.notPaid.desc')
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Unknown error with request.
|
|
||||||
return {
|
|
||||||
title: Lang.queryJS('login.error.unknown.title'),
|
|
||||||
desc: err.message
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Unknown Mojang error.
|
|
||||||
return {
|
|
||||||
title: err.error,
|
|
||||||
desc: err.errorMessage
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let loginViewOnSuccess = VIEWS.landing
|
let loginViewOnSuccess = VIEWS.landing
|
||||||
let loginViewOnCancel = VIEWS.settings
|
let loginViewOnCancel = VIEWS.settings
|
||||||
let loginViewCancelHandler
|
let loginViewCancelHandler
|
||||||
@ -285,16 +212,15 @@ loginButton.addEventListener('click', () => {
|
|||||||
formDisabled(false)
|
formDisabled(false)
|
||||||
})
|
})
|
||||||
}, 1000)
|
}, 1000)
|
||||||
}).catch((err) => {
|
}).catch((displayableError) => {
|
||||||
loginLoading(false)
|
loginLoading(false)
|
||||||
const errF = resolveError(err)
|
setOverlayContent(displayableError.title, displayableError.desc, Lang.queryJS('login.tryAgain'))
|
||||||
setOverlayContent(errF.title, errF.desc, Lang.queryJS('login.tryAgain'))
|
|
||||||
setOverlayHandler(() => {
|
setOverlayHandler(() => {
|
||||||
formDisabled(false)
|
formDisabled(false)
|
||||||
toggleOverlay(false)
|
toggleOverlay(false)
|
||||||
})
|
})
|
||||||
toggleOverlay(true)
|
toggleOverlay(true)
|
||||||
loggerLogin.log('Error while logging in.', err)
|
loggerLogin.log('Error while logging in.', displayableError)
|
||||||
})
|
})
|
||||||
|
|
||||||
})
|
})
|
2788
package-lock.json
generated
2788
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
17
package.json
17
package.json
@ -23,16 +23,17 @@
|
|||||||
"node": "16.x.x"
|
"node": "16.x.x"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@electron/remote": "^2.0.1",
|
"@electron/remote": "^2.0.4",
|
||||||
"adm-zip": "^0.5.9",
|
"adm-zip": "^0.5.9",
|
||||||
"async": "^3.2.1",
|
"async": "^3.2.3",
|
||||||
"discord-rpc": "^3.2.0",
|
"discord-rpc-patch": "^4.0.1",
|
||||||
"ejs": "^3.1.6",
|
"ejs": "^3.1.6",
|
||||||
"ejs-electron": "^2.1.1",
|
"ejs-electron": "^2.1.1",
|
||||||
"electron-updater": "^4.3.9",
|
"electron-updater": "^4.6.5",
|
||||||
"fs-extra": "^10.0.0",
|
"fs-extra": "^10.0.0",
|
||||||
"github-syntax-dark": "^0.5.0",
|
"github-syntax-dark": "^0.5.0",
|
||||||
"helios-core": "^0.1.0-alpha.3",
|
"got": "^11.8.3",
|
||||||
|
"helios-core": "^0.1.0-alpha.5",
|
||||||
"jquery": "^3.6.0",
|
"jquery": "^3.6.0",
|
||||||
"node-stream-zip": "^1.15.0",
|
"node-stream-zip": "^1.15.0",
|
||||||
"request": "^2.88.2",
|
"request": "^2.88.2",
|
||||||
@ -41,9 +42,9 @@
|
|||||||
"winreg": "^1.2.4"
|
"winreg": "^1.2.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"electron": "^15.2.0",
|
"electron": "^16.0.8",
|
||||||
"electron-builder": "^22.13.1",
|
"electron-builder": "^22.14.13",
|
||||||
"eslint": "^8.0.1"
|
"eslint": "^8.8.0"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
Loading…
Reference in New Issue
Block a user