Add files via upload

This commit is contained in:
MastermDEV 2020-06-18 18:19:14 -07:00 committed by GitHub
parent d84b162867
commit 6c0e851f2b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 4113 additions and 4113 deletions

View File

@ -1,73 +1,73 @@
let target = require('./assetguard')[process.argv[2]] let target = require('./assetguard')[process.argv[2]]
if(target == null){ if(target == null){
process.send({context: 'error', data: null, error: 'Invalid class name'}) process.send({context: 'error', data: null, error: 'Invalid class name'})
console.error('Invalid class name passed to argv[2], cannot continue.') console.error('Invalid class name passed to argv[2], cannot continue.')
process.exit(1) process.exit(1)
} }
let tracker = new target(...(process.argv.splice(3))) let tracker = new target(...(process.argv.splice(3)))
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0' process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
//const tracker = new AssetGuard(process.argv[2], process.argv[3]) //const tracker = new AssetGuard(process.argv[2], process.argv[3])
console.log('AssetExec Started') console.log('AssetExec Started')
// Temporary for debug purposes. // Temporary for debug purposes.
process.on('unhandledRejection', r => console.log(r)) process.on('unhandledRejection', r => console.log(r))
let percent = 0 let percent = 0
function assignListeners(){ function assignListeners(){
tracker.on('validate', (data) => { tracker.on('validate', (data) => {
process.send({context: 'validate', data}) process.send({context: 'validate', data})
}) })
tracker.on('progress', (data, acc, total) => { tracker.on('progress', (data, acc, total) => {
const currPercent = parseInt((acc/total) * 100) const currPercent = parseInt((acc/total) * 100)
if (currPercent !== percent) { if (currPercent !== percent) {
percent = currPercent percent = currPercent
process.send({context: 'progress', data, value: acc, total, percent}) process.send({context: 'progress', data, value: acc, total, percent})
} }
}) })
tracker.on('complete', (data, ...args) => { tracker.on('complete', (data, ...args) => {
process.send({context: 'complete', data, args}) process.send({context: 'complete', data, args})
}) })
tracker.on('error', (data, error) => { tracker.on('error', (data, error) => {
process.send({context: 'error', data, error}) process.send({context: 'error', data, error})
}) })
} }
assignListeners() assignListeners()
process.on('message', (msg) => { process.on('message', (msg) => {
if(msg.task === 'execute'){ if(msg.task === 'execute'){
const func = msg.function const func = msg.function
let nS = tracker[func] // Nonstatic context let nS = tracker[func] // Nonstatic context
let iS = target[func] // Static context let iS = target[func] // Static context
if(typeof nS === 'function' || typeof iS === 'function'){ if(typeof nS === 'function' || typeof iS === 'function'){
const f = typeof nS === 'function' ? nS : iS const f = typeof nS === 'function' ? nS : iS
const res = f.apply(f === nS ? tracker : null, msg.argsArr) const res = f.apply(f === nS ? tracker : null, msg.argsArr)
if(res instanceof Promise){ if(res instanceof Promise){
res.then((v) => { res.then((v) => {
process.send({result: v, context: func}) process.send({result: v, context: func})
}).catch((err) => { }).catch((err) => {
process.send({result: err.message || err, context: func}) process.send({result: err.message || err, context: func})
}) })
} else { } else {
process.send({result: res, context: func}) process.send({result: res, context: func})
} }
} else { } else {
process.send({context: 'error', data: null, error: `Function ${func} not found on ${process.argv[2]}`}) process.send({context: 'error', data: null, error: `Function ${func} not found on ${process.argv[2]}`})
} }
} else if(msg.task === 'changeContext'){ } else if(msg.task === 'changeContext'){
target = require('./assetguard')[msg.class] target = require('./assetguard')[msg.class]
if(target == null){ if(target == null){
process.send({context: 'error', data: null, error: `Invalid class ${msg.class}`}) process.send({context: 'error', data: null, error: `Invalid class ${msg.class}`})
} else { } else {
tracker = new target(...(msg.args)) tracker = new target(...(msg.args))
assignListeners() assignListeners()
} }
} }
}) })
process.on('disconnect', () => { process.on('disconnect', () => {
console.log('AssetExec Disconnected') console.log('AssetExec Disconnected')
process.exit(0) process.exit(0)
}) })

File diff suppressed because it is too large Load Diff

View File

