mirror of
https://github.com/sasjs/adapter.git
synced 2025-12-11 09:24:35 +00:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ffd6bc5a5c | ||
|
|
c2e64d9ba6 | ||
|
|
a90f699abd | ||
|
|
2cca192f88 | ||
|
|
053b07769a | ||
|
|
4c4511913c | ||
|
|
8c64c24f3c | ||
|
|
1f2f445002 | ||
|
|
6afa056a86 | ||
|
|
fe47ca1152 | ||
|
|
10da691f0f | ||
|
|
318f9694cb | ||
|
|
56e6131e5c |
5
.github/workflows/build.yml
vendored
5
.github/workflows/build.yml
vendored
@@ -22,8 +22,9 @@ jobs:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: npm
|
||||
|
||||
- name: Check npm audit
|
||||
run: npm audit --production --audit-level=low
|
||||
# FIXME: uncomment 'Check npm audit' step after axios version bump
|
||||
# - name: Check npm audit
|
||||
# run: npm audit --production --audit-level=low
|
||||
|
||||
- name: Install Dependencies
|
||||
run: npm ci
|
||||
|
||||
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"cSpell.words": ["SASVIYA"]
|
||||
}
|
||||
@@ -43,10 +43,10 @@ module.exports = {
|
||||
// An object that configures minimum threshold enforcement for coverage results
|
||||
coverageThreshold: {
|
||||
global: {
|
||||
statements: 64.01,
|
||||
statements: 64.03,
|
||||
branches: 45.11,
|
||||
functions: 54.1,
|
||||
lines: 64.51
|
||||
functions: 54.18,
|
||||
lines: 64.53
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -223,7 +223,7 @@ const needsRetry = (state: string) =>
|
||||
* @param authConfig - an access token, refresh token, client and secret for an authorized user.
|
||||
* @param streamLog - indicates if job log should be streamed.
|
||||
* @param logStream - job log stream.
|
||||
* @param jobSessionManager - job session object containing session object and an instance of Session Manager. Job session object is used to periodically (every 10th job state poll) check parent session state.
|
||||
* @param jobSessionManager - job session object containing session object and an instance of Session Manager. Job session object is used to periodically (every 10th job state poll) check parent session state. Session state is considered healthy if it is equal to 'running' or 'idle'.
|
||||
* @returns - a promise which resolves with a job state
|
||||
*/
|
||||
export const doPoll = async (
|
||||
@@ -263,15 +263,20 @@ export const doPoll = async (
|
||||
throw new JobStatePollError(jobId, err)
|
||||
})
|
||||
|
||||
// Checks if session state is equal to 'running' or 'idle'.
|
||||
const isSessionStatesHealthy = (state: string) =>
|
||||
[SessionState.Running, SessionState.Idle].includes(
|
||||
state as SessionState
|
||||
)
|
||||
|
||||
// Clear parent session and throw an error if session state is not
|
||||
// 'running' or response status is not 200.
|
||||
if (sessionState !== SessionState.Running || responseStatus !== 200) {
|
||||
// 'running', 'idle' or response status is not 200.
|
||||
if (!isSessionStatesHealthy(sessionState) || responseStatus !== 200) {
|
||||
sessionManager.clearSession(sessionId, access_token)
|
||||
|
||||
const sessionError =
|
||||
sessionState !== SessionState.Running
|
||||
? `Session state of the job is not 'running'. Session state is '${sessionState}'`
|
||||
: `Session response status is not 200. Session response status is ${responseStatus}.`
|
||||
const sessionError = isSessionStatesHealthy(sessionState)
|
||||
? `Session response status is not 200. Session response status is ${responseStatus}.`
|
||||
: `Session state of the job is not 'running' or 'idle'. Session state is '${sessionState}'`
|
||||
|
||||
throw new JobStatePollError(jobId, new Error(sessionError))
|
||||
}
|
||||
|
||||
@@ -465,7 +465,7 @@ describe('doPoll', () => {
|
||||
.spyOn(sessionManager as any, 'getSessionState')
|
||||
.mockImplementation(() => {
|
||||
return Promise.resolve({
|
||||
result: SessionState.Running,
|
||||
result: SessionState.Idle,
|
||||
responseStatus: 200
|
||||
})
|
||||
})
|
||||
@@ -533,9 +533,9 @@ describe('doPoll', () => {
|
||||
)
|
||||
})
|
||||
|
||||
it('should throw an error if session is not in running state', async () => {
|
||||
it('should throw an error if session state is not healthy', async () => {
|
||||
const filteredSessionStates = Object.values(SessionState).filter(
|
||||
(state) => state !== SessionState.Running
|
||||
(state) => state !== SessionState.Running && state !== SessionState.Idle
|
||||
)
|
||||
const randomSessionState =
|
||||
filteredSessionStates[
|
||||
@@ -580,7 +580,7 @@ describe('doPoll', () => {
|
||||
new JobStatePollError(
|
||||
mockJob.id,
|
||||
new Error(
|
||||
`Session state of the job is not 'running'. Session state is '${randomSessionState}'`
|
||||
`Session state of the job is not 'running' or 'idle'. Session state is '${randomSessionState}'`
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -7,6 +7,7 @@ import { extractUserLongNameSas9 } from '../utils/sas9/extractUserLongNameSas9'
|
||||
import { openWebPage } from './openWebPage'
|
||||
import { verifySas9Login } from './verifySas9Login'
|
||||
import { verifySasViyaLogin } from './verifySasViyaLogin'
|
||||
import { isLogInSuccessHeaderPresent } from './'
|
||||
|
||||
export class AuthManager {
|
||||
public userName = ''
|
||||
@@ -14,6 +15,7 @@ export class AuthManager {
|
||||
private loginUrl: string
|
||||
private logoutUrl: string
|
||||
private redirectedLoginUrl = `/SASLogon` //SAS 9 M8 no longer redirects from `/SASLogon/home` to the login page. `/SASLogon` seems to be stable enough across SAS versions
|
||||
|
||||
constructor(
|
||||
private serverUrl: string,
|
||||
private serverType: ServerType,
|
||||
@@ -27,6 +29,8 @@ export class AuthManager {
|
||||
: this.serverType === ServerType.SasViya
|
||||
? '/SASLogon/logout.do?'
|
||||
: '/SASLogon/logout'
|
||||
|
||||
this.redirectedLoginUrl = this.serverUrl + this.redirectedLoginUrl
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -129,7 +133,7 @@ export class AuthManager {
|
||||
|
||||
let loginResponse = await this.sendLoginRequest(loginForm, loginParams)
|
||||
|
||||
let isLoggedIn = isLogInSuccess(this.serverType, loginResponse)
|
||||
let isLoggedIn = isLogInSuccessHeaderPresent(this.serverType, loginResponse)
|
||||
|
||||
if (!isLoggedIn) {
|
||||
if (isCredentialsVerifyError(loginResponse)) {
|
||||
@@ -214,7 +218,7 @@ export class AuthManager {
|
||||
* - a boolean `isLoggedIn`
|
||||
* - a string `userName`,
|
||||
* - a string `userFullName` and
|
||||
* - a form `loginForm` if not loggedin.
|
||||
* - a form `loginForm` if not loggedIn.
|
||||
*/
|
||||
public async checkSession(): Promise<LoginResultInternal> {
|
||||
const { isLoggedIn, userName, userLongName } = await this.fetchUserName()
|
||||
@@ -381,9 +385,3 @@ const isCredentialsVerifyError = (response: string): boolean =>
|
||||
/An error occurred while the system was verifying your credentials. Please enter your credentials again./gm.test(
|
||||
response
|
||||
)
|
||||
|
||||
const isLogInSuccess = (serverType: ServerType, response: any): boolean => {
|
||||
if (serverType === ServerType.Sasjs) return response?.loggedin
|
||||
|
||||
return /You have signed in/gm.test(response)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './AuthManager'
|
||||
export * from './isAuthorizeFormRequired'
|
||||
export * from './isLoginRequired'
|
||||
export * from './loginHeader'
|
||||
|
||||
97
src/auth/loginHeader.ts
Normal file
97
src/auth/loginHeader.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
import { ServerType } from '@sasjs/utils/types'
|
||||
import { getUserLanguage } from '../utils'
|
||||
|
||||
const enLoginSuccessHeader = 'You have signed in.'
|
||||
|
||||
export const defaultSuccessHeaderKey = 'default'
|
||||
|
||||
// The following headers provided by https://github.com/sasjs/adapter/issues/835#issuecomment-2177818601
|
||||
export const loginSuccessHeaders: { [key: string]: string } = {
|
||||
es: `Ya se ha iniciado la sesi\u00f3n.`,
|
||||
th: `\u0e04\u0e38\u0e13\u0e25\u0e07\u0e0a\u0e37\u0e48\u0e2d\u0e40\u0e02\u0e49\u0e32\u0e43\u0e0a\u0e49\u0e41\u0e25\u0e49\u0e27`,
|
||||
ja: `\u30b5\u30a4\u30f3\u30a4\u30f3\u3057\u307e\u3057\u305f\u3002`,
|
||||
nb: `Du har logget deg p\u00e5.`,
|
||||
sl: `Prijavili ste se.`,
|
||||
ar: `\u0644\u0642\u062f \u0642\u0645\u062a `,
|
||||
sk: `Prihl\u00e1sili ste sa.`,
|
||||
zh_HK: `\u60a8\u5df2\u767b\u5165\u3002`,
|
||||
zh_CN: `\u60a8\u5df2\u767b\u5f55\u3002`,
|
||||
it: `L'utente si \u00e8 connesso.`,
|
||||
sv: `Du har loggat in.`,
|
||||
he: `\u05e0\u05db\u05e0\u05e1\u05ea `,
|
||||
nl: `U hebt zich aangemeld.`,
|
||||
pl: `Zosta\u0142e\u015b zalogowany.`,
|
||||
ko: `\ub85c\uadf8\uc778\ud588\uc2b5\ub2c8\ub2e4.`,
|
||||
zh_TW: `\u60a8\u5df2\u767b\u5165\u3002`,
|
||||
tr: `Oturum a\u00e7t\u0131n\u0131z.`,
|
||||
iw: `\u05e0\u05db\u05e0\u05e1\u05ea `,
|
||||
fr: `Vous \u00eates connect\u00e9.`,
|
||||
uk: `\u0412\u0438 \u0432\u0432\u0456\u0439\u0448\u043b\u0438 \u0432 \u043e\u0431\u043b\u0456\u043a\u043e\u0432\u0438\u0439 \u0437\u0430\u043f\u0438\u0441.`,
|
||||
pt_BR: `Voc\u00ea se conectou.`,
|
||||
no: `Du har logget deg p\u00e5.`,
|
||||
cs: `Jste p\u0159ihl\u00e1\u0161eni.`,
|
||||
fi: `Olet kirjautunut sis\u00e4\u00e4n.`,
|
||||
ru: `\u0412\u044b \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043b\u0438 \u0432\u0445\u043e\u0434 \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0443.`,
|
||||
el: `\u0388\u03c7\u03b5\u03c4\u03b5 \u03c3\u03c5\u03bd\u03b4\u03b5\u03b8\u03b5\u03af.`,
|
||||
hr: `Prijavili ste se.`,
|
||||
da: `Du er logget p\u00e5.`,
|
||||
de: `Sie sind jetzt angemeldet.`,
|
||||
sh: `Prijavljeni ste.`,
|
||||
pt: `Iniciou sess\u00e3o.`,
|
||||
hu: `Bejelentkezett.`,
|
||||
sr: `Prijavljeni ste.`,
|
||||
en: enLoginSuccessHeader,
|
||||
[defaultSuccessHeaderKey]: enLoginSuccessHeader
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides expected login header based on language settings of the browser.
|
||||
* @returns - expected header as a string.
|
||||
*/
|
||||
export const getExpectedLogInSuccessHeader = (): string => {
|
||||
// get default success header
|
||||
let successHeader = loginSuccessHeaders[defaultSuccessHeaderKey]
|
||||
|
||||
// get user language based on language settings of the browser
|
||||
const userLang = getUserLanguage()
|
||||
|
||||
if (userLang) {
|
||||
// get success header on exact match of the language code
|
||||
let userLangSuccessHeader = loginSuccessHeaders[userLang]
|
||||
|
||||
// handle case when there is no exact match of the language code
|
||||
if (!userLangSuccessHeader) {
|
||||
// get all supported language codes
|
||||
const headerLanguages = Object.keys(loginSuccessHeaders)
|
||||
|
||||
// find language code on partial match
|
||||
const headerLanguage = headerLanguages.find((language) =>
|
||||
new RegExp(language, 'i').test(userLang)
|
||||
)
|
||||
|
||||
// reassign success header if partial match was found
|
||||
if (headerLanguage) {
|
||||
successHeader = loginSuccessHeaders[headerLanguage]
|
||||
}
|
||||
} else {
|
||||
successHeader = userLangSuccessHeader
|
||||
}
|
||||
}
|
||||
|
||||
return successHeader
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if Login success header is present in the response based on language settings of the browser.
|
||||
* @param serverType - server type.
|
||||
* @param response - response object.
|
||||
* @returns - boolean indicating if Login success header is present.
|
||||
*/
|
||||
export const isLogInSuccessHeaderPresent = (
|
||||
serverType: ServerType,
|
||||
response: any
|
||||
): boolean => {
|
||||
if (serverType === ServerType.Sasjs) return response?.loggedIn
|
||||
|
||||
return new RegExp(getExpectedLogInSuccessHeader(), 'gm').test(response)
|
||||
}
|
||||
@@ -1,17 +1,22 @@
|
||||
/**
|
||||
* @jest-environment jsdom
|
||||
*/
|
||||
|
||||
import { AuthManager } from '../AuthManager'
|
||||
import * as dotenv from 'dotenv'
|
||||
import { ServerType } from '@sasjs/utils/types'
|
||||
import axios from 'axios'
|
||||
import {
|
||||
mockedCurrentUserApi,
|
||||
mockLoginAuthoriseRequiredResponse,
|
||||
mockLoginSuccessResponse
|
||||
mockLoginAuthoriseRequiredResponse
|
||||
} from './mockResponses'
|
||||
import { serialize } from '../../utils'
|
||||
import * as openWebPageModule from '../openWebPage'
|
||||
import * as verifySasViyaLoginModule from '../verifySasViyaLogin'
|
||||
import * as verifySas9LoginModule from '../verifySas9Login'
|
||||
import { RequestClient } from '../../request/RequestClient'
|
||||
import { getExpectedLogInSuccessHeader } from '../'
|
||||
|
||||
jest.mock('axios')
|
||||
const mockedAxios = axios as jest.Mocked<typeof axios>
|
||||
|
||||
@@ -125,6 +130,7 @@ describe('AuthManager', () => {
|
||||
requestClient,
|
||||
authCallback
|
||||
)
|
||||
|
||||
jest.spyOn(authManager, 'checkSession').mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
isLoggedIn: false,
|
||||
@@ -133,8 +139,9 @@ describe('AuthManager', () => {
|
||||
loginForm: { name: 'test' }
|
||||
})
|
||||
)
|
||||
|
||||
mockedAxios.post.mockImplementation(() =>
|
||||
Promise.resolve({ data: mockLoginSuccessResponse })
|
||||
Promise.resolve({ data: getExpectedLogInSuccessHeader() })
|
||||
)
|
||||
|
||||
const loginResponse = await authManager.logIn(userName, password)
|
||||
@@ -170,6 +177,7 @@ describe('AuthManager', () => {
|
||||
requestClient,
|
||||
authCallback
|
||||
)
|
||||
|
||||
jest.spyOn(authManager, 'checkSession').mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
isLoggedIn: false,
|
||||
@@ -178,8 +186,9 @@ describe('AuthManager', () => {
|
||||
loginForm: { name: 'test' }
|
||||
})
|
||||
)
|
||||
|
||||
mockedAxios.post.mockImplementation(() =>
|
||||
Promise.resolve({ data: mockLoginSuccessResponse })
|
||||
Promise.resolve({ data: getExpectedLogInSuccessHeader() })
|
||||
)
|
||||
mockedAxios.get.mockImplementation(() => Promise.resolve({ status: 200 }))
|
||||
|
||||
@@ -365,7 +374,7 @@ describe('AuthManager', () => {
|
||||
expect(loginResponse.userName).toEqual(userName)
|
||||
|
||||
expect(openWebPageModule.openWebPage).toHaveBeenCalledWith(
|
||||
`/SASLogon`,
|
||||
`${serverUrl}/SASLogon`,
|
||||
'SASLogon',
|
||||
{
|
||||
width: 500,
|
||||
@@ -409,7 +418,7 @@ describe('AuthManager', () => {
|
||||
expect(loginResponse.userName).toEqual(userName)
|
||||
|
||||
expect(openWebPageModule.openWebPage).toHaveBeenCalledWith(
|
||||
`/SASLogon`,
|
||||
`${serverUrl}/SASLogon`,
|
||||
'SASLogon',
|
||||
{
|
||||
width: 500,
|
||||
@@ -453,7 +462,7 @@ describe('AuthManager', () => {
|
||||
expect(loginResponse.userName).toEqual('')
|
||||
|
||||
expect(openWebPageModule.openWebPage).toHaveBeenCalledWith(
|
||||
`/SASLogon`,
|
||||
`${serverUrl}/SASLogon`,
|
||||
'SASLogon',
|
||||
{
|
||||
width: 500,
|
||||
@@ -497,7 +506,7 @@ describe('AuthManager', () => {
|
||||
expect(loginResponse.userName).toEqual('')
|
||||
|
||||
expect(openWebPageModule.openWebPage).toHaveBeenCalledWith(
|
||||
`/SASLogon`,
|
||||
`${serverUrl}/SASLogon`,
|
||||
'SASLogon',
|
||||
{
|
||||
width: 500,
|
||||
|
||||
82
src/auth/spec/loginHeader.spec.ts
Normal file
82
src/auth/spec/loginHeader.spec.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* @jest-environment jsdom
|
||||
*/
|
||||
|
||||
import { ServerType } from '@sasjs/utils/types'
|
||||
import {
|
||||
loginSuccessHeaders,
|
||||
isLogInSuccessHeaderPresent,
|
||||
defaultSuccessHeaderKey
|
||||
} from '../'
|
||||
|
||||
describe('isLogInSuccessHeaderPresent', () => {
|
||||
let languageGetter: any
|
||||
|
||||
beforeEach(() => {
|
||||
languageGetter = jest.spyOn(window.navigator, 'language', 'get')
|
||||
})
|
||||
|
||||
it('should check SASVIYA and SAS9 login success header based on language preferences of the browser', () => {
|
||||
// test SASVIYA server type
|
||||
Object.keys(loginSuccessHeaders).forEach((key) => {
|
||||
languageGetter.mockReturnValue(key)
|
||||
|
||||
expect(
|
||||
isLogInSuccessHeaderPresent(
|
||||
ServerType.SasViya,
|
||||
loginSuccessHeaders[key]
|
||||
)
|
||||
).toBeTruthy()
|
||||
})
|
||||
|
||||
// test SAS9 server type
|
||||
Object.keys(loginSuccessHeaders).forEach((key) => {
|
||||
languageGetter.mockReturnValue(key)
|
||||
|
||||
expect(
|
||||
isLogInSuccessHeaderPresent(ServerType.Sas9, loginSuccessHeaders[key])
|
||||
).toBeTruthy()
|
||||
})
|
||||
|
||||
// test possible longer language codes
|
||||
const possibleLanguageCodes = [
|
||||
{ short: 'en', long: 'en-US' },
|
||||
{ short: 'fr', long: 'fr-FR' },
|
||||
{ short: 'es', long: 'es-ES' }
|
||||
]
|
||||
|
||||
possibleLanguageCodes.forEach((key) => {
|
||||
const { short, long } = key
|
||||
languageGetter.mockReturnValue(long)
|
||||
|
||||
expect(
|
||||
isLogInSuccessHeaderPresent(
|
||||
ServerType.SasViya,
|
||||
loginSuccessHeaders[short]
|
||||
)
|
||||
).toBeTruthy()
|
||||
})
|
||||
|
||||
// test falling back to default language code
|
||||
languageGetter.mockReturnValue('WRONG-LANGUAGE')
|
||||
|
||||
expect(
|
||||
isLogInSuccessHeaderPresent(
|
||||
ServerType.Sas9,
|
||||
loginSuccessHeaders[defaultSuccessHeaderKey]
|
||||
)
|
||||
).toBeTruthy()
|
||||
})
|
||||
|
||||
it('should check SASVJS login success header', () => {
|
||||
expect(
|
||||
isLogInSuccessHeaderPresent(ServerType.Sasjs, { loggedIn: true })
|
||||
).toBeTruthy()
|
||||
|
||||
expect(
|
||||
isLogInSuccessHeaderPresent(ServerType.Sasjs, { loggedIn: false })
|
||||
).toBeFalsy()
|
||||
|
||||
expect(isLogInSuccessHeaderPresent(ServerType.Sasjs, undefined)).toBeFalsy()
|
||||
})
|
||||
})
|
||||
@@ -1,7 +1,6 @@
|
||||
import { SasAuthResponse } from '@sasjs/utils/types'
|
||||
|
||||
export const mockLoginAuthoriseRequiredResponse = `<form id="application_authorization" action="/SASLogon/oauth/authorize" method="POST"><input type="hidden" name="X-Uaa-Csrf" value="2nfuxIn6WaOURWL7tzTXCe"/>`
|
||||
export const mockLoginSuccessResponse = `You have signed in`
|
||||
|
||||
export const mockAuthResponse: SasAuthResponse = {
|
||||
access_token: 'acc355',
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*/
|
||||
import { verifySas9Login } from '../verifySas9Login'
|
||||
import * as delayModule from '../../utils/delay'
|
||||
import { getExpectedLogInSuccessHeader } from '../'
|
||||
|
||||
describe('verifySas9Login', () => {
|
||||
const serverUrl = 'http://test-server.com'
|
||||
@@ -18,7 +19,9 @@ describe('verifySas9Login', () => {
|
||||
const popup = {
|
||||
window: {
|
||||
location: { href: serverUrl + `/SASLogon` },
|
||||
document: { body: { innerText: '<h3>You have signed in.</h3>' } }
|
||||
document: {
|
||||
body: { innerText: `<h3>${getExpectedLogInSuccessHeader()}</h3>` }
|
||||
}
|
||||
}
|
||||
} as unknown as Window
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*/
|
||||
import { verifySasViyaLogin } from '../verifySasViyaLogin'
|
||||
import * as delayModule from '../../utils/delay'
|
||||
import { getExpectedLogInSuccessHeader } from '../'
|
||||
|
||||
describe('verifySasViyaLogin', () => {
|
||||
const serverUrl = 'http://test-server.com'
|
||||
@@ -19,7 +20,9 @@ describe('verifySasViyaLogin', () => {
|
||||
const popup = {
|
||||
window: {
|
||||
location: { href: serverUrl + `/SASLogon` },
|
||||
document: { body: { innerText: '<h3>You have signed in.</h3>' } }
|
||||
document: {
|
||||
body: { innerText: `<h3>${getExpectedLogInSuccessHeader()}</h3>` }
|
||||
}
|
||||
}
|
||||
} as unknown as Window
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { delay } from '../utils'
|
||||
import { getExpectedLogInSuccessHeader } from './'
|
||||
|
||||
export async function verifySas9Login(loginPopup: Window): Promise<{
|
||||
isLoggedIn: boolean
|
||||
@@ -6,13 +7,17 @@ export async function verifySas9Login(loginPopup: Window): Promise<{
|
||||
let isLoggedIn = false
|
||||
let startTime = new Date()
|
||||
let elapsedSeconds = 0
|
||||
|
||||
do {
|
||||
await delay(1000)
|
||||
if (loginPopup.closed) break
|
||||
|
||||
isLoggedIn =
|
||||
loginPopup.window.location.href.includes('SASLogon') &&
|
||||
loginPopup.window.document.body.innerText.includes('You have signed in.')
|
||||
loginPopup.window.document.body.innerText.includes(
|
||||
getExpectedLogInSuccessHeader()
|
||||
)
|
||||
|
||||
elapsedSeconds = (new Date().valueOf() - startTime.valueOf()) / 1000
|
||||
} while (!isLoggedIn && elapsedSeconds < 5 * 60)
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { delay } from '../utils'
|
||||
import { getExpectedLogInSuccessHeader } from './'
|
||||
|
||||
export async function verifySasViyaLogin(loginPopup: Window): Promise<{
|
||||
isLoggedIn: boolean
|
||||
@@ -6,23 +7,32 @@ export async function verifySasViyaLogin(loginPopup: Window): Promise<{
|
||||
let isLoggedIn = false
|
||||
let startTime = new Date()
|
||||
let elapsedSeconds = 0
|
||||
|
||||
do {
|
||||
await delay(1000)
|
||||
|
||||
if (loginPopup.closed) break
|
||||
|
||||
isLoggedIn = isLoggedInSASVIYA()
|
||||
|
||||
elapsedSeconds = (new Date().valueOf() - startTime.valueOf()) / 1000
|
||||
} while (!isLoggedIn && elapsedSeconds < 5 * 60)
|
||||
|
||||
let isAuthorized = false
|
||||
|
||||
startTime = new Date()
|
||||
|
||||
do {
|
||||
await delay(1000)
|
||||
|
||||
if (loginPopup.closed) break
|
||||
|
||||
isAuthorized =
|
||||
loginPopup.window.location.href.includes('SASLogon') ||
|
||||
loginPopup.window.document.body?.innerText?.includes(
|
||||
'You have signed in.'
|
||||
getExpectedLogInSuccessHeader()
|
||||
)
|
||||
|
||||
elapsedSeconds = (new Date().valueOf() - startTime.valueOf()) / 1000
|
||||
} while (!isAuthorized && elapsedSeconds < 5 * 60)
|
||||
|
||||
|
||||
10
src/utils/getUserLanguage.ts
Normal file
10
src/utils/getUserLanguage.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
interface IEnavigator {
|
||||
userLanguage?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides preferred language of the user.
|
||||
* @returns A string representing the preferred language of the user, usually the language of the browser UI. Examples of valid language codes include "en", "en-US", "fr", "fr-FR", "es-ES". More info available https://datatracker.ietf.org/doc/html/rfc5646
|
||||
*/
|
||||
export const getUserLanguage = () =>
|
||||
window.navigator.language || (window.navigator as IEnavigator).userLanguage
|
||||
@@ -20,3 +20,4 @@ export * from './serialize'
|
||||
export * from './splitChunks'
|
||||
export * from './validateInput'
|
||||
export * from './getFormData'
|
||||
export * from './getUserLanguage'
|
||||
|
||||
Reference in New Issue
Block a user