Skip to content

Commit

Permalink
fix: 🐛 Adjusted cookie handling (kolplattformen#79)
Browse files Browse the repository at this point in the history
  • Loading branch information
JohanObrink authored Mar 11, 2021
1 parent c62dab9 commit 16020a3
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 52 deletions.
93 changes: 49 additions & 44 deletions lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,32 +49,42 @@ export class Api extends EventEmitter {
this.headers = {}
}

getPersonalNumber() {
public getPersonalNumber(): string | undefined {
return this.personalNumber
}

async getSession(url: string, options: RequestInit = {}): Promise<RequestInit> {
const cookie = await this.cookieManager.getCookieString(url)
private getRequestInit(options: RequestInit = {}): RequestInit {
return {
...options,
headers: {
...this.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,
},
}
}

async clearSession(): Promise<void> {
private async clearSession(): Promise<void> {
this.headers = {}
await this.cookieManager.clearAll()
}

addHeader(name: string, value: string): void {
private addHeader(name: string, value: string): void {
this.headers[name] = value
}

async login(personalNumber: string): Promise<LoginStatusChecker> {
public async login(personalNumber: string): Promise<LoginStatusChecker> {
if (personalNumber.endsWith('1212121212')) return this.fakeMode()

this.isFake = false
Expand Down Expand Up @@ -105,24 +115,24 @@ export class Api extends EventEmitter {
return status
}

async retrieveSessionCookie(): Promise<void> {
private async retrieveSessionCookie(): Promise<void> {
const url = routes.loginCookie
await this.fetch('login-cookie', url)
}

async retrieveXsrfToken(): Promise<void> {
private async retrieveXsrfToken(): Promise<void> {
const url = routes.hemPage
const session = await this.getSession(url)
const session = this.getRequestInit()
const response = await this.fetch('hemPage', url, session)
const text = await response.text()
const doc = html.parse(decode(text))
const xsrfToken = doc.querySelector('input[name="__RequestVerificationToken"]').getAttribute('value') || ''
this.addHeader('X-XSRF-Token', xsrfToken)
}

async retrieveApiKey(): Promise<void> {
private async retrieveApiKey(): Promise<void> {
const url = routes.startBundle
const session = await this.getSession(url)
const session = this.getRequestInit()
const response = await this.fetch('startBundle', url, session)
const text = await response.text()

Expand All @@ -133,45 +143,42 @@ export class Api extends EventEmitter {
this.addHeader('API-Key', apiKey)
}

async retrieveCdnUrl(): Promise<string> {
private async retrieveCdnUrl(): Promise<string> {
const url = routes.cdn
const session = await this.getSession(url)
const session = this.getRequestInit()
const response = await this.fetch('cdn', url, session)
const cdnUrl = await response.text()
return cdnUrl
}

async retrieveAuthBody(): Promise<string> {
private async retrieveAuthBody(): Promise<string> {
const url = routes.auth
const session = await this.getSession(url)
const session = this.getRequestInit()
const response = await this.fetch('auth', url, session)
const authBody = await response.text()
return authBody
}

async retrieveAuthToken(url: string, authBody: string): Promise<string> {
const cdnHost = new URL(url).host
const session = await this.getSession(url, {
private async retrieveAuthToken(url: string, authBody: string): Promise<string> {
const session = this.getRequestInit({
method: 'POST',
headers: {
Accept: 'text/plain',
Host: cdnHost,
Origin: 'https://etjanst.stockholm.se',
Referer: 'https://etjanst.stockholm.se/',
Connection: 'keep-alive',
},
body: authBody,
})

// Delete cookies from session and empty cookie manager
delete session.headers.cookie
// Temporarily remove cookies
const cookies = await this.cookieManager.getCookies(url)
this.cookieManager.clearAll()

// Perform request
const response = await this.fetch('createItem', url, session)

// Refill cookie manager
// Restore cookies
cookies.forEach((cookie) => {
this.cookieManager.setCookie(cookie, url)
})
Expand All @@ -184,7 +191,7 @@ export class Api extends EventEmitter {
return authData.token
}

async fakeMode(): Promise<LoginStatusChecker> {
private async fakeMode(): Promise<LoginStatusChecker> {
this.isFake = true

setTimeout(() => {
Expand All @@ -197,25 +204,25 @@ export class Api extends EventEmitter {
return emitter
}

async getUser(): Promise<User> {
public async getUser(): Promise<User> {
if (this.isFake) return fakeResponse(fake.user())

const url = routes.user
const session = await this.getSession(url)
const session = this.getRequestInit()
const response = await this.fetch('user', url, session)
const data = await response.json()
return parse.user(data)
}

async getChildren(): Promise<Child[]> {
public async getChildren(): Promise<Child[]> {
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 session = await this.getSession(url, {
const session = this.getRequestInit({
headers: {
Accept: 'application/json;odata=verbose',
Auth: token,
Expand All @@ -225,8 +232,6 @@ export class Api extends EventEmitter {
})
const response = await this.fetch('children', url, session)

console.log(session.headers)
console.log('children response', response)
if (!response.ok) {
throw new Error(`Server Error [${response.status}] [${response.statusText}] [${url}]`)
}
Expand All @@ -235,78 +240,78 @@ export class Api extends EventEmitter {
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))

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 data = await response.json()
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))

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 data = await response.json()
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))

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 data = await response.json()
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))

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 data = await response.json()
return parse.news(data)
}

async getNewsDetails(child: Child, item: NewsItem): Promise<any> {
public async getNewsDetails(child: Child, item: NewsItem): Promise<any> {
if (this.isFake) {
return fakeResponse(fake.news(child).find((ni) => ni.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 data = await response.json()
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))

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 data = await response.json()
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))

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 data = await response.json()
return parse.notifications(data)
}

async logout() {
public async logout() {
this.isFake = false
this.personalNumber = undefined
this.isLoggedIn = false
Expand Down
16 changes: 8 additions & 8 deletions run.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,14 +91,14 @@ async function run() {
api.on('login', async () => {
console.log('Logged in')

console.log('user')
const user = await api.getUser()
console.log(user)
// console.log('user')
// const user = await api.getUser()
// console.log(user)

console.log('children')
const children = await api.getChildren()
console.log(children)

/*
console.log('calendar')
const calendar = await api.getCalendar(children[0])
console.log(calendar)
Expand All @@ -113,7 +113,7 @@ async function run() {
console.log('news')
const news = await api.getNews(children[0])

*/
/*console.log('news details')
const newsItems = await Promise.all(
news.map((newsItem) =>
Expand All @@ -127,9 +127,9 @@ async function run() {
const menu = await api.getMenu(children[0])
console.log(menu)*/

console.log('notifications')
const notifications = await api.getNotifications(children[0])
console.log(notifications)
// console.log('notifications')
// const notifications = await api.getNotifications(children[0])
// console.log(notifications)

await api.logout()
})
Expand Down

0 comments on commit 16020a3

Please sign in to comment.