@ -1,99 +1,99 @@
/** /**
* AuthManager * AuthManager
* *
* This module aims to abstract login procedures. Results from Mojang's REST api * This module aims to abstract login procedures. Results from Mojang's REST api
* are retrieved through our Mojang module. These results are processed and stored, * are retrieved through our Mojang module. These results are processed and stored,
* if applicable, in the config using the ConfigManager. All login procedures should * if applicable, in the config using the ConfigManager. All login procedures should
* be made through this module. * be made through this module.
* *
* @module authmanager * @module authmanager
*/ */
// Requirements // Requirements
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 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')
// Functions // Functions
/** /**
* Add an 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.
* *
* @param {string} username The account username (email if migrated). * @param {string} username The account username (email if migrated).
* @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.addAccount = async function(username, password){ exports.addAccount = async function(username, password){
try { try {
const session = await Mojang.authenticate(username, password, ConfigManager.getClientToken()) const session = await Mojang.authenticate(username, password, ConfigManager.getClientToken())
if(session.selectedProfile != null){ if(session.selectedProfile != null){
const ret = ConfigManager.addAuthAccount(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)
} }
ConfigManager.save() ConfigManager.save()
return ret return ret
} else { } else {
throw new Error('NotPaidAccount') throw new Error('NotPaidAccount')
} }
} catch (err){ } catch (err){
return Promise.reject(err) return Promise.reject(err)
} }
} }
/** /**
* Remove an account. This will invalidate the access token associated * Remove an 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.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()) await Mojang.invalidate(authAcc.accessToken, ConfigManager.getClientToken())
ConfigManager.removeAuthAccount(uuid) ConfigManager.removeAuthAccount(uuid)
ConfigManager.save() ConfigManager.save()
return Promise.resolve() return Promise.resolve()
} catch (err){ } catch (err){
return Promise.reject(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** * **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.
*/ */
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 isValid = await Mojang.validate(current.accessToken, ConfigManager.getClientToken())
if(!isValid){ if(!isValid){
try { try {
const session = await Mojang.refresh(current.accessToken, ConfigManager.getClientToken()) const session = await Mojang.refresh(current.accessToken, ConfigManager.getClientToken())
ConfigManager.updateAuthAccount(current.uuid, session.accessToken) ConfigManager.updateAuthAccount(current.uuid, session.accessToken)
ConfigManager.save() ConfigManager.save()
} catch(err) { } catch(err) {
logger.debug('Error while validating selected profile:', err) logger.debug('Error while validating selected profile:', err)
if(err && err.error === 'ForbiddenOperationException'){ if(err && err.error === 'ForbiddenOperationException'){
// What do we do? // What do we do?
} }
logger.log('Account access token is invalid.') logger.log('Account access token is invalid.')
return false return false
} }
loggerSuccess.log('Account access token validated.') loggerSuccess.log('Account access token validated.')
return true return true
} else { } else {
loggerSuccess.log('Account access token validated.') loggerSuccess.log('Account access token validated.')
return true return true
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,48 +1,48 @@
// 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')
let client let client
let activity let activity
exports.initRPC = function(genSettings, servSettings, initialDetails = 'Waiting for Client..'){ exports.initRPC = function(genSettings, servSettings, initialDetails = 'Waiting for Client..'){
client = new Client({ transport: 'ipc' }) client = new Client({ transport: 'ipc' })
activity = { activity = {
details: initialDetails, details: initialDetails,
state: 'Server: ' + servSettings.shortId, state: 'Server: ' + servSettings.shortId,
largeImageKey: servSettings.largeImageKey, largeImageKey: servSettings.largeImageKey,
largeImageText: servSettings.largeImageText, largeImageText: servSettings.largeImageText,
smallImageKey: genSettings.smallImageKey, smallImageKey: genSettings.smallImageKey,
smallImageText: genSettings.smallImageText, smallImageText: genSettings.smallImageText,
startTimestamp: new Date().getTime(), startTimestamp: new Date().getTime(),
instance: false instance: false
} }
client.on('ready', () => { client.on('ready', () => {
logger.log('Discord RPC Connected') logger.log('Discord RPC Connected')
client.setActivity(activity) client.setActivity(activity)
}) })
client.login({clientId: genSettings.clientId}).catch(error => { client.login({clientId: genSettings.clientId}).catch(error => {
if(error.message.includes('ENOENT')) { if(error.message.includes('ENOENT')) {
logger.log('Unable to initialize Discord Rich Presence, no client detected.') logger.log('Unable to initialize Discord Rich Presence, no client detected.')
} else { } else {
logger.log('Unable to initialize Discord Rich Presence: ' + error.message, error) logger.log('Unable to initialize Discord Rich Presence: ' + error.message, error)
} }
}) })
} }
exports.updateDetails = function(details){ exports.updateDetails = function(details){
activity.details = details activity.details = details
client.setActivity(activity) client.setActivity(activity)
} }
exports.shutdownRPC = function(){ exports.shutdownRPC = function(){
if(!client) return if(!client) return
client.clearActivity() client.clearActivity()
client.destroy() client.destroy()
client = null client = null
activity = null activity = null
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,232 +1,232 @@
const fs = require('fs-extra') const fs = require('fs-extra')
const path = require('path') const path = require('path')
const { shell } = require('electron') const { shell } = require('electron')
// Group #1: File Name (without .disabled, if any) // Group #1: File Name (without .disabled, if any)
// Group #2: File Extension (jar, zip, or litemod) // Group #2: File Extension (jar, zip, or litemod)
// Group #3: If it is disabled (if string 'disabled' is present) // Group #3: If it is disabled (if string 'disabled' is present)
const MOD_REGEX = /^(.+(jar|zip|litemod))(?:\.(disabled))?$/ const MOD_REGEX = /^(.+(jar|zip|litemod))(?:\.(disabled))?$/
const DISABLED_EXT = '.disabled' const DISABLED_EXT = '.disabled'
const SHADER_REGEX = /^(.+)\.zip$/ const SHADER_REGEX = /^(.+)\.zip$/
const SHADER_OPTION = /shaderPack=(.+)/ const SHADER_OPTION = /shaderPack=(.+)/
const SHADER_DIR = 'shaderpacks' const SHADER_DIR = 'shaderpacks'
const SHADER_CONFIG = 'optionsshaders.txt' const SHADER_CONFIG = 'optionsshaders.txt'
/** /**
* Validate that the given directory exists. If not, it is * Validate that the given directory exists. If not, it is
* created. * created.
* *
* @param {string} modsDir The path to the mods directory. * @param {string} modsDir The path to the mods directory.
*/ */
exports.validateDir = function(dir) { exports.validateDir = function(dir) {
fs.ensureDirSync(dir) fs.ensureDirSync(dir)
} }
/** /**
* Scan for drop-in mods in both the mods folder and version * Scan for drop-in mods in both the mods folder and version
* safe mods folder. * safe mods folder.
* *
* @param {string} modsDir The path to the mods directory. * @param {string} modsDir The path to the mods directory.
* @param {string} version The minecraft version of the server configuration. * @param {string} version The minecraft version of the server configuration.
* *
* @returns {{fullName: string, name: string, ext: string, disabled: boolean}[]} * @returns {{fullName: string, name: string, ext: string, disabled: boolean}[]}
* An array of objects storing metadata about each discovered mod. * An array of objects storing metadata about each discovered mod.
*/ */
exports.scanForDropinMods = function(modsDir, version) { exports.scanForDropinMods = function(modsDir, version) {
const modsDiscovered = [] const modsDiscovered = []
if(fs.existsSync(modsDir)){ if(fs.existsSync(modsDir)){
let modCandidates = fs.readdirSync(modsDir) let modCandidates = fs.readdirSync(modsDir)
let verCandidates = [] let verCandidates = []
const versionDir = path.join(modsDir, version) const versionDir = path.join(modsDir, version)
if(fs.existsSync(versionDir)){ if(fs.existsSync(versionDir)){
verCandidates = fs.readdirSync(versionDir) verCandidates = fs.readdirSync(versionDir)
} }
for(let file of modCandidates){ for(let file of modCandidates){
const match = MOD_REGEX.exec(file) const match = MOD_REGEX.exec(file)
if(match != null){ if(match != null){
modsDiscovered.push({ modsDiscovered.push({
fullName: match[0], fullName: match[0],
name: match[1], name: match[1],
ext: match[2], ext: match[2],
disabled: match[3] != null disabled: match[3] != null
}) })
} }
} }
for(let file of verCandidates){ for(let file of verCandidates){
const match = MOD_REGEX.exec(file) const match = MOD_REGEX.exec(file)
if(match != null){ if(match != null){
modsDiscovered.push({ modsDiscovered.push({
fullName: path.join(version, match[0]), fullName: path.join(version, match[0]),
name: match[1], name: match[1],
ext: match[2], ext: match[2],
disabled: match[3] != null disabled: match[3] != null
}) })
} }
} }
} }
return modsDiscovered return modsDiscovered
} }
/** /**
* Add dropin mods. * Add dropin mods.
* *
* @param {FileList} files The files to add. * @param {FileList} files The files to add.
* @param {string} modsDir The path to the mods directory. * @param {string} modsDir The path to the mods directory.
*/ */
exports.addDropinMods = function(files, modsdir) { exports.addDropinMods = function(files, modsdir) {
exports.validateDir(modsdir) exports.validateDir(modsdir)
for(let f of files) { for(let f of files) {
if(MOD_REGEX.exec(f.name) != null) { if(MOD_REGEX.exec(f.name) != null) {
fs.moveSync(f.path, path.join(modsdir, f.name)) fs.moveSync(f.path, path.join(modsdir, f.name))
} }
} }
} }
/** /**
* Delete a drop-in mod from the file system. * Delete a drop-in mod from the file system.
* *
* @param {string} modsDir The path to the mods directory. * @param {string} modsDir The path to the mods directory.
* @param {string} fullName The fullName of the discovered mod to delete. * @param {string} fullName The fullName of the discovered mod to delete.
* *
* @returns {boolean} True if the mod was deleted, otherwise false. * @returns {boolean} True if the mod was deleted, otherwise false.
*/ */
exports.deleteDropinMod = function(modsDir, fullName){ exports.deleteDropinMod = function(modsDir, fullName){
const res = shell.moveItemToTrash(path.join(modsDir, fullName)) const res = shell.moveItemToTrash(path.join(modsDir, fullName))
if(!res){ if(!res){
shell.beep() shell.beep()
} }
return res return res
} }
/** /**
* Toggle a discovered mod on or off. This is achieved by either * Toggle a discovered mod on or off. This is achieved by either
* adding or disabling the .disabled extension to the local file. * adding or disabling the .disabled extension to the local file.
* *
* @param {string} modsDir The path to the mods directory. * @param {string} modsDir The path to the mods directory.
* @param {string} fullName The fullName of the discovered mod to toggle. * @param {string} fullName The fullName of the discovered mod to toggle.
* @param {boolean} enable Whether to toggle on or off the mod. * @param {boolean} enable Whether to toggle on or off the mod.
* *
* @returns {Promise.<void>} A promise which resolves when the mod has * @returns {Promise.<void>} A promise which resolves when the mod has
* been toggled. If an IO error occurs the promise will be rejected. * been toggled. If an IO error occurs the promise will be rejected.
*/ */
exports.toggleDropinMod = function(modsDir, fullName, enable){ exports.toggleDropinMod = function(modsDir, fullName, enable){
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const oldPath = path.join(modsDir, fullName) const oldPath = path.join(modsDir, fullName)
const newPath = path.join(modsDir, enable ? fullName.substring(0, fullName.indexOf(DISABLED_EXT)) : fullName + DISABLED_EXT) const newPath = path.join(modsDir, enable ? fullName.substring(0, fullName.indexOf(DISABLED_EXT)) : fullName + DISABLED_EXT)
fs.rename(oldPath, newPath, (err) => { fs.rename(oldPath, newPath, (err) => {
if(err){ if(err){
reject(err) reject(err)
} else { } else {
resolve() resolve()
} }
}) })
}) })
} }
/** /**
* Check if a drop-in mod is enabled. * Check if a drop-in mod is enabled.
* *
* @param {string} fullName The fullName of the discovered mod to toggle. * @param {string} fullName The fullName of the discovered mod to toggle.
* @returns {boolean} True if the mod is enabled, otherwise false. * @returns {boolean} True if the mod is enabled, otherwise false.
*/ */
exports.isDropinModEnabled = function(fullName){ exports.isDropinModEnabled = function(fullName){
return !fullName.endsWith(DISABLED_EXT) return !fullName.endsWith(DISABLED_EXT)
} }
/** /**
* Scan for shaderpacks inside the shaderpacks folder. * Scan for shaderpacks inside the shaderpacks folder.
* *
* @param {string} instanceDir The path to the server instance directory. * @param {string} instanceDir The path to the server instance directory.
* *
* @returns {{fullName: string, name: string}[]} * @returns {{fullName: string, name: string}[]}
* An array of objects storing metadata about each discovered shaderpack. * An array of objects storing metadata about each discovered shaderpack.
*/ */
exports.scanForShaderpacks = function(instanceDir){ exports.scanForShaderpacks = function(instanceDir){
const shaderDir = path.join(instanceDir, SHADER_DIR) const shaderDir = path.join(instanceDir, SHADER_DIR)
const packsDiscovered = [{ const packsDiscovered = [{
fullName: 'OFF', fullName: 'OFF',
name: 'Off (Default)' name: 'Off (Default)'
}] }]
if(fs.existsSync(shaderDir)){ if(fs.existsSync(shaderDir)){
let modCandidates = fs.readdirSync(shaderDir) let modCandidates = fs.readdirSync(shaderDir)
for(let file of modCandidates){ for(let file of modCandidates){
const match = SHADER_REGEX.exec(file) const match = SHADER_REGEX.exec(file)
if(match != null){ if(match != null){
packsDiscovered.push({ packsDiscovered.push({
fullName: match[0], fullName: match[0],
name: match[1] name: match[1]
}) })
} }
} }
} }
return packsDiscovered return packsDiscovered
} }
/** /**
* Read the optionsshaders.txt file to locate the current * Read the optionsshaders.txt file to locate the current
* enabled pack. If the file does not exist, OFF is returned. * enabled pack. If the file does not exist, OFF is returned.
* *
* @param {string} instanceDir The path to the server instance directory. * @param {string} instanceDir The path to the server instance directory.
* *
* @returns {string} The file name of the enabled shaderpack. * @returns {string} The file name of the enabled shaderpack.
*/ */
exports.getEnabledShaderpack = function(instanceDir){ exports.getEnabledShaderpack = function(instanceDir){
exports.validateDir(instanceDir) exports.validateDir(instanceDir)
const optionsShaders = path.join(instanceDir, SHADER_CONFIG) const optionsShaders = path.join(instanceDir, SHADER_CONFIG)
if(fs.existsSync(optionsShaders)){ if(fs.existsSync(optionsShaders)){
const buf = fs.readFileSync(optionsShaders, {encoding: 'utf-8'}) const buf = fs.readFileSync(optionsShaders, {encoding: 'utf-8'})
const match = SHADER_OPTION.exec(buf) const match = SHADER_OPTION.exec(buf)
if(match != null){ if(match != null){
return match[1] return match[1]
} else { } else {
console.warn('WARNING: Shaderpack regex failed.') console.warn('WARNING: Shaderpack regex failed.')
} }
} }
return 'OFF' return 'OFF'
} }
/** /**
* Set the enabled shaderpack. * Set the enabled shaderpack.
* *
* @param {string} instanceDir The path to the server instance directory. * @param {string} instanceDir The path to the server instance directory.
* @param {string} pack the file name of the shaderpack. * @param {string} pack the file name of the shaderpack.
*/ */
exports.setEnabledShaderpack = function(instanceDir, pack){ exports.setEnabledShaderpack = function(instanceDir, pack){
exports.validateDir(instanceDir) exports.validateDir(instanceDir)
const optionsShaders = path.join(instanceDir, SHADER_CONFIG) const optionsShaders = path.join(instanceDir, SHADER_CONFIG)
let buf let buf
if(fs.existsSync(optionsShaders)){ if(fs.existsSync(optionsShaders)){
buf = fs.readFileSync(optionsShaders, {encoding: 'utf-8'}) buf = fs.readFileSync(optionsShaders, {encoding: 'utf-8'})
buf = buf.replace(SHADER_OPTION, `shaderPack=${pack}`) buf = buf.replace(SHADER_OPTION, `shaderPack=${pack}`)
} else { } else {
buf = `shaderPack=${pack}` buf = `shaderPack=${pack}`
} }
fs.writeFileSync(optionsShaders, buf, {encoding: 'utf-8'}) fs.writeFileSync(optionsShaders, buf, {encoding: 'utf-8'})
} }
/** /**
* Add shaderpacks. * Add shaderpacks.
* *
* @param {FileList} files The files to add. * @param {FileList} files The files to add.
* @param {string} instanceDir The path to the server instance directory. * @param {string} instanceDir The path to the server instance directory.
*/ */
exports.addShaderpacks = function(files, instanceDir) { exports.addShaderpacks = function(files, instanceDir) {
const p = path.join(instanceDir, SHADER_DIR) const p = path.join(instanceDir, SHADER_DIR)
exports.validateDir(p) exports.validateDir(p)
for(let f of files) { for(let f of files) {
if(SHADER_REGEX.exec(f.name) != null) { if(SHADER_REGEX.exec(f.name) != null) {
fs.moveSync(f.path, path.join(p, f.name)) fs.moveSync(f.path, path.join(p, f.name))
} }
} }
} }

