Skip to content

Draft: Encrypted cookies #158

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/contracts/src/database/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export interface DatabaseConfig {
/**
* The default database connection name.
*/
connection: string
connection: keyof this['connections']

/**
* The settings of configured database connections.
Expand Down
3 changes: 2 additions & 1 deletion packages/contracts/src/http/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { HttpMethods } from './methods.js'
import { HttpContext } from './context.js'
import { CookieBag } from './cookie-bag.js'
import { IncomingMessage } from 'node:http'
import type { Encrypter } from '../index.js'
import { IncomingHttpHeaders } from 'node:http2'
import { CookieConfig } from './cookie-config.js'
import { MacroableCtor } from '@supercharge/macroable'
Expand All @@ -17,7 +18,7 @@ export interface HttpRequestCtor extends MacroableCtor {
/**
* Create a new HTTP request instance.
*/
new (context: HttpContext, cookieConfig: CookieConfig): HttpRequest
new (context: HttpContext, cookieConfig: CookieConfig, encryption: Encrypter): HttpRequest
}

export type Protocol = 'http' | 'https' | string
Expand Down
3 changes: 2 additions & 1 deletion packages/contracts/src/http/response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { InputBag } from './input-bag.js'
import { HttpContext } from './context.js'
import { CookieBag } from './cookie-bag.js'
import { HttpRedirect } from './redirect.js'
import type { Encrypter } from '../index.js'
import { OutgoingHttpHeaders } from 'node:http2'
import { CookieConfig } from './cookie-config.js'
import { MacroableCtor } from '@supercharge/macroable'
Expand All @@ -13,7 +14,7 @@ export interface HttpResponseCtor extends MacroableCtor {
/**
* Create a new HTTP response instance.
*/
new (context: HttpContext, cookieConfig: CookieConfig): HttpResponse
new (context: HttpContext, cookieConfig: CookieConfig, encryption: Encrypter): HttpResponse
}

