@@ -5,6 +5,7 @@ const pathnameRegex = /^\/\w{2}-\w{2}\/n?iv/;
const MAX _SIGNIN _ATTEMPTS = 1 ;
const MAX _SIGNIN _ATTEMPTS = 1 ;
const PAGE _WAIT _TIME = 3792 ;
const PAGE _WAIT _TIME = 3792 ;
const MINUTE = 60 ;
const MINUTE = 60 ;
const RANDOM _JITTER = 0.1 ;
const SOFT _BAN _TIMEOUT = 27 ;
const SOFT _BAN _TIMEOUT = 27 ;
const NOTIF _CHANNEL = "snegov_test"
const NOTIF _CHANNEL = "snegov_test"
@@ -44,11 +45,15 @@ function getRandomInt(max) {
return Math . floor ( Math . random ( ) * Math . floor ( max ) ) ;
return Math . floor ( Math . random ( ) * Math . floor ( max ) ) ;
}
}
function getJitter ( frequency ) {
return frequency * MINUTE * RANDOM _JITTER ;
}
function getFutureDate ( minutes , maxRandomSeconds = 0 ) {
function getFutureDate ( minutes , maxRandomSeconds = 0 ) {
// return date some amount of minutes in future plus random amount of seconds
// return date some amount of minutes in future plus random amount of seconds
let futureDate = new Date ( ) ;
let futureDate = new Date ( ) ;
futureDate . setMinute s ( futureDate . getMinute s ( ) + minutes ) ;
futureDate . setSecond s ( futureDate . getSecond s ( ) + minutes * MINUTE + getRandomInt ( maxRandomSeconds ) ) ;
futureDate . setSeconds ( futureDate . getSeconds ( ) + getRandomInt ( maxRandomSeconds ) ) ;
return futureDate . toISOString ( ) ;
return futureDate . toISOString ( ) ;
}
}
@@ -86,7 +91,7 @@ function getPathnameParts(pathname) {
let pathParts = pathname . split ( '/' ) ;
let pathParts = pathname . split ( '/' ) ;
let locale = pathParts [ 1 ] || 'en-us' ;
let locale = pathParts [ 1 ] || 'en-us' ;
let visaType = pathParts [ 2 ] || 'niv' ;
let visaType = pathParts [ 2 ] || 'niv' ;
return { locale , visaType } ;
return [ locale , visaType ] ;
}
}
function isSignInPage ( ) {
function isSignInPage ( ) {
@@ -124,10 +129,8 @@ async function handleHttpError(e) {
console . log ( msg ) ;
console . log ( msg ) ;
await sendNotification ( msg ) ;
await sendNotification ( msg ) ;
await logOut ( ) ;
await logOut ( ) ;
return null ;
} else {
} else {
console . error ( e ) ;
console . error ( e ) ;
return null ;
}
}
}
}
@@ -195,7 +198,7 @@ async function getConsulates() {
"isSelected" : option . selected ,
"isSelected" : option . selected ,
"bestDate" : null ,
"bestDate" : null ,
"currentDate" : null ,
"currentDate" : null ,
"nextCheckAt" : getFutureDate ( 0 , config . frequency * MINUTE ) ,
"nextCheckAt" : getFutureDate ( 0 , getJitter ( config. frequency ) ) ,
"autobook" : false ,
"autobook" : false ,
} ;
} ;
}
}
@@ -203,15 +206,27 @@ async function getConsulates() {
}
}
async function getAvailableDates ( consulateId ) {
async function getAvailableDates ( consulateId ) {
let u ri = window . location . pathname + ` /day s/ ${ consulateId } .json?appointments[expedite]=false `
let addressU ri = window . location . pathname + ` /addres s/ ${ consulateId } `
let dates = fetch ( u ri, { headers : { "x-requested-with" : "XMLHttpRequest" } } )
fetch ( addressU ri, { headers : { "x-requested-with" : "XMLHttpRequest" } } )
. catch ( error => console . error ( 'Error:' , error ) ) ;
let datesUri = window . location . pathname + ` /days/ ${ consulateId } .json?appointments[expedite]=false `
let dates = fetch ( datesUri , { headers : {
"x-requested-with" : "XMLHttpRequest" ,
"accept" : "application/json, text/javascript, */*; q=0.01" ,
// "cache-control": "no-cache",
} } )
. then ( d => d . json ( ) )
. then ( d => d . json ( ) )
. catch ( async e => {
await handleHttpError ( e ) ;
throw e ;
} )
. then ( data => {
. then ( data => {
let dateList = data . map ( item => item . date ) ;
let dateList = data . map ( item => item . date ) ;
dateList . sort ( ) ;
dateList . sort ( ) ;
return dateList ;
return dateList ;
} )
} )
. catch ( async e => handleHttpError ( e ) ) ;
. catch ( e => null ) ;
return dates ;
return dates ;
}
}
@@ -229,8 +244,12 @@ async function getAvailableTimes(consulateId, date) {
let uri = window . location . pathname + ` /times/ ${ consulateId } .json?date= ${ date } &appointments[expedite]=false `
let uri = window . location . pathname + ` /times/ ${ consulateId } .json?date= ${ date } &appointments[expedite]=false `
let times = await fetch ( uri , { headers : { "x-requested-with" : "XMLHttpRequest" } } )
let times = await fetch ( uri , { headers : { "x-requested-with" : "XMLHttpRequest" } } )
. then ( d => d . json ( ) )
. then ( d => d . json ( ) )
. catch ( async e => {
await handleHttpError ( e ) ;
throw e ;
} )
. then ( data => data . available _times )
. then ( data => data . available _times )
. catch ( e => handleHttpError ( e ) ) ;
. catch ( e => null ) ;
return times ;
return times ;
}
}
@@ -247,7 +266,7 @@ async function runner() {
config . activate = result [ '__activate' ] || false ;
config . activate = result [ '__activate' ] || false ;
config . username = result [ '__username' ] || "" ;
config . username = result [ '__username' ] || "" ;
config . password = result [ '__password' ] || "" ;
config . password = result [ '__password' ] || "" ;
config . frequency = parseIn t ( result [ '__frequency' ] || 1 ) ;
config . frequency = parseFloa t ( result [ '__frequency' ] || 1 ) ;
config . signinAttempts = result [ '__signinAttempts' ] || 0 ;
config . signinAttempts = result [ '__signinAttempts' ] || 0 ;
config . apptId = result [ '__apptId' ] || null ;
config . apptId = result [ '__apptId' ] || null ;
config . currentAppt = result [ '__currentAppt' ] || { consulate : null , date : null } ;
config . currentAppt = result [ '__currentAppt' ] || { consulate : null , date : null } ;
@@ -278,7 +297,7 @@ async function runner() {
if ( key === 'frequency' ) {
if ( key === 'frequency' ) {
let wasChanged = false ;
let wasChanged = false ;
for ( let consulate in config . consulates ) {
for ( let consulate in config . consulates ) {
let newNextCheckAt = getFutureDate ( config . frequency , 10 ) ;
let newNextCheckAt = getFutureDate ( config . frequency , getJitter ( config . frequency ) ) ;
if ( config . consulates [ consulate ] . nextCheckAt > newNextCheckAt ) {
if ( config . consulates [ consulate ] . nextCheckAt > newNextCheckAt ) {
config . consulates [ consulate ] . nextCheckAt = newNextCheckAt ;
config . consulates [ consulate ] . nextCheckAt = newNextCheckAt ;
wasChanged = true ;
wasChanged = true ;
@@ -334,6 +353,7 @@ async function runner() {
if ( currentHourUTC >= 23 || currentHourUTC < 9 ) {
if ( currentHourUTC >= 23 || currentHourUTC < 9 ) {
// Continue running the code
// Continue running the code
} else {
} else {
await chrome . storage . local . set ( { "__status" : "not operational hours" } ) ;
isRunning = false ;
isRunning = false ;
return ;
return ;
}
}
@@ -507,7 +527,7 @@ async function runner() {
console . log ( msg ) ;
console . log ( msg ) ;
await chrome . storage . local . set ( { "__status" : msg } ) ;
await chrome . storage . local . set ( { "__status" : msg } ) ;
let availDates = await getAvailableDates ( config . consulates [ consulate ] . id ) ;
let availDates = await getAvailableDates ( config . consulates [ consulate ] . id ) ;
config . consulates [ consulate ] . nextCheckAt = getFutureDate ( config . frequency , 10 ) ;
config . consulates [ consulate ] . nextCheckAt = getFutureDate ( config . frequency , getJitter ( config . frequency ) ) ;
if ( ! availDates ) {
if ( ! availDates ) {
msg = ` Failed to fetch available dates in ${ consulate } ` ;
msg = ` Failed to fetch available dates in ${ consulate } ` ;
@@ -529,7 +549,7 @@ async function runner() {
// Only set SOFT_BAN_TIMEOUT if it's not the first 5 minutes of 23pm UTC
// Only set SOFT_BAN_TIMEOUT if it's not the first 5 minutes of 23pm UTC
if ( ! ( currentHourUTC === 23 && currentMinuteUTC < 5 ) ) {
if ( ! ( currentHourUTC === 23 && currentMinuteUTC < 5 ) ) {
config . consulates [ consulate ] . nextCheckAt = getFutureDate ( SOFT _BAN _TIMEOUT , 10 ) ;
config . consulates [ consulate ] . nextCheckAt = getFutureDate ( SOFT _BAN _TIMEOUT , getJitter ( config . frequency ) ) ;
}
}
continue ;
continue ;