View File

@ -1,5 +1,5 @@
'use strict' 'use strict'
const getFromEnv = parseInt(process.env.ELECTRON_IS_DEV, 10) === 1 const getFromEnv = parseInt(process.env.ELECTRON_IS_DEV, 10) === 1
const isEnvSet = 'ELECTRON_IS_DEV' in process.env const isEnvSet = 'ELECTRON_IS_DEV' in process.env
module.exports = isEnvSet ? getFromEnv : (process.defaultApp || /node_modules[\\/]electron[\\/]/.test(process.execPath)) module.exports = isEnvSet ? getFromEnv : (process.defaultApp || /node_modules[\\/]electron[\\/]/.test(process.execPath))

View File

@ -1,21 +1,21 @@
const fs = require('fs-extra') const fs = require('fs-extra')
const path = require('path') const path = require('path')
let lang let lang
exports.loadLanguage = function(id){ exports.loadLanguage = function(id){
lang = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'lang', `${id}.json`))) || {} lang = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'lang', `${id}.json`))) || {}
} }
exports.query = function(id){ exports.query = function(id){
let query = id.split('.') let query = id.split('.')
let res = lang let res = lang
for(let q of query){ for(let q of query){
res = res[q] res = res[q]
} }
return res === lang ? {} : res return res === lang ? {} : res
} }
exports.queryJS = function(id){ exports.queryJS = function(id){
return exports.query(`js.${id}`) return exports.query(`js.${id}`)
} }

