fix: 🐛 Adjusted cookie handling (#79)

This commit is contained in:
Johan Öbrink 2021-03-11 17:27:26 +01:00 committed by GitHub
parent c62dab9e2e
commit 16020a3d3c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 57 additions and 52 deletions

View File

@ -49,32 +49,42 @@ export class Api extends EventEmitter {
this.headers = {} this.headers = {}
} }
getPersonalNumber() { public getPersonalNumber(): string | undefined {
return this.personalNumber return this.personalNumber
} }
async getSession(url: string, options: RequestInit = {}): Promise<RequestInit> { private getRequestInit(options: RequestInit = {}): RequestInit {
const cookie = await this.cookieManager.getCookieString(url)
return { return {
...options, ...options,
headers: { headers: {
...this.headers, ...this.headers,
...options.headers, ...options.headers,
},
}
}
public async getSession(url: string, options?: RequestInit): Promise<RequestInit> {
const init = this.getRequestInit(options)
const cookie = await this.cookieManager.getCookieString(url)
return {
...init,
headers: {
...init.headers,
cookie, cookie,
}, },
} }
} }
async clearSession(): Promise<void> { private async clearSession(): Promise<void> {
this.headers = {} this.headers = {}
await this.cookieManager.clearAll() await this.cookieManager.clearAll()
} }
addHeader(name: string, value: string): void { private addHeader(name: string, value: string): void {
this.headers[name] = value this.headers[name] = value
} }
async login(personalNumber: string): Promise<LoginStatusChecker> { public async login(personalNumber: string): Promise<LoginStatusChecker> {
if (personalNumber.endsWith('1212121212')) return this.fakeMode() if (personalNumber.endsWith('1212121212')) return this.fakeMode()
this.isFake = false this.isFake = false
@ -105,14 +115,14 @@ export class Api extends EventEmitter {
return status return status
} }
async retrieveSessionCookie(): Promise<void> { private async retrieveSessionCookie(): Promise<void> {
const url = routes.loginCookie const url = routes.loginCookie
await this.fetch('login-cookie', url) await this.fetch('login-cookie', url)
} }
async retrieveXsrfToken(): Promise<void> { private async retrieveXsrfToken(): Promise<void> {
const url = routes.hemPage const url = routes.hemPage
const session = await this.getSession(url) const session = this.getRequestInit()
const response = await this.fetch('hemPage', url, session) const response = await this.fetch('hemPage', url, session)
const text = await response.text() const text = await response.text()
const doc = html.parse(decode(text)) const doc = html.parse(decode(text))
@ -120,9 +130,9 @@ export class Api extends EventEmitter {
this.addHeader('X-XSRF-Token', xsrfToken) this.addHeader('X-XSRF-Token', xsrfToken)
} }
async retrieveApiKey(): Promise<void> { private async retrieveApiKey(): Promise<void> {
const url = routes.startBundle const url = routes.startBundle
const session = await this.getSession(url) const session = this.getRequestInit()
const response = await this.fetch('startBundle', url, session) const response = await this.fetch('startBundle', url, session)
const text = await response.text() const text = await response.text()
@ -133,29 +143,27 @@ export class Api extends EventEmitter {
this.addHeader('API-Key', apiKey) this.addHeader('API-Key', apiKey)
} }
async retrieveCdnUrl(): Promise<string> { private async retrieveCdnUrl(): Promise<string> {
const url = routes.cdn const url = routes.cdn
const session = await this.getSession(url) const session = this.getRequestInit()
const response = await this.fetch('cdn', url, session) const response = await this.fetch('cdn', url, session)
const cdnUrl = await response.text() const cdnUrl = await response.text()
return cdnUrl return cdnUrl
} }
async retrieveAuthBody(): Promise<string> { private async retrieveAuthBody(): Promise<string> {
const url = routes.auth const url = routes.auth
const session = await this.getSession(url) const session = this.getRequestInit()
const response = await this.fetch('auth', url, session) const response = await this.fetch('auth', url, session)
const authBody = await response.text() const authBody = await response.text()
return authBody return authBody
} }
async retrieveAuthToken(url: string, authBody: string): Promise<string> { private async retrieveAuthToken(url: string, authBody: string): Promise<string> {
const cdnHost = new URL(url).host const session = this.getRequestInit({
const session = await this.getSession(url, {
method: 'POST', method: 'POST',
headers: { headers: {
Accept: 'text/plain', Accept: 'text/plain',
Host: cdnHost,
Origin: 'https://etjanst.stockholm.se', Origin: 'https://etjanst.stockholm.se',
Referer: 'https://etjanst.stockholm.se/', Referer: 'https://etjanst.stockholm.se/',
Connection: 'keep-alive', Connection: 'keep-alive',
@ -163,15 +171,14 @@ export class Api extends EventEmitter {
body: authBody, body: authBody,
}) })
// Delete cookies from session and empty cookie manager // Temporarily remove cookies
delete session.headers.cookie
const cookies = await this.cookieManager.getCookies(url) const cookies = await this.cookieManager.getCookies(url)
this.cookieManager.clearAll() this.cookieManager.clearAll()
// Perform request // Perform request
const response = await this.fetch('createItem', url, session) const response = await this.fetch('createItem', url, session)
// Refill cookie manager // Restore cookies
cookies.forEach((cookie) => { cookies.forEach((cookie) => {
this.cookieManager.setCookie(cookie, url) this.cookieManager.setCookie(cookie, url)
}) })
@ -184,7 +191,7 @@ export class Api extends EventEmitter {
return authData.token return authData.token
} }
async fakeMode(): Promise<LoginStatusChecker> { private async fakeMode(): Promise<LoginStatusChecker> {
this.isFake = true this.isFake = true
setTimeout(() => { setTimeout(() => {
@ -197,17 +204,17 @@ export class Api extends EventEmitter {
return emitter return emitter
} }
async getUser(): Promise<User> { public async getUser(): Promise<User> {
if (this.isFake) return fakeResponse(fake.user()) if (this.isFake) return fakeResponse(fake.user())
const url = routes.user const url = routes.user
const session = await this.getSession(url) const session = this.getRequestInit()
const response = await this.fetch('user', url, session) const response = await this.fetch('user', url, session)
const data = await response.json() const data = await response.json()
return parse.user(data) return parse.user(data)
} }
async getChildren(): Promise<Child[]> { public async getChildren(): Promise<Child[]> {
if (this.isFake) return fakeResponse(fake.children()) if (this.isFake) return fakeResponse(fake.children())
const cdnUrl = await this.retrieveCdnUrl() const cdnUrl = await this.retrieveCdnUrl()
@ -215,7 +222,7 @@ export class Api extends EventEmitter {
const token = await this.retrieveAuthToken(cdnUrl, authBody) const token = await this.retrieveAuthToken(cdnUrl, authBody)
const url = routes.children const url = routes.children
const session = await this.getSession(url, { const session = this.getRequestInit({
headers: { headers: {
Accept: 'application/json;odata=verbose', Accept: 'application/json;odata=verbose',
Auth: token, Auth: token,
@ -225,8 +232,6 @@ export class Api extends EventEmitter {
}) })
const response = await this.fetch('children', url, session) const response = await this.fetch('children', url, session)
console.log(session.headers)
console.log('children response', response)
if (!response.ok) { if (!response.ok) {
throw new Error(`Server Error [${response.status}] [${response.statusText}] [${url}]`) throw new Error(`Server Error [${response.status}] [${response.statusText}] [${url}]`)
} }
@ -235,78 +240,78 @@ export class Api extends EventEmitter {
return parse.children(data) return parse.children(data)
} }
async getCalendar(child: Child): Promise<CalendarItem[]> { public async getCalendar(child: Child): Promise<CalendarItem[]> {
if (this.isFake) return fakeResponse(fake.calendar(child)) if (this.isFake) return fakeResponse(fake.calendar(child))
const url = routes.calendar(child.id) const url = routes.calendar(child.id)
const session = await this.getSession(url) const session = this.getRequestInit()
const response = await this.fetch('calendar', url, session) const response = await this.fetch('calendar', url, session)
const data = await response.json() const data = await response.json()
return parse.calendar(data) return parse.calendar(data)
} }
async getClassmates(child: Child): Promise<Classmate[]> { public async getClassmates(child: Child): Promise<Classmate[]> {
if (this.isFake) return fakeResponse(fake.classmates(child)) if (this.isFake) return fakeResponse(fake.classmates(child))
const url = routes.classmates(child.sdsId) const url = routes.classmates(child.sdsId)
const session = await this.getSession(url) const session = this.getRequestInit()
const response = await this.fetch('classmates', url, session) const response = await this.fetch('classmates', url, session)
const data = await response.json() const data = await response.json()
return parse.classmates(data) return parse.classmates(data)
} }
async getSchedule(child: Child, from: DateTime, to: DateTime): Promise<ScheduleItem[]> { public async getSchedule(child: Child, from: DateTime, to: DateTime): Promise<ScheduleItem[]> {
if (this.isFake) return fakeResponse(fake.schedule(child)) if (this.isFake) return fakeResponse(fake.schedule(child))
const url = routes.schedule(child.sdsId, from.toISODate(), to.toISODate()) const url = routes.schedule(child.sdsId, from.toISODate(), to.toISODate())
const session = await this.getSession(url) const session = this.getRequestInit()
const response = await this.fetch('schedule', url, session) const response = await this.fetch('schedule', url, session)
const data = await response.json() const data = await response.json()
return parse.schedule(data) return parse.schedule(data)
} }
async getNews(child: Child): Promise<NewsItem[]> { public async getNews(child: Child): Promise<NewsItem[]> {
if (this.isFake) return fakeResponse(fake.news(child)) if (this.isFake) return fakeResponse(fake.news(child))
const url = routes.news(child.id) const url = routes.news(child.id)
const session = await this.getSession(url) const session = this.getRequestInit()
const response = await this.fetch('news', url, session) const response = await this.fetch('news', url, session)
const data = await response.json() const data = await response.json()
return parse.news(data) return parse.news(data)
} }
async getNewsDetails(child: Child, item: NewsItem): Promise<any> { public async getNewsDetails(child: Child, item: NewsItem): Promise<any> {
if (this.isFake) { if (this.isFake) {
return fakeResponse(fake.news(child).find((ni) => ni.id === item.id)) return fakeResponse(fake.news(child).find((ni) => ni.id === item.id))
} }
const url = routes.newsDetails(child.id, item.id) const url = routes.newsDetails(child.id, item.id)
const session = await this.getSession(url) const session = this.getRequestInit()
const response = await this.fetch(`news_${item.id}`, url, session) const response = await this.fetch(`news_${item.id}`, url, session)
const data = await response.json() const data = await response.json()
return parse.newsItemDetails(data) return parse.newsItemDetails(data)
} }
async getMenu(child: Child): Promise<MenuItem[]> { public async getMenu(child: Child): Promise<MenuItem[]> {
if (this.isFake) return fakeResponse(fake.menu(child)) if (this.isFake) return fakeResponse(fake.menu(child))
const url = routes.menu(child.id) const url = routes.menu(child.id)
const session = await this.getSession(url) const session = this.getRequestInit()
const response = await this.fetch('menu', url, session) const response = await this.fetch('menu', url, session)
const data = await response.json() const data = await response.json()
return parse.menu(data) return parse.menu(data)
} }
async getNotifications(child: Child): Promise<Notification[]> { public async getNotifications(child: Child): Promise<Notification[]> {
if (this.isFake) return fakeResponse(fake.notifications(child)) if (this.isFake) return fakeResponse(fake.notifications(child))
const url = routes.notifications(child.sdsId) const url = routes.notifications(child.sdsId)
const session = await this.getSession(url) const session = this.getRequestInit()
const response = await this.fetch('notifications', url, session) const response = await this.fetch('notifications', url, session)
const data = await response.json() const data = await response.json()
return parse.notifications(data) return parse.notifications(data)
} }
async logout() { public async logout() {
this.isFake = false this.isFake = false
this.personalNumber = undefined this.personalNumber = undefined
this.isLoggedIn = false this.isLoggedIn = false

16
run.js
View File

@ -91,14 +91,14 @@ async function run() {
api.on('login', async () => { api.on('login', async () => {
console.log('Logged in') console.log('Logged in')
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)
/*
console.log('calendar') console.log('calendar')
const calendar = await api.getCalendar(children[0]) const calendar = await api.getCalendar(children[0])
console.log(calendar) console.log(calendar)
@ -113,7 +113,7 @@ async function run() {
console.log('news') console.log('news')
const news = await api.getNews(children[0]) const news = await api.getNews(children[0])
*/
/*console.log('news details') /*console.log('news details')
const newsItems = await Promise.all( const newsItems = await Promise.all(
news.map((newsItem) => news.map((newsItem) =>
@ -127,9 +127,9 @@ async function run() {
const menu = await api.getMenu(children[0]) const menu = await api.getMenu(children[0])
console.log(menu)*/ console.log(menu)*/
console.log('notifications') // console.log('notifications')
const notifications = await api.getNotifications(children[0]) // const notifications = await api.getNotifications(children[0])
console.log(notifications) // console.log(notifications)
await api.logout() await api.logout()
}) })