feat: 🎸 Remove all obsolete login obstacles (#146)
This commit is contained in:
parent
7f93285554
commit
befb073a32
|
@ -49,7 +49,7 @@ async function run() {
|
||||||
console.log('user')
|
console.log('user')
|
||||||
const user = await api.getUser()
|
const user = await api.getUser()
|
||||||
console.log(user)
|
console.log(user)
|
||||||
/*
|
|
||||||
console.log('children')
|
console.log('children')
|
||||||
const children = await api.getChildren()
|
const children = await api.getChildren()
|
||||||
console.log(children)
|
console.log(children)
|
||||||
|
@ -115,7 +115,7 @@ async function Login(api) {
|
||||||
console.log('Login with old cookie succeeded')
|
console.log('Login with old cookie succeeded')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('Could not login with old session cookie. Reverting to BankId')
|
console.log('Could not login with old session cookie. Reverting to BankId')
|
||||||
console.error(error)
|
// console.error(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (useBankId) {
|
if (useBankId) {
|
||||||
|
|
137
lib/api.ts
137
lib/api.ts
|
@ -3,7 +3,6 @@ import { EventEmitter } from 'events'
|
||||||
import { decode } from 'he'
|
import { decode } from 'he'
|
||||||
import * as html from 'node-html-parser'
|
import * as html from 'node-html-parser'
|
||||||
import { Language } from '@skolplattformen/curriculum/dist/translations'
|
import { Language } from '@skolplattformen/curriculum/dist/translations'
|
||||||
import * as base64 from 'base-64'
|
|
||||||
import { URLSearchParams } from './URLSearchParams'
|
import { URLSearchParams } from './URLSearchParams'
|
||||||
import { checkStatus, LoginStatusChecker } from './loginStatus'
|
import { checkStatus, LoginStatusChecker } from './loginStatus'
|
||||||
import {
|
import {
|
||||||
|
@ -60,8 +59,6 @@ export class Api extends EventEmitter {
|
||||||
|
|
||||||
public isFake: boolean = false
|
public isFake: boolean = false
|
||||||
|
|
||||||
public childControllerUrl?: string
|
|
||||||
|
|
||||||
private authorizedSystems: SSOSystems = {}
|
private authorizedSystems: SSOSystems = {}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
@ -136,7 +133,6 @@ export class Api extends EventEmitter {
|
||||||
status.on('OK', async () => {
|
status.on('OK', async () => {
|
||||||
await this.retrieveSessionCookie()
|
await this.retrieveSessionCookie()
|
||||||
await this.retrieveXsrfToken()
|
await this.retrieveXsrfToken()
|
||||||
// await this.retrieveApiKey()
|
|
||||||
|
|
||||||
this.isLoggedIn = true
|
this.isLoggedIn = true
|
||||||
this.emit('login')
|
this.emit('login')
|
||||||
|
@ -166,7 +162,6 @@ export class Api extends EventEmitter {
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.retrieveXsrfToken()
|
await this.retrieveXsrfToken()
|
||||||
await this.retrieveApiKey()
|
|
||||||
|
|
||||||
this.isLoggedIn = true
|
this.isLoggedIn = true
|
||||||
this.emit('login')
|
this.emit('login')
|
||||||
|
@ -187,110 +182,10 @@ export class Api extends EventEmitter {
|
||||||
doc
|
doc
|
||||||
.querySelector('input[name="__RequestVerificationToken"]')
|
.querySelector('input[name="__RequestVerificationToken"]')
|
||||||
?.getAttribute('value') || ''
|
?.getAttribute('value') || ''
|
||||||
const scriptTags = doc.querySelectorAll('script')
|
|
||||||
const childControllerScriptTag = scriptTags.find((elem) => {
|
|
||||||
const srcAttr = elem.getAttribute('src')
|
|
||||||
return srcAttr?.startsWith('/vardnadshavare/bundles/childcontroller')
|
|
||||||
})
|
|
||||||
this.childControllerUrl =
|
|
||||||
routes.baseEtjanst + childControllerScriptTag?.getAttribute('src')
|
|
||||||
this.addHeader('x-xsrf-token', xsrfToken)
|
this.addHeader('x-xsrf-token', xsrfToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
private async retrieveApiKey(): Promise<void> {
|
|
||||||
const url = routes.childcontrollerScript
|
|
||||||
const session = this.getRequestInit()
|
|
||||||
const response = await this.fetch('startBundle', url, session)
|
|
||||||
const text = await response.text()
|
|
||||||
|
|
||||||
const apiKeyRegex = /"API-Key": "([\w\d]+)"/gm
|
|
||||||
const apiKeyMatches = apiKeyRegex.exec(text)
|
|
||||||
const apiKey =
|
|
||||||
apiKeyMatches && apiKeyMatches.length > 1 ? apiKeyMatches[1] : ''
|
|
||||||
|
|
||||||
this.addHeader('API-Key', apiKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
private async retrieveCdnUrl(): Promise<string> {
|
|
||||||
const url = routes.cdn
|
|
||||||
const session = this.getRequestInit()
|
|
||||||
const response = await this.fetch('cdn', url, session)
|
|
||||||
const cdnUrl = await response.text()
|
|
||||||
return cdnUrl
|
|
||||||
}
|
|
||||||
|
|
||||||
private async retrieveAuthBody(): Promise<string> {
|
|
||||||
const url = routes.auth
|
|
||||||
const session = this.getRequestInit()
|
|
||||||
const response = await this.fetch('auth', url, session)
|
|
||||||
const authBody = await response.text()
|
|
||||||
return authBody
|
|
||||||
}
|
|
||||||
|
|
||||||
private async getTopologyConfig(): Promise<Record<string, any>> {
|
|
||||||
|
|
||||||
const response = await this.fetch('topologyConfigUrl', routes.topologyConfigUrl)
|
|
||||||
|
|
||||||
const json = await response.json()
|
|
||||||
|
|
||||||
return json
|
|
||||||
}
|
|
||||||
|
|
||||||
private async retrieveCreateItemHeaders() {
|
|
||||||
const response = await this.fetch(
|
|
||||||
'createItemConfig',
|
|
||||||
routes.createItemConfig
|
|
||||||
)
|
|
||||||
const json = await response.json()
|
|
||||||
return json
|
|
||||||
}
|
|
||||||
|
|
||||||
private async retrieveAuthToken(
|
|
||||||
url: string,
|
|
||||||
authBody: string
|
|
||||||
): Promise<string> {
|
|
||||||
const session = this.getRequestInit({
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
Accept: 'text/plain',
|
|
||||||
Origin: 'https://etjanst.stockholm.se',
|
|
||||||
Referer: 'https://etjanst.stockholm.se/',
|
|
||||||
Connection: 'keep-alive',
|
|
||||||
},
|
|
||||||
body: authBody,
|
|
||||||
})
|
|
||||||
delete session.headers['API-Key']
|
|
||||||
|
|
||||||
// Temporarily remove cookies
|
|
||||||
const cookies = await this.cookieManager.getCookies(url)
|
|
||||||
this.cookieManager.clearAll()
|
|
||||||
|
|
||||||
// Perform request
|
|
||||||
let scriptUrl = this.childControllerUrl
|
|
||||||
if (!scriptUrl) {
|
|
||||||
scriptUrl = routes.childcontrollerScript
|
|
||||||
}
|
|
||||||
const createItemHeaders = await this.retrieveCreateItemHeaders()
|
|
||||||
const response = await this.fetch('createItem', url, {
|
|
||||||
method: 'POST',
|
|
||||||
...createItemHeaders,
|
|
||||||
body: authBody,
|
|
||||||
})
|
|
||||||
// Restore cookies
|
|
||||||
cookies.forEach((cookie) => {
|
|
||||||
this.cookieManager.setCookie(cookie, url)
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(
|
|
||||||
`Server Error [${response.status}] [${response.statusText}] [${url}]`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const authData = await response.json()
|
|
||||||
return authData.token
|
|
||||||
}
|
|
||||||
|
|
||||||
private async fakeMode(): Promise<LoginStatusChecker> {
|
private async fakeMode(): Promise<LoginStatusChecker> {
|
||||||
this.isFake = true
|
this.isFake = true
|
||||||
|
|
||||||
|
@ -314,43 +209,13 @@ export class Api extends EventEmitter {
|
||||||
return parse.user(data)
|
return parse.user(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getTopology (): Promise<string> {
|
|
||||||
|
|
||||||
const configTopology = await this.getTopologyConfig()
|
|
||||||
|
|
||||||
const currentTime = new Date().getTime() + 600000
|
|
||||||
|
|
||||||
let topo = `${configTopology.topologyLongKey}${currentTime}`
|
|
||||||
|
|
||||||
const secretNumberString = configTopology.topologyShortKey
|
|
||||||
const numberOfBase64Iterations = configTopology.topologyBase64Iterations
|
|
||||||
|
|
||||||
for (let i = 0; i < numberOfBase64Iterations; i += 1) {
|
|
||||||
topo = base64.encode(topo)
|
|
||||||
};
|
|
||||||
|
|
||||||
const part1 = topo.substring(0, 1)
|
|
||||||
const part2 = secretNumberString.charAt(numberOfBase64Iterations)
|
|
||||||
const part3 = topo.substring(1, topo.length)
|
|
||||||
|
|
||||||
const finalTopology = part1 + part2 + part3
|
|
||||||
|
|
||||||
return finalTopology
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getChildren(): Promise<EtjanstChild[]> {
|
public async getChildren(): Promise<EtjanstChild[]> {
|
||||||
if (this.isFake) return fakeResponse(fake.children())
|
if (this.isFake) return fakeResponse(fake.children())
|
||||||
|
|
||||||
// const cdnUrl = await this.retrieveCdnUrl()
|
|
||||||
// const authBody = await this.retrieveAuthBody()
|
|
||||||
// const token = await this.retrieveAuthToken(cdnUrl, authBody)
|
|
||||||
|
|
||||||
const url = routes.children
|
const url = routes.children
|
||||||
const session = this.getRequestInit({
|
const session = this.getRequestInit({
|
||||||
headers: {
|
headers: {
|
||||||
Accept: 'application/json;odata=verbose',
|
Accept: 'application/json;odata=verbose',
|
||||||
// Auth: token,
|
|
||||||
topology: await this.getTopology(),
|
|
||||||
Host: 'etjanst.stockholm.se',
|
Host: 'etjanst.stockholm.se',
|
||||||
Referer: 'https://etjanst.stockholm.se/vardnadshavare/inloggad2/hem',
|
Referer: 'https://etjanst.stockholm.se/vardnadshavare/inloggad2/hem',
|
||||||
},
|
},
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@react-native-cookies/cookies": "^6.0.7",
|
"@react-native-cookies/cookies": "^6.0.7",
|
||||||
"@skolplattformen/curriculum": "^1.3.0",
|
"@skolplattformen/curriculum": "^1.4.1",
|
||||||
"@types/base-64": "^1.0.0",
|
"@types/base-64": "^1.0.0",
|
||||||
"@types/he": "^1.1.1",
|
"@types/he": "^1.1.1",
|
||||||
"@types/jest": "^26.0.22",
|
"@types/jest": "^26.0.22",
|
||||||
|
@ -49,7 +49,6 @@
|
||||||
"typescript": "^4.2.4"
|
"typescript": "^4.2.4"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"base-64": "^1.0.0",
|
|
||||||
"camelcase-keys": "^6.2.2",
|
"camelcase-keys": "^6.2.2",
|
||||||
"change-case": "^4.1.2",
|
"change-case": "^4.1.2",
|
||||||
"events": "^3.3.0",
|
"events": "^3.3.0",
|
||||||
|
|
13
yarn.lock
13
yarn.lock
|
@ -522,10 +522,10 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@sinonjs/commons" "^1.7.0"
|
"@sinonjs/commons" "^1.7.0"
|
||||||
|
|
||||||
"@skolplattformen/curriculum@^1.3.0":
|
"@skolplattformen/curriculum@^1.4.1":
|
||||||
version "1.3.0"
|
version "1.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/@skolplattformen/curriculum/-/curriculum-1.3.0.tgz#841e2ff0095e39e174cffdd0b8a81a17956de7ed"
|
resolved "https://registry.yarnpkg.com/@skolplattformen/curriculum/-/curriculum-1.4.1.tgz#f60b82276d61f731bf6c169826a4fb2a82e0a574"
|
||||||
integrity sha512-nuwZX45gHe5JaiYfygDP1HmbhAJOEXuuWwR04tNAnl/PaDGqJscfzKt8YD2SL+MHqi3LARjSKLa4ms4SxVQFyw==
|
integrity sha512-tKJjB2KsOXhNGvtBTp3DsTVchdQbSU08AwAfK1KbmIGFUQLAz8Su3T6RqYsxXEpCcFKRV6poscBnUZrdgZQy3w==
|
||||||
|
|
||||||
"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.7":
|
"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.7":
|
||||||
version "7.1.12"
|
version "7.1.12"
|
||||||
|
@ -991,11 +991,6 @@ balanced-match@^1.0.0:
|
||||||
resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz"
|
resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz"
|
||||||
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
|
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
|
||||||
|
|
||||||
base-64@^1.0.0:
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/base-64/-/base-64-1.0.0.tgz#09d0f2084e32a3fd08c2475b973788eee6ae8f4a"
|
|
||||||
integrity sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==
|
|
||||||
|
|
||||||
base@^0.11.1:
|
base@^0.11.1:
|
||||||
version "0.11.2"
|
version "0.11.2"
|
||||||
resolved "https://registry.npmjs.org/base/-/base-0.11.2.tgz"
|
resolved "https://registry.npmjs.org/base/-/base-0.11.2.tgz"
|
||||||
|
|
Loading…
Reference in New Issue