export interface HttpResponse<T = any> extends InteractsWithState {
Expand Down
6 changes: 3 additions & 3 deletions packages/contracts/src/logging/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ export interface LoggingConfig {
/**
* The logging driver name.
*/
driver: string
driver: keyof this['channels']

/**
* The logging channels config.
Expand All @@ -13,12 +13,12 @@ export interface LoggingConfig {

export interface LoggingChannels {
/**
* The file channel.
* Stores the configuration for the file channel.
*/
file?: FileChannelConfig

/**
* The console channel.
* Stores the configuration for the console channel.
*/
console?: ConsoleChannelConfig
}
Expand Down
1 change: 1 addition & 0 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
},
"devDependencies": {
"@supercharge/view": "^4.0.0-alpha.2",
"@supercharge/encryption": "^4.0.0-alpha.2",
"c8": "~8.0.1",
"expect": "~29.7.0",
"mocked-env": "~1.3.5",
Expand Down
5 changes: 2 additions & 3 deletions packages/core/src/bootstrappers/handle-shutdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,8 @@ export class HandleShutdown implements Bootstrapper {
*/
async bootstrap (): Promise<void> {
this.shutdownSignalListener
.onShutdown(async () => {
await this.app.shutdown()
})
.onShutdown(async () => await this.app.shutdown())
.onShutdown(() => this.shutdownSignalListener.cleanup())
.listen()
}
}
2 changes: 1 addition & 1 deletion packages/core/src/shutdown-signal-listener.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Os from 'node:os'
import Set from '@supercharge/set'
import { Application } from '@supercharge/contracts'

export type OnShutdownCallback = () => Promise<void> | void
export type OnShutdownCallback = () => Promise<unknown> | unknown

export class ShutdownSignalListener {
/**
Expand Down
2 changes: 2 additions & 0 deletions packages/core/test/error-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { fileURLToPath } from 'node:url'
import { Server } from '@supercharge/http'
import { ViewServiceProvider } from '@supercharge/view'
import { Application, ErrorHandler } from '../dist/index.js'
import { EncryptionServiceProvider } from '@supercharge/encryption'

const viewMock = {
boot () { },
Expand All @@ -29,6 +30,7 @@ function createApp () {

app
.bind('view', () => viewMock)
.register(new EncryptionServiceProvider(app))

app.config()
.set('app.key', 1234)
Expand Down
26 changes: 22 additions & 4 deletions packages/http/src/http-service-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Router } from './routing/index.js'
import { Request } from './server/request.js'
import { Response } from './server/response.js'
import { ServiceProvider } from '@supercharge/support'
import { ApplicationConfig, HttpConfig } from '@supercharge/contracts'
import { ApplicationConfig, HttpConfig, type Encrypter } from '@supercharge/contracts'

/**
* Add container bindings for services from this provider.
Expand Down Expand Up @@ -39,7 +39,12 @@ export class HttpServiceProvider extends ServiceProvider {
.singleton('server', () => {
const appConfig = this.config().get<ApplicationConfig>('app')

return new Server(this.app(), appConfig, this.httpConfig())
return new Server(
this.app(),
appConfig,
this.httpConfig(),
this.encrypter(),
)
})
.alias('server', 'http.server')
.alias('server', Server)
Expand All @@ -50,8 +55,21 @@ export class HttpServiceProvider extends ServiceProvider {
*/
private bindRouter (): void {
this.app()
.singleton('route', () => new Router(this.app(), this.httpConfig()))
.alias('route', 'router')
.singleton('router', () => {
return new Router(
this.app(),
this.httpConfig(),
this.encrypter(),
)
})
.alias('router', 'route')
}

/**
* Returns the encrypter instance.
*/
private encrypter (): Encrypter {
return this.app().make('encryption')
}

/**
Expand Down
19 changes: 16 additions & 3 deletions packages/http/src/routing/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { HandleErrorMiddleware } from '../middleware/handle-error.js'
import { HttpContext, HttpRedirect, Response } from '../server/index.js'
import KoaRouter, { RouterContext, Middleware as KoaMiddleware } from '@koa/router'
import { Class, isConstructor, isFunction, isNotConstructor } from '@supercharge/classes'
import { HttpRouter, RouteHandler, RouteAttributes, HttpMethods, MiddlewareCtor, NextHandler, Middleware, Application, HttpConfig } from '@supercharge/contracts'
import { HttpRouter, RouteHandler, RouteAttributes, HttpMethods, MiddlewareCtor, NextHandler, Middleware, Application, HttpConfig, type Encrypter } from '@supercharge/contracts'

export class Router implements HttpRouter {
private readonly meta: {
Expand All @@ -22,6 +22,11 @@ export class Router implements HttpRouter {
*/
app: Application

/**
* Stores the encrypter instance.
*/
encryption: Encrypter

/**
* Stores the HTTP configuration object.
*/
Expand Down Expand Up @@ -51,9 +56,10 @@ export class Router implements HttpRouter {
/**
* Create a new router instance.
*/
constructor (app: Application, httpConfig: HttpConfig) {
constructor (app: Application, httpConfig: HttpConfig, encryption: Encrypter) {
this.meta = {
app,
encryption,
httpConfig,
groupStack: [],
middleware: new Map(),
Expand All @@ -69,6 +75,13 @@ export class Router implements HttpRouter {
return this.meta.app
}

/**
* Returns the encryption instance.
*/
encryption (): Encrypter {
return this.meta.encryption
}

/**
* Returns the Koa router instance.
*/
Expand Down Expand Up @@ -251,7 +264,7 @@ export class Router implements HttpRouter {
* Wrap the given Koa `ctx` into a Supercharge ctx.
*/
private createContext (ctx: any): HttpContext {
return HttpContext.wrap(ctx, this.app(), this.meta.httpConfig.cookie)
return HttpContext.wrap(ctx, this.app(), this.meta.httpConfig.cookie, this.encryption())
}

/**
Expand Down
22 changes: 14 additions & 8 deletions packages/http/src/server/http-context.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,40 @@

import { RouterContext } from '@koa/router'
import { InteractsWithState } from './interacts-with-state.js'
import { Application, HttpContext as HttpContextContract, HttpRequest, HttpResponse, HttpResponseCtor, HttpRequestCtor, HttpConfig } from '@supercharge/contracts'
import { Application, HttpContext as HttpContextContract, HttpRequest, HttpResponse, HttpResponseCtor, HttpRequestCtor, HttpConfig, type Encrypter } from '@supercharge/contracts'

export class HttpContext extends InteractsWithState implements HttpContextContract {
/**
* The application instance.
* Stores the application instance.
*/
private readonly app: Application

/**
* The cookie config object.
* Stores the encrypter instance.
*/
private readonly encryption: Encrypter

/**
* Stores the cookie config object.
*/
private readonly cookieConfig: HttpConfig['cookie']

/**
* Create a new HTTP context instance.
*/
constructor (ctx: RouterContext, app: Application, cookieConfig: HttpConfig['cookie']) {
constructor (ctx: RouterContext, app: Application, cookieConfig: HttpConfig['cookie'], encryption: Encrypter) {
super(ctx)

this.app = app
this.encryption = encryption
this.cookieConfig = cookieConfig
}

/**
* Returns a wrapped HTTP context for the raw Koa HTTP `ctx`.
*/
static wrap (ctx: RouterContext, app: Application, cookieConfig: HttpConfig['cookie']): HttpContext {
return new this(ctx, app, cookieConfig)
static wrap (ctx: RouterContext, app: Application, cookieConfig: HttpConfig['cookie'], encryption: Encrypter): HttpContext {
return new this(ctx, app, cookieConfig, encryption)
}

/**
Expand All @@ -49,7 +55,7 @@ export class HttpContext extends InteractsWithState implements HttpContextContra
*/
const Request = this.app.make<HttpRequestCtor>('request')

return new Request(this, this.cookieConfig)
return new Request(this, this.cookieConfig, this.encryption)
}

/**
Expand All @@ -63,6 +69,6 @@ export class HttpContext extends InteractsWithState implements HttpContextContra
*/
const Response = this.app.make<HttpResponseCtor>('response')

return new Response(this, this.cookieConfig)
return new Response(this, this.cookieConfig, this.encryption)
}
}
19 changes: 16 additions & 3 deletions packages/http/src/server/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Server as NodeHttpServer } from 'node:http'
import { BodyparserMiddleware } from '../middleware/index.js'
import { className, isConstructor } from '@supercharge/classes'
import { HandleErrorMiddleware } from '../middleware/handle-error.js'
import { Application, HttpServer as HttpServerContract, Middleware as MiddlewareContract, MiddlewareCtor, HttpRouter, HttpServerHandler, InlineMiddlewareHandler, ApplicationConfig, HttpConfig } from '@supercharge/contracts'
import { Application, HttpServer as HttpServerContract, Middleware as MiddlewareContract, MiddlewareCtor, HttpRouter, HttpServerHandler, InlineMiddlewareHandler, ApplicationConfig, HttpConfig, type Encrypter } from '@supercharge/contracts'

type Callback = (server: Server) => unknown | Promise<unknown>

Expand All @@ -26,6 +26,11 @@ export class Server implements HttpServerContract {
*/
httpConfig: HttpConfig

/**
* The encrypter instance.
*/
encryption: Encrypter

/**
* The Koa server instance.
*/
Expand Down Expand Up @@ -55,10 +60,11 @@ export class Server implements HttpServerContract {
/**
* Create a new HTTP context instance.
*/
constructor (app: Application, appConfig: ApplicationConfig, httpConfig: HttpConfig) {
constructor (app: Application, appConfig: ApplicationConfig, httpConfig: HttpConfig, encryption: Encrypter) {
this.meta = {
app,
httpConfig,
encryption,
bootedCallbacks: [],
isBootstrapped: false,
koa: this.createKoaInstance(appConfig)
Expand Down Expand Up @@ -162,6 +168,13 @@ export class Server implements HttpServerContract {
return this.meta.app
}

/**
* Returns the encrypter instance.
*/
encryption (): Encrypter {
return this.meta.encryption
}

/**
* Determine whether the HTTP server is already boostrapped.
*/
Expand Down Expand Up @@ -292,7 +305,7 @@ export class Server implements HttpServerContract {
* Wrap the given Koa `ctx` into a Supercharge context.
*/
private createContext (ctx: any): HttpContext {
return HttpContext.wrap(ctx, this.app(), this.cookieConfig())
return HttpContext.wrap(ctx, this.app(), this.cookieConfig(), this.encryption())
}

/**
Expand Down
2 changes: 1 addition & 1 deletion packages/logging/src/console-logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export class ConsoleLogger extends Logger<ConsoleChannelConfig> implements Loggi
* error => bold red
*/
getColorForLevel (label: string): ChalkInstance {
return this.logColors()[label] || Chalk.white
return this.logColors()[label] ?? Chalk.white
}

/**
Expand Down
Loading