View File

@ -1,32 +1,32 @@
class LoggerUtil { class LoggerUtil {
constructor(prefix, style){ constructor(prefix, style){
this.prefix = prefix this.prefix = prefix
this.style = style this.style = style
} }
log(){ log(){
console.log.apply(null, [this.prefix, this.style, ...arguments]) console.log.apply(null, [this.prefix, this.style, ...arguments])
} }
info(){ info(){
console.info.apply(null, [this.prefix, this.style, ...arguments]) console.info.apply(null, [this.prefix, this.style, ...arguments])
} }
warn(){ warn(){
console.warn.apply(null, [this.prefix, this.style, ...arguments]) console.warn.apply(null, [this.prefix, this.style, ...arguments])
} }
debug(){ debug(){
console.debug.apply(null, [this.prefix, this.style, ...arguments]) console.debug.apply(null, [this.prefix, this.style, ...arguments])
} }
error(){ error(){
console.error.apply(null, [this.prefix, this.style, ...arguments]) console.error.apply(null, [this.prefix, this.style, ...arguments])
} }
} }
module.exports = function (prefix, style){ module.exports = function (prefix, style){
return new LoggerUtil(prefix, style) return new LoggerUtil(prefix, style)
} }

View File

@ -1,271 +1,271 @@
/** /**
* Mojang * Mojang
* *
* This module serves as a minimal wrapper for Mojang's REST api. * This module serves as a minimal wrapper for Mojang's REST api.
* *
* @module mojang * @module mojang
*/ */
// Requirements // Requirements
const request = require('request') const request = require('request')
const logger = require('./loggerutil')('%c[Mojang]', 'color: #a02d2a; font-weight: bold') const logger = require('./loggerutil')('%c[Mojang]', 'color: #a02d2a; font-weight: bold')
// Constants // Constants
const minecraftAgent = { const minecraftAgent = {
name: 'Minecraft', name: 'Minecraft',
version: 1 version: 1
} }
const authpath = 'https://authserver.mojang.com' const authpath = 'https://authserver.mojang.com'
const statuses = [ const statuses = [
{ {
service: 'sessionserver.mojang.com', service: 'sessionserver.mojang.com',
status: 'grey', status: 'grey',
name: 'Multiplayer Session Service', name: 'Multiplayer Session Service',
essential: true essential: true
}, },
{ {
service: 'authserver.mojang.com', service: 'authserver.mojang.com',
status: 'grey', status: 'grey',
name: 'Authentication Service', name: 'Authentication Service',
essential: true essential: true
}, },
{ {
service: 'textures.minecraft.net', service: 'textures.minecraft.net',
status: 'grey', status: 'grey',
name: 'Minecraft Skins', name: 'Minecraft Skins',
essential: false essential: false
}, },
{ {
service: 'api.mojang.com', service: 'api.mojang.com',
status: 'grey', status: 'grey',
name: 'Public API', name: 'Public API',
essential: false essential: false
}, },
{ {
service: 'minecraft.net', service: 'minecraft.net',
status: 'grey', status: 'grey',
name: 'Minecraft.net', name: 'Minecraft.net',
essential: false essential: false
}, },
{ {
service: 'account.mojang.com', service: 'account.mojang.com',
status: 'grey', status: 'grey',
name: 'Mojang Accounts Website', name: 'Mojang Accounts Website',
essential: false essential: false
} }
] ]
// Functions // Functions
/** /**
* Converts a Mojang status color to a hex value. Valid statuses * Converts a Mojang status color to a hex value. Valid statuses
* are 'green', 'yellow', 'red', and 'grey'. Grey is a custom status * are 'green', 'yellow', 'red', and 'grey'. Grey is a custom status
* to our project which represents an unknown status. * to our project which represents an unknown status.
* *
* @param {string} status A valid status code. * @param {string} status A valid status code.
* @returns {string} The hex color of the status code. * @returns {string} The hex color of the status code.
*/ */
exports.statusToHex = function(status){ exports.statusToHex = function(status){
switch(status.toLowerCase()){ switch(status.toLowerCase()){
case 'green': case 'green':
return '#a5c325' return '#a5c325'
case 'yellow': case 'yellow':
return '#eac918' return '#eac918'
case 'red': case 'red':
return '#c32625' return '#c32625'
case 'grey': case 'grey':
default: default:
return '#848484' return '#848484'
} }
} }
/** /**
* Retrieves the status of Mojang's services. * Retrieves the status of Mojang's services.
* The response is condensed into a single object. Each service is * The response is condensed into a single object. Each service is
* a key, where the value is an object containing a status and name * a key, where the value is an object containing a status and name
* property. * property.
* *
* @see http://wiki.vg/Mojang_API#API_Status * @see http://wiki.vg/Mojang_API#API_Status
*/ */
exports.status = function(){ exports.status = function(){
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
request.get('https://status.mojang.com/check', request.get('https://status.mojang.com/check',
{ {
json: true, json: true,
timeout: 2500 timeout: 2500
}, },
function(error, response, body){ function(error, response, body){
if(error || response.statusCode !== 200){ if(error || response.statusCode !== 200){
logger.warn('Unable to retrieve Mojang status.') logger.warn('Unable to retrieve Mojang status.')
logger.debug('Error while retrieving Mojang statuses:', error) logger.debug('Error while retrieving Mojang statuses:', error)
//reject(error || response.statusCode) //reject(error || response.statusCode)
for(let i=0; i<statuses.length; i++){ for(let i=0; i<statuses.length; i++){
statuses[i].status = 'grey' statuses[i].status = 'grey'
} }
resolve(statuses) resolve(statuses)
} else { } else {
for(let i=0; i<body.length; i++){ for(let i=0; i<body.length; i++){
const key = Object.keys(body[i])[0] const key = Object.keys(body[i])[0]
inner: inner:
for(let j=0; j<statuses.length; j++){ for(let j=0; j<statuses.length; j++){
if(statuses[j].service === key) { if(statuses[j].service === key) {
statuses[j].status = body[i][key] statuses[j].status = body[i][key]
break inner break inner
} }
} }
} }
resolve(statuses) resolve(statuses)
} }
}) })
}) })
} }
/** /**
* Authenticate a user with their Mojang credentials. * Authenticate a user with their Mojang credentials.
* *
* @param {string} username The user's username, this is often an email. * @param {string} username The user's username, this is often an email.
* @param {string} password The user's password. * @param {string} password The user's password.
* @param {string} clientToken The launcher's Client Token. * @param {string} clientToken The launcher's Client Token.
* @param {boolean} requestUser Optional. Adds user object to the reponse. * @param {boolean} requestUser Optional. Adds user object to the reponse.
* @param {Object} agent Optional. Provided by default. Adds user info to the response. * @param {Object} agent Optional. Provided by default. Adds user info to the response.
* *
* @see http://wiki.vg/Authentication#Authenticate * @see http://wiki.vg/Authentication#Authenticate
*/ */
exports.authenticate = function(username, password, clientToken, requestUser = true, agent = minecraftAgent){ exports.authenticate = function(username, password, clientToken, requestUser = true, agent = minecraftAgent){
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const body = { const body = {
agent, agent,
username, username,
password, password,
requestUser requestUser
} }
if(clientToken != null){ if(clientToken != null){
body.clientToken = clientToken body.clientToken = clientToken
} }
request.post(authpath + '/authenticate', request.post(authpath + '/authenticate',
{ {
json: true, json: true,
body body
}, },
function(error, response, body){ function(error, response, body){
if(error){ if(error){
logger.error('Error during authentication.', error) logger.error('Error during authentication.', error)
reject(error) reject(error)
} else { } else {
if(response.statusCode === 200){ if(response.statusCode === 200){
resolve(body) resolve(body)
} else { } else {
reject(body || {code: 'ENOTFOUND'}) reject(body || {code: 'ENOTFOUND'})
} }
} }
}) })
}) })
} }
/** /**
* Validate an access token. This should always be done before launching. * Validate an access token. This should always be done before launching.
* The client token should match the one used to create the access token. * The client token should match the one used to create the access token.
* *
* @param {string} accessToken The access token to validate. * @param {string} accessToken The access token to validate.
* @param {string} clientToken The launcher's client token. * @param {string} clientToken The launcher's client token.
* *
* @see http://wiki.vg/Authentication#Validate * @see http://wiki.vg/Authentication#Validate
*/ */
exports.validate = function(accessToken, clientToken){ exports.validate = function(accessToken, clientToken){
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
request.post(authpath + '/validate', request.post(authpath + '/validate',
{ {
json: true, json: true,
body: { body: {
accessToken, accessToken,
clientToken clientToken
} }
}, },
function(error, response, body){ function(error, response, body){
if(error){ if(error){
logger.error('Error during validation.', error) logger.error('Error during validation.', error)
reject(error) reject(error)
} else { } else {
if(response.statusCode === 403){ if(response.statusCode === 403){
resolve(false) resolve(false)
} else { } else {
// 204 if valid // 204 if valid
resolve(true) resolve(true)
} }
} }
}) })
}) })
} }
/** /**
* Invalidates an access token. The clientToken must match the * Invalidates an access token. The clientToken must match the
* token used to create the provided accessToken. * token used to create the provided accessToken.
* *
* @param {string} accessToken The access token to invalidate. * @param {string} accessToken The access token to invalidate.
* @param {string} clientToken The launcher's client token. * @param {string} clientToken The launcher's client token.
* *
* @see http://wiki.vg/Authentication#Invalidate * @see http://wiki.vg/Authentication#Invalidate
*/ */
exports.invalidate = function(accessToken, clientToken){ exports.invalidate = function(accessToken, clientToken){
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
request.post(authpath + '/invalidate', request.post(authpath + '/invalidate',
{ {
json: true, json: true,
body: { body: {
accessToken, accessToken,
clientToken clientToken
} }
}, },
function(error, response, body){ function(error, response, body){
if(error){ if(error){
logger.error('Error during invalidation.', error) logger.error('Error during invalidation.', error)
reject(error) reject(error)
} else { } else {
if(response.statusCode === 204){ if(response.statusCode === 204){
resolve() resolve()
} else { } else {
reject(body) reject(body)
} }
} }
}) })
}) })
} }
/** /**
* Refresh a user's authentication. This should be used to keep a user logged * 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 * 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. * be generated using a recent invalid access token. See Wiki for more info.
* *
* @param {string} accessToken The old access token. * @param {string} accessToken The old access token.
* @param {string} clientToken The launcher's client token. * @param {string} clientToken The launcher's client token.
* @param {boolean} requestUser Optional. Adds user object to the reponse. * @param {boolean} requestUser Optional. Adds user object to the reponse.
* *
* @see http://wiki.vg/Authentication#Refresh * @see http://wiki.vg/Authentication#Refresh
*/ */
exports.refresh = function(accessToken, clientToken, requestUser = true){ exports.refresh = function(accessToken, clientToken, requestUser = true){
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
request.post(authpath + '/refresh', request.post(authpath + '/refresh',
{ {
json: true, json: true,
body: { body: {
accessToken, accessToken,
clientToken, clientToken,
requestUser requestUser
} }
}, },
function(error, response, body){ function(error, response, body){
if(error){ if(error){
logger.error('Error during refresh.', error) logger.error('Error during refresh.', error)
reject(error) reject(error)
} else { } else {
if(response.statusCode === 200){ if(response.statusCode === 200){
resolve(body) resolve(body)
} else { } else {
reject(body) reject(body)
} }
} }
}) })
}) })
} }

