Skip to content
This repository has been archived by the owner on Dec 1, 2023. It is now read-only.

Commit

Permalink
fix: bot cannot login with latest SMS authentication flow
Browse files Browse the repository at this point in the history
Closes #64
  • Loading branch information
wdzeng committed Jul 21, 2023
1 parent 5e69946 commit f2ac9b1
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 17 deletions.
1 change: 1 addition & 0 deletions src/exit-code.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export enum ExitCode {
OPERATION_TIMEOUT_EXCEEDED = 4,
LOGIN_DENIED = 6,
NEED_EMAIL_AUTH = 7,
SHOPEE_ERROR = 10,
TOO_MUCH_TRY = 69,
INVALID_OPTIONS = 77,
WRONG_PASSWORD = 87,
Expand Down
4 changes: 3 additions & 1 deletion src/text.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ export const PLAY_PUZZLE = '點擊以重新載入頁面'
export const RECEIVE_COIN = '完成簽到'
export const SHOPEE_REWARD = '蝦幣獎勵'
export const TOO_MUCH_TRY = '您已達到今日驗證次數上限。'
export const USE_LINK = '使用連結驗證'
export const USE_SMS = '使用簡訊驗證'
export const SMS_SENT = '您的驗證碼已透過簡訊傳送至'
export const USE_EMAIL_LINK = '透過電子郵件連結驗證'
export const WRONG_PASSWORDS = [
'你的帳號或密碼不正確,請再試一次',
'登入失敗,請稍後再試或使用其他登入方法',
'您輸入的帳號或密碼不正確,若遇到困難,請重設您的密碼。'
]
export const ERROR_TRY_AGAIN = '發生錯誤,請再試一次。'
73 changes: 57 additions & 16 deletions src/tw-shopee-bot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export default class TaiwanShopeeBot {
const xpath = [
...Text.WRONG_PASSWORDS.map((e) => xpathByText('div', e)),
xpathByText('button', Text.PLAY_PUZZLE),
xpathByText('div', Text.USE_LINK),
xpathByText('div', Text.USE_SMS),
xpathByText('div', Text.TOO_MUCH_TRY),
xpathByText('div', Text.SHOPEE_REWARD),
xpathByText('div', Text.USE_EMAIL_LINK)
Expand All @@ -110,7 +110,7 @@ export default class TaiwanShopeeBot {
logger.error('Login failed: I cannot solve the puzzle.')
return ExitCode.CANNOT_SOLVE_PUZZLE
}
if (text === Text.USE_LINK) {
if (text === Text.USE_SMS) {
// Need to authenticate via SMS link.
logger.warn('Login failed: please login via SMS.')
return ExitCode.NEED_SMS_AUTH
Expand Down Expand Up @@ -195,29 +195,70 @@ export default class TaiwanShopeeBot {
}

private async tryLoginWithSmsLink(): Promise<number | undefined> {
// Wait until the '使用連結驗證' button is available.
// Wait until the '使用簡訊驗證' button is available.
await this.driver.wait(
until.elementLocated(By.xpath(xpathByText('div', Text.USE_LINK))),
until.elementLocated(By.xpath(xpathByText('div', Text.USE_SMS))),
TIMEOUT_OPERATION
)

// Click the '使用連結驗證' button.
// Click the '使用簡訊驗證' button.
const btnLoginWithLink = await this.driver.findElement(
By.xpath(xpathByText('div', Text.USE_LINK))
By.xpath(xpathByText('div', Text.USE_SMS))
)
await btnLoginWithLink.click()
logger.debug('Clicked "使用簡訊驗證" button. Waiting for redirect.')

// Wait until the page is redirect. Set timeout to be 8 seconds.
await this.driver.wait(until.urlContains('https://shopee.tw/verify/otp'), 8000)

const validatePageLoaded = async (timeout: number) => {
const start = Date.now()

while (Date.now() < start + timeout) {
// Check if reaching daily limits.
const reachLimit = await this.driver.findElements(
By.xpath(xpathByText('div', Text.TOO_MUCH_TRY))
)
if (reachLimit.length > 0) {
// Failed because reach limits.
logger.error('Cannot use SMS link to login: reach daily limits.')
return ExitCode.TOO_MUCH_TRY
}

// Wait until the page is redirect.
await this.driver.wait(until.urlIs('https://shopee.tw/verify/link'))
// Check if puzzle quiz is required.
const requirePuzzleQuiz = await this.driver.findElements(
By.xpath(xpathByText('button', Text.PLAY_PUZZLE))
)
if (requirePuzzleQuiz.length > 0) {
logger.error('Login failed: I cannot solve the puzzle.')
return ExitCode.CANNOT_SOLVE_PUZZLE
}

// Check if reaching daily limits.
const reachLimit = await this.driver.findElements(
By.xpath(xpathByText('div', Text.TOO_MUCH_TRY))
)
if (reachLimit.length > 0) {
// Failed because reach limits.
logger.error('Cannot use SMS link to login: reach daily limits.')
return ExitCode.TOO_MUCH_TRY
// Check if Shopee website reports any error.
const errorTryAgain = await this.driver.findElements(
By.xpath(xpathByText('div', Text.ERROR_TRY_AGAIN))
)
if (errorTryAgain.length > 0) {
logger.error('Failed to login with SMS authentication.')
return ExitCode.SHOPEE_ERROR
}

// Check if SMS is sent out.
const smsSent = await this.driver.findElements(By.xpath(xpathByText('div', Text.SMS_SENT)))
if (smsSent.length > 0) {
return true
}
}

// Unexpected error.
logger.error('Redirect timeout exceeds.')
return ExitCode.OPERATION_TIMEOUT_EXCEEDED
}

// Wait for page loaded. 10s should be enough.
const result = await validatePageLoaded(10 * 1000)
if (result !== true) {
return result
}

// Now user should click the link sent from Shopee to her mobile via SMS.
Expand Down

0 comments on commit f2ac9b1

Please sign in to comment.