2018-04-25 17:11:10 -07:00
/ * *
* Script for login . ejs
* /
2018-04-25 14:06:10 -07:00
// Validation Regexes.
2018-04-25 14:40:46 -07:00
const validUsername = /^[a-zA-Z0-9_]{1,16}$/
const basicEmail = /^\S+@\S+\.\S+$/
2018-04-25 17:11:10 -07:00
//const validEmail = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i
2018-04-25 14:40:46 -07:00
// Login Elements
2018-05-30 19:22:17 -07:00
const loginCancelContainer = document . getElementById ( 'loginCancelContainer' )
const loginCancelButton = document . getElementById ( 'loginCancelButton' )
2018-04-25 14:40:46 -07:00
const loginEmailError = document . getElementById ( 'loginEmailError' )
const loginUsername = document . getElementById ( 'loginUsername' )
const loginPasswordError = document . getElementById ( 'loginPasswordError' )
const loginPassword = document . getElementById ( 'loginPassword' )
const checkmarkContainer = document . getElementById ( 'checkmarkContainer' )
const loginRememberOption = document . getElementById ( 'loginRememberOption' )
const loginButton = document . getElementById ( 'loginButton' )
2018-04-26 15:41:26 -07:00
const loginForm = document . getElementById ( 'loginForm' )
2018-04-25 14:06:10 -07:00
// Control variables.
let lu = false , lp = false
2018-08-22 11:21:49 -07:00
const loggerLogin = LoggerUtil ( '%c[Login]' , 'color: #000668; font-weight: bold' )
2018-04-25 14:40:46 -07:00
/ * *
* Show a login error .
*
* @ param { HTMLElement } element The element on which to display the error .
* @ param { string } value The error text .
* /
2018-04-25 14:06:10 -07:00
function showError ( element , value ) {
element . innerHTML = value
element . style . opacity = 1
}
2018-04-25 14:40:46 -07:00
/ * *
* Shake a login error to add emphasis .
*
* @ param { HTMLElement } element The element to shake .
* /
2018-04-25 14:06:10 -07:00
function shakeError ( element ) {
if ( element . style . opacity == 1 ) {
element . classList . remove ( 'shake' )
void element . offsetWidth
element . classList . add ( 'shake' )
}
}
2018-04-25 14:40:46 -07:00
/ * *
* Validate that an email field is neither empty nor invalid .
*
* @ param { string } value The email value .
* /
2018-04-25 14:06:10 -07:00
function validateEmail ( value ) {
if ( value ) {
if ( ! basicEmail . test ( value ) && ! validUsername . test ( value ) ) {
showError ( loginEmailError , '* Invalid Value' )
loginDisabled ( true )
lu = false
} else {
loginEmailError . style . opacity = 0
lu = true
if ( lp ) {
loginDisabled ( false )
}
}
} else {
lu = false
showError ( loginEmailError , '* Required' )
loginDisabled ( true )
}
}
2018-04-25 14:40:46 -07:00
/ * *
* Validate that the password field is not empty .
*
* @ param { string } value The password value .
* /
2018-04-25 14:06:10 -07:00
function validatePassword ( value ) {
if ( value ) {
loginPasswordError . style . opacity = 0
lp = true
if ( lu ) {
loginDisabled ( false )
}
} else {
lp = false
showError ( loginPasswordError , '* Required' )
loginDisabled ( true )
}
}
// Emphasize errors with shake when focus is lost.
loginUsername . addEventListener ( 'focusout' , ( e ) => {
validateEmail ( e . target . value )
shakeError ( loginEmailError )
} )
loginPassword . addEventListener ( 'focusout' , ( e ) => {
validatePassword ( e . target . value )
shakeError ( loginPasswordError )
} )
// Validate input for each field.
loginUsername . addEventListener ( 'input' , ( e ) => {
validateEmail ( e . target . value )
} )
loginPassword . addEventListener ( 'input' , ( e ) => {
validatePassword ( e . target . value )
} )
2018-04-25 14:40:46 -07:00
/ * *
* Enable or disable the login button .
*
* @ param { boolean } v True to enable , false to disable .
* /
2018-04-25 14:06:10 -07:00
function loginDisabled ( v ) {
if ( loginButton . disabled !== v ) {
loginButton . disabled = v
}
}
2018-04-25 14:40:46 -07:00
/ * *
* Enable or disable loading elements .
*
* @ param { boolean } v True to enable , false to disable .
* /
2018-04-25 14:06:10 -07:00
function loginLoading ( v ) {
if ( v ) {
loginButton . setAttribute ( 'loading' , v )
loginButton . innerHTML = loginButton . innerHTML . replace ( 'LOGIN' , 'LOGGING IN' )
} else {
loginButton . removeAttribute ( 'loading' )
loginButton . innerHTML = loginButton . innerHTML . replace ( 'LOGGING IN' , 'LOGIN' )
}
}
2018-04-25 14:40:46 -07:00
/ * *
* Enable or disable login form .
*
* @ param { boolean } v True to enable , false to disable .
* /
2018-04-25 14:06:10 -07:00
function formDisabled ( v ) {
loginDisabled ( v )
2018-05-30 19:22:17 -07:00
loginCancelButton . disabled = v
2018-04-25 14:06:10 -07:00
loginUsername . disabled = v
loginPassword . disabled = v
if ( v ) {
checkmarkContainer . setAttribute ( 'disabled' , v )
} else {
checkmarkContainer . removeAttribute ( 'disabled' )
}
loginRememberOption . disabled = v
}
2018-04-25 14:40:46 -07:00
/ * *
* 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 .
* /
2018-04-25 14:06:10 -07:00
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 : 'Error During Login:<br>Invalid Credentials' ,
desc : 'You\'ve attempted to login with a migrated account. Try again using the account email as the username.'
}
} else {
if ( err . error != null ) {
if ( err . error === 'ForbiddenOperationException' ) {
if ( err . errorMessage != null ) {
if ( err . errorMessage === 'Invalid credentials. Invalid username or password.' ) {
return {
title : 'Error During Login:<br>Invalid Credentials' ,
desc : 'The email or password you\'ve entered is incorrect. Please try again.'
}
} else if ( err . errorMessage === 'Invalid credentials.' ) {
return {
title : 'Error During Login:<br>Too Many Attempts' ,
desc : 'There have been too many login attempts with this account recently. Please try again later.'
}
}
}
}
} else {
// Request errors (from Node).
if ( err . code != null ) {
if ( err . code === 'ENOENT' ) {
// No Internet.
return {
title : 'Error During Login:<br>No Internet Connection' ,
desc : 'You must be connected to the internet in order to login. Please connect and try again.'
}
} else if ( err . code === 'ENOTFOUND' ) {
// Could not reach server.
return {
title : 'Error During Login:<br>Authentication Server Offline' ,
desc : 'Mojang\'s authentication server is currently offline or unreachable. Please wait a bit and try again. You can check the status of the server on <a href="https://help.mojang.com/">Mojang\'s help portal</a>.'
}
}
}
}
}
if ( err . message != null ) {
2019-02-05 14:26:00 -08:00
if ( err . message === 'NotPaidAccount' ) {
return {
title : 'Error During Login:<br>Game Not Purchased' ,
desc : 'The account you are trying to login with has not purchased a copy of Minecraft.<br>You may purchase a copy on <a href="https://minecraft.net/">Minecraft.net</a>'
}
} else {
// Unknown error with request.
return {
title : 'Error During Login:<br>Unknown Error' ,
desc : err . message
}
2018-04-25 14:06:10 -07:00
}
} else {
// Unknown Mojang error.
return {
title : err . error ,
desc : err . errorMessage
}
}
}
2018-05-30 19:22:17 -07:00
let loginViewOnSuccess = VIEWS . landing
let loginViewOnCancel = VIEWS . settings
2018-08-22 07:54:09 -07:00
let loginViewCancelHandler
2018-05-30 19:22:17 -07:00
function loginCancelEnabled ( val ) {
if ( val ) {
$ ( loginCancelContainer ) . show ( )
} else {
$ ( loginCancelContainer ) . hide ( )
}
}
loginCancelButton . onclick = ( e ) => {
switchView ( getCurrentView ( ) , loginViewOnCancel , 500 , 500 , ( ) => {
2019-02-05 14:26:00 -08:00
loginUsername . value = ''
loginPassword . value = ''
2018-05-30 19:22:17 -07:00
loginCancelEnabled ( false )
2018-08-22 07:54:09 -07:00
if ( loginViewCancelHandler != null ) {
loginViewCancelHandler ( )
loginViewCancelHandler = null
}
2018-05-30 19:22:17 -07:00
} )
}
2018-04-26 15:41:26 -07:00
// Disable default form behavior.
loginForm . onsubmit = ( ) => { return false }
2018-04-25 14:40:46 -07:00
// Bind login button behavior.
2018-04-25 14:06:10 -07:00
loginButton . addEventListener ( 'click' , ( ) => {
// Disable form.
formDisabled ( true )
// Show loading stuff.
loginLoading ( true )
AuthManager . addAccount ( loginUsername . value , loginPassword . value ) . then ( ( value ) => {
2018-04-29 15:05:59 -07:00
updateSelectedAccount ( value )
2018-04-25 14:06:10 -07:00
loginButton . innerHTML = loginButton . innerHTML . replace ( 'LOGGING IN' , 'SUCCESS' )
$ ( '.circle-loader' ) . toggleClass ( 'load-complete' )
$ ( '.checkmark' ) . toggle ( )
setTimeout ( ( ) => {
2018-05-30 19:22:17 -07:00
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.
2018-08-22 07:54:09 -07:00
loginViewCancelHandler = null // Reset this for good measure.
2018-05-09 19:23:37 -07:00
loginUsername . value = ''
loginPassword . value = ''
2018-05-29 18:47:55 -07:00
$ ( '.circle-loader' ) . toggleClass ( 'load-complete' )
$ ( '.checkmark' ) . toggle ( )
2018-05-09 19:23:37 -07:00
loginLoading ( false )
loginButton . innerHTML = loginButton . innerHTML . replace ( 'SUCCESS' , 'LOGIN' )
formDisabled ( false )
2018-04-25 14:06:10 -07:00
} )
} , 1000 )
} ) . catch ( ( err ) => {
loginLoading ( false )
const errF = resolveError ( err )
setOverlayContent ( errF . title , errF . desc , 'Try Again' )
setOverlayHandler ( ( ) => {
formDisabled ( false )
toggleOverlay ( false )
} )
toggleOverlay ( true )
2018-08-22 11:21:49 -07:00
loggerLogin . log ( 'Error while logging in.' , err )
2018-04-25 14:06:10 -07:00
} )
} )