View File

@ -1,69 +1,69 @@
const {ipcRenderer} = require('electron') const {ipcRenderer} = require('electron')
const fs = require('fs-extra') const fs = require('fs-extra')
const os = require('os') const os = require('os')
const path = require('path') const path = require('path')
const ConfigManager = require('./configmanager') const ConfigManager = require('./configmanager')
const DistroManager = require('./distromanager') const DistroManager = require('./distromanager')
const LangLoader = require('./langloader') const LangLoader = require('./langloader')
const logger = require('./loggerutil')('%c[Preloader]', 'color: #a02d2a; font-weight: bold') const logger = require('./loggerutil')('%c[Preloader]', 'color: #a02d2a; font-weight: bold')
logger.log('Loading..') logger.log('Loading..')
// Load ConfigManager // Load ConfigManager
ConfigManager.load() ConfigManager.load()
// Load Strings // Load Strings
LangLoader.loadLanguage('en_US') LangLoader.loadLanguage('en_US')
function onDistroLoad(data){ function onDistroLoad(data){
if(data != null){ if(data != null){
// Resolve the selected server if its value has yet to be set. // Resolve the selected server if its value has yet to be set.
if(ConfigManager.getSelectedServer() == null || data.getServer(ConfigManager.getSelectedServer()) == null){ if(ConfigManager.getSelectedServer() == null || data.getServer(ConfigManager.getSelectedServer()) == null){
logger.log('Determining default selected server..') logger.log('Determining default selected server..')
ConfigManager.setSelectedServer(data.getMainServer().getID()) ConfigManager.setSelectedServer(data.getMainServer().getID())
ConfigManager.save() ConfigManager.save()
} }
} }
ipcRenderer.send('distributionIndexDone', data != null) ipcRenderer.send('distributionIndexDone', data != null)
} }
// Ensure Distribution is downloaded and cached. // Ensure Distribution is downloaded and cached.
DistroManager.pullRemote().then((data) => { DistroManager.pullRemote().then((data) => {
logger.log('Loaded distribution index.') logger.log('Loaded distribution index.')
onDistroLoad(data) onDistroLoad(data)
}).catch((err) => { }).catch((err) => {
logger.log('Failed to load distribution index.') logger.log('Failed to load distribution index.')
logger.error(err) logger.error(err)
logger.log('Attempting to load an older version of the distribution index.') logger.log('Attempting to load an older version of the distribution index.')
// Try getting a local copy, better than nothing. // Try getting a local copy, better than nothing.
DistroManager.pullLocal().then((data) => { DistroManager.pullLocal().then((data) => {
logger.log('Successfully loaded an older version of the distribution index.') logger.log('Successfully loaded an older version of the distribution index.')
onDistroLoad(data) onDistroLoad(data)
}).catch((err) => { }).catch((err) => {
logger.log('Failed to load an older version of the distribution index.') logger.log('Failed to load an older version of the distribution index.')
logger.log('Application cannot run.') logger.log('Application cannot run.')
logger.error(err) logger.error(err)
onDistroLoad(null) onDistroLoad(null)
}) })
}) })
// Clean up temp dir incase previous launches ended unexpectedly. // Clean up temp dir incase previous launches ended unexpectedly.
fs.remove(path.join(os.tmpdir(), ConfigManager.getTempNativeFolder()), (err) => { fs.remove(path.join(os.tmpdir(), ConfigManager.getTempNativeFolder()), (err) => {
if(err){ if(err){
logger.warn('Error while cleaning natives directory', err) logger.warn('Error while cleaning natives directory', err)
} else { } else {
logger.log('Cleaned natives directory.') logger.log('Cleaned natives directory.')
} }
}) })

