You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
123 lines
3.2 KiB
123 lines
3.2 KiB
import { Injectable } from '../../../di/src/decorator/Injection.ts'
|
|
import { getCookies, setCookie, delCookie, ServerRequest } from '../external/http.ts'
|
|
import { InMemCache } from '../support/InMemCache.ts'
|
|
import { HTTPRequest } from './type/HTTPRequest.ts'
|
|
|
|
/**
|
|
* Base type representing a parsed cookie.
|
|
*/
|
|
export interface Cookie {
|
|
key: string,
|
|
original_value: string,
|
|
value: any,
|
|
}
|
|
|
|
/**
|
|
* Type representing what might be a cookie, or might be undefined.
|
|
*/
|
|
export type MaybeCookie = Cookie | undefined
|
|
|
|
// TODO cookie options (http only, expires, &c.)
|
|
/**
|
|
* Base class for managing cookies.
|
|
*/
|
|
@Injectable()
|
|
export class CookieJar {
|
|
/**
|
|
* Cache of parsed cookie values.
|
|
* @type object
|
|
*/
|
|
protected _parsed: { [key: string]: string } = {}
|
|
|
|
/**
|
|
* Cache of cookie values.
|
|
* @type InMemCache
|
|
*/
|
|
protected _cache = new InMemCache()
|
|
|
|
constructor(
|
|
/**
|
|
* The associated request.
|
|
* @type HTTPRequest
|
|
*/
|
|
protected request: HTTPRequest,
|
|
) {
|
|
this._parsed = getCookies(this.request.to_native)
|
|
}
|
|
|
|
/**
|
|
* Get the raw value of a cookie string, if it is defined.
|
|
* @param {string} key
|
|
* @return string | undefined
|
|
*/
|
|
public async get_raw(key: string): Promise<string | undefined> {
|
|
return this._parsed[key]
|
|
}
|
|
|
|
/**
|
|
* Get the parsed value of a cookie, if it is defined.
|
|
* @param {string} key
|
|
* @return Promise<MaybeCookie>
|
|
*/
|
|
public async get(key: string): Promise<MaybeCookie> {
|
|
// Try the cache
|
|
if ( await this._cache.has(key) ) {
|
|
return JSON.parse((await this._cache.fetch(key)) || '""') as Cookie
|
|
}
|
|
|
|
// If the cache missed, try to parse it and load in cache
|
|
if ( key in this._parsed ) {
|
|
let value = this._parsed[key]
|
|
try {
|
|
value = JSON.parse(atob(this._parsed[key]))
|
|
} catch(e) {}
|
|
|
|
const cookie = {
|
|
key,
|
|
value,
|
|
original_value: this._parsed[key],
|
|
}
|
|
|
|
await this._cache.put(key, JSON.stringify(cookie))
|
|
return cookie
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set the cookie for the given key to the serialized value.
|
|
* @param {string} key
|
|
* @param value
|
|
* @return Promise<void>
|
|
*/
|
|
public async set(key: string, value: any): Promise<void> {
|
|
const original_value = btoa(JSON.stringify(value))
|
|
const cookie = {
|
|
key,
|
|
value,
|
|
original_value,
|
|
}
|
|
|
|
await this._cache.put(key, JSON.stringify(cookie))
|
|
setCookie(this.request.response, { name: key, value: original_value })
|
|
}
|
|
|
|
/**
|
|
* Returns true if the given cookie exists.
|
|
* @param {string} key
|
|
* @return Promise<boolean>
|
|
*/
|
|
public async has(key: string): Promise<boolean> {
|
|
return (await this._cache.has(key)) || key in this._parsed
|
|
}
|
|
|
|
/**
|
|
* Deletes the given cookie, if it exists.
|
|
* @param {string} key
|
|
* @return Promise<void>
|
|
*/
|
|
public async delete(key: string): Promise<void> {
|
|
await this._cache.drop(key)
|
|
delCookie(this.request.response, key)
|
|
}
|
|
}
|