Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
matthieusieben committed Dec 18, 2023
1 parent 624f005 commit e056360
Show file tree
Hide file tree
Showing 13 changed files with 544 additions and 280 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
import { Client } from '../client/client'
import { ClientId } from '../client/types'
import { DeviceId } from '../device/device-id'
import {
AuthorizationRequest,
AuthorizationRequestJar,
AuthorizationRequestUri,
RequestUri,
RequestUriPrefix,
authorizationRequestSchema,
} from './types'

// Make opaque
declare const requestIdSymbol: unique symbol
export type RequestId = string & { [requestIdSymbol]: true }

export type SessionId = string

export type RequestInfo = {
id: RequestId
uri: RequestUri
data: AuthorizationRequest
expiresAt: Date
}

export type UpdateData = {
deviceId?: DeviceId
sessionId?: SessionId
expiresAt?: Date
}

export class AuthorizationRequestManager {
constructor(protected readonly store: unknown) {}

async create(
client: Client,
input: AuthorizationRequestJar | AuthorizationRequest,
deviceId: null | DeviceId = null,
clientAuthenticated = false,
): Promise<RequestInfo> {
const request =
'request' in input
? authorizationRequestSchema.parse(
(
await client.jwtVerify(input.request, {
maxTokenAge: 60,
})
).payload,
)
: input

// TODO Validate request agains client metadata !!!!

// TODO: insert in store
const data = {
clientId: client.id,
clientAuthenticated, // Is this even used ?
request,
deviceId,
expiresAt: new Date(Date.now() + 60 * 1000),
}

const id = '123' as RequestId
const uri = encodeRequestUri(id)
return { id, uri, expiresAt: data.expiresAt, data: data.request }
}

async get(
client: Client,
{ request_uri: uri }: AuthorizationRequestUri,
deviceId: DeviceId,
): Promise<RequestInfo> {
const id = decodeRequestUri(uri)

// TODO: from a store
const data = {
deviceId: 123n as DeviceId | undefined,
clientId: 'did:web:foo' as ClientId,
sessionId: '123' as SessionId | undefined,
expiresAt: new Date(Date.now() - 60 * 1000 * Math.random()),
request: <AuthorizationRequest>{
response_type: 'code',
redirect_uri: 'https://foo.com',
scope: 'openid',
state: 'randomStr',
nonce: 'randomStr',
response_mode: 'query',
prompt: 'none',
code_challenge: 'randomStr',
code_challenge_method: 'S256',
},
}

const updates: UpdateData = {}

// TODO : better errors

if (data.sessionId) {
// If the a session was linked to the request, the next step is to exchange
// the code for a token.
await this.delete(uri)
throw new TypeError('Invalid request_uri')
}

if (data.expiresAt < new Date()) {
await this.delete(uri)
throw new TypeError('Invalid request_uri')
} else {
updates.expiresAt = new Date(Date.now() + 60 * 1000)
}

if (data.clientId !== client.id) {
await this.delete(uri)
throw new TypeError('Invalid request_uri')
}

if (!data.deviceId) {
updates.deviceId = deviceId
} else if (data.deviceId !== deviceId) {
await this.delete(uri)
throw new TypeError('Invalid request_uri')
}

if (Object.keys(updates).length > 0) {
await this.update(uri, updates)
}

return {
id,
uri,
expiresAt: updates.expiresAt || data.expiresAt,
data: data.request,
}
}

async conclude(uri, sessionId: SessionId): Promise<{ code: string }> {
// TODO

// Bind the request to the session, preventing it from being used again.
// - We might want to update the expiresAt here, to allow some time to the
// client to exchange the code for a token.

return { code: '123' }
}

private async update(
requestUri: RequestUri,
data: UpdateData,
): Promise<void> {
// TODO
// Whenever the request is bound to a session, it means that the user has
// already authenticated and consented to the client's request. In this
// case, it should no longer be possible to use the request_uri or update
// the request.
}

public async delete(uri: RequestUri): Promise<void> {
// TODO
}
}

function encodeRequestUri(requestId: RequestId): RequestUri {
return `${RequestUriPrefix}${encodeURIComponent(requestId)}`
}

function decodeRequestUri(requestUri: RequestUri) {
// Foolproofing
if (!requestUri.startsWith(RequestUriPrefix)) {
throw new TypeError('Invalid request_uri')
}
return decodeURIComponent(
requestUri.slice(RequestUriPrefix.length),
) as RequestId
}
Loading

0 comments on commit e056360

Please sign in to comment.