View File

@ -317,7 +317,7 @@ class ProcessBuilder {
// Java Arguments // Java Arguments
if(process.platform === 'darwin'){ if(process.platform === 'darwin'){
args.push('-Xdock:name=HeliosLauncher') args.push('-Xdock:name=NemesisMCLauncher')
args.push('-Xdock:icon=' + path.join(__dirname, '..', 'images', 'minecraft.icns')) args.push('-Xdock:icon=' + path.join(__dirname, '..', 'images', 'minecraft.icns'))
} }
args.push('-Xmx' + ConfigManager.getMaxRAM()) args.push('-Xmx' + ConfigManager.getMaxRAM())
@ -355,7 +355,7 @@ class ProcessBuilder {
// Java Arguments // Java Arguments
if(process.platform === 'darwin'){ if(process.platform === 'darwin'){
args.push('-Xdock:name=HeliosLauncher') args.push('-Xdock:name=NemesisMCLauncher')
args.push('-Xdock:icon=' + path.join(__dirname, '..', 'images', 'minecraft.icns')) args.push('-Xdock:icon=' + path.join(__dirname, '..', 'images', 'minecraft.icns'))
} }
args.push('-Xmx' + ConfigManager.getMaxRAM()) args.push('-Xmx' + ConfigManager.getMaxRAM())
@ -457,7 +457,7 @@ class ProcessBuilder {
val = args[i].replace(argDiscovery, tempNativePath) val = args[i].replace(argDiscovery, tempNativePath)
break break
case 'launcher_name': case 'launcher_name':
val = args[i].replace(argDiscovery, 'Helios-Launcher') val = args[i].replace(argDiscovery, 'NemesisMC-Launcher')
break break
case 'launcher_version': case 'launcher_version':
val = args[i].replace(argDiscovery, this.launcherVersion) val = args[i].replace(argDiscovery, this.launcherVersion)

View File

@ -1,65 +1,65 @@
const net = require('net') const net = require('net')
/** /**
* Retrieves the status of a minecraft server. * Retrieves the status of a minecraft server.
* *
* @param {string} address The server address. * @param {string} address The server address.
* @param {number} port Optional. The port of the server. Defaults to 25565. * @param {number} port Optional. The port of the server. Defaults to 25565.
* @returns {Promise.<Object>} A promise which resolves to an object containing * @returns {Promise.<Object>} A promise which resolves to an object containing
* status information. * status information.
*/ */
exports.getStatus = function(address, port = 25565){ exports.getStatus = function(address, port = 25565){
if(port == null || port == ''){ if(port == null || port == ''){
port = 25565 port = 25565
} }
if(typeof port === 'string'){ if(typeof port === 'string'){
port = parseInt(port) port = parseInt(port)
} }
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const socket = net.connect(port, address, () => { const socket = net.connect(port, address, () => {
let buff = Buffer.from([0xFE, 0x01]) let buff = Buffer.from([0xFE, 0x01])
socket.write(buff) socket.write(buff)
}) })
socket.setTimeout(2500, () => { socket.setTimeout(2500, () => {
socket.end() socket.end()
reject({ reject({
code: 'ETIMEDOUT', code: 'ETIMEDOUT',
errno: 'ETIMEDOUT', errno: 'ETIMEDOUT',
address, address,
port port
}) })
}) })
socket.on('data', (data) => { socket.on('data', (data) => {
if(data != null && data != ''){ if(data != null && data != ''){
let server_info = data.toString().split('\x00\x00\x00') let server_info = data.toString().split('\x00\x00\x00')
const NUM_FIELDS = 6 const NUM_FIELDS = 6
if(server_info != null && server_info.length >= NUM_FIELDS){ if(server_info != null && server_info.length >= NUM_FIELDS){
resolve({ resolve({
online: true, online: true,
version: server_info[2].replace(/\u0000/g, ''), version: server_info[2].replace(/\u0000/g, ''),
motd: server_info[3].replace(/\u0000/g, ''), motd: server_info[3].replace(/\u0000/g, ''),
onlinePlayers: server_info[4].replace(/\u0000/g, ''), onlinePlayers: server_info[4].replace(/\u0000/g, ''),
maxPlayers: server_info[5].replace(/\u0000/g,'') maxPlayers: server_info[5].replace(/\u0000/g,'')
}) })
} else { } else {
resolve({ resolve({
online: false online: false
}) })
} }
} }
socket.end() socket.end()
}) })
socket.on('error', (err) => { socket.on('error', (err) => {
socket.destroy() socket.destroy()
reject(err) reject(err)
// ENOTFOUND = Unable to resolve. // ENOTFOUND = Unable to resolve.
// ECONNREFUSED = Unable to connect to port. // ECONNREFUSED = Unable to connect to port.
}) })
}) })
} }