128 lines
3.0 KiB
TypeScript
Raw Normal View History

2024-05-17 23:22:44 +03:00
import { redirect } from '@sveltejs/kit';
import { OAuth2Error } from './error';
interface ErrorResponseData {
[x: string]: string | undefined;
error: string;
error_description: string;
state?: string;
}
export interface OAuth2TokenResponse {
id_token?: string;
access_token?: string;
refresh_token?: string;
expires_in?: number;
token_type?: string;
state?: string;
2024-06-07 17:24:27 +03:00
}
export interface OAuth2IntrospectResponse {
active: boolean;
scope?: string;
2024-06-07 17:24:27 +03:00
username?: string;
client_id?: string;
exp?: number;
2024-05-17 23:22:44 +03:00
}
2024-06-07 17:24:27 +03:00
export type OAuth2ResponseType = OAuth2TokenResponse | OAuth2IntrospectResponse;
2024-05-17 23:22:44 +03:00
2024-06-07 17:24:27 +03:00
export class OAuth2Response {
2024-05-17 23:22:44 +03:00
static error(url: URL, err: OAuth2Error, redirectUri?: string) {
if (!(err instanceof OAuth2Error)) {
throw err;
}
2024-06-07 17:24:27 +03:00
OAuth2Response.doErrorRedirect(url, err, redirectUri);
2024-05-17 23:22:44 +03:00
2024-05-18 12:22:05 +03:00
return OAuth2Response.createErrorResponse(err);
2024-05-17 23:22:44 +03:00
}
static errorPlain(url: URL, err: OAuth2Error, redirectUri?: string) {
if (!(err instanceof OAuth2Error)) {
throw err;
}
2024-06-07 17:24:27 +03:00
OAuth2Response.doErrorRedirect(url, err, redirectUri);
2024-05-17 23:22:44 +03:00
return {
error: err.code,
error_description: err.message
};
}
static response(
url: URL,
2024-06-07 17:24:27 +03:00
obj: OAuth2ResponseType,
2024-05-17 23:22:44 +03:00
redirectUri?: string,
fragment: boolean = false
) {
2024-06-07 17:24:27 +03:00
OAuth2Response.doResponseRedirect(url, obj, redirectUri, fragment);
2024-05-17 23:22:44 +03:00
return OAuth2Response.createResponse(200, obj);
}
static responsePlain(
url: URL,
2024-06-07 17:24:27 +03:00
obj: OAuth2ResponseType,
2024-05-17 23:22:44 +03:00
redirectUri?: string,
fragment: boolean = false
) {
2024-06-07 17:24:27 +03:00
OAuth2Response.doResponseRedirect(url, obj, redirectUri, fragment);
2024-05-17 23:22:44 +03:00
2024-06-07 17:24:27 +03:00
return obj;
}
private static createResponse(code: number, data: unknown) {
const isJson = typeof data === 'object';
const body = isJson ? JSON.stringify(data) : (data as string);
return new Response(body, {
status: code,
headers: {
'Content-Type': isJson ? 'application/json' : 'application/octet-stream'
2024-05-17 23:22:44 +03:00
}
2024-06-07 17:24:27 +03:00
});
}
private static createErrorResponse(err: OAuth2Error) {
return OAuth2Response.createResponse(err.status, {
error: err.code,
error_description: err.message
});
}
2024-05-17 23:22:44 +03:00
2024-06-07 17:24:27 +03:00
private static doResponseRedirect(
url: URL,
obj: OAuth2ResponseType,
redirectUri?: string,
fragment: boolean = false
) {
if (!redirectUri) return;
const searchJoinChar = redirectUri.includes('?') ? '&' : '?';
redirectUri += fragment ? '#' : searchJoinChar;
if (url.searchParams.has('state')) {
(obj as OAuth2TokenResponse).state = url.searchParams.get('state') as string;
2024-05-17 23:22:44 +03:00
}
2024-06-07 17:24:27 +03:00
redirectUri += new URLSearchParams(obj as Record<string, string>).toString();
return redirect(302, redirectUri);
}
private static doErrorRedirect(url: URL, err: OAuth2Error, redirectUri?: string) {
if (!redirectUri) return;
const obj: ErrorResponseData = {
error: err.code,
error_description: err.message
};
if (url.searchParams.has('state')) {
obj.state = url.searchParams.get('state') as string;
}
redirectUri += '?' + new URLSearchParams(obj as Record<string, string>).toString();
return redirect(302, redirectUri);
2024-05-17 23:22:44 +03:00
}
}