This commit is contained in:
@ -1,19 +1,48 @@
|
||||
import { IncomingMessage, ServerResponse } from 'http';
|
||||
import { to_utf8 } from '@sapphirecode/encoding-helper';
|
||||
import auth from './Authority';
|
||||
|
||||
interface AccessSettings {
|
||||
access_token_expires_in?: number
|
||||
access_token_expires_in: number
|
||||
include_refresh_token?: boolean
|
||||
refresh_token_expires_in?: number
|
||||
}
|
||||
|
||||
interface AccessResult {
|
||||
access_token_id: string;
|
||||
refresh_token_id?: string;
|
||||
}
|
||||
|
||||
|
||||
interface AccessResponse {
|
||||
token_type: string;
|
||||
access_token: string;
|
||||
expires_in: number;
|
||||
refresh_token?: string;
|
||||
refresh_expires_in?: number;
|
||||
}
|
||||
|
||||
class AuthRequest {
|
||||
public request: IncomingMessage;
|
||||
public response: ServerResponse;
|
||||
|
||||
public constructor (req: IncomingMessage, res: ServerResponse) {
|
||||
public is_basic: boolean;
|
||||
public user: string;
|
||||
public password: string;
|
||||
|
||||
private _cookie_name?: string;
|
||||
|
||||
public constructor (
|
||||
req: IncomingMessage,
|
||||
res: ServerResponse,
|
||||
cookie?: string
|
||||
) {
|
||||
this.request = req;
|
||||
this.response = res;
|
||||
this.is_basic = false;
|
||||
this.user = '';
|
||||
this.password = '';
|
||||
this._cookie_name = cookie;
|
||||
}
|
||||
|
||||
private default_header () {
|
||||
@ -26,25 +55,40 @@ class AuthRequest {
|
||||
access_token_expires_in,
|
||||
include_refresh_token,
|
||||
refresh_token_expires_in
|
||||
}: AccessSettings): void {
|
||||
}: AccessSettings): AccessResult {
|
||||
this.default_header ();
|
||||
this.response.writeHead (200);
|
||||
|
||||
const res = {
|
||||
const at = auth.sign ('access_token', access_token_expires_in);
|
||||
const result: AccessResult = { access_token_id: at.id };
|
||||
|
||||
const res: AccessResponse = {
|
||||
token_type: 'bearer',
|
||||
access_token: auth.sign ('access_token', access_token_expires_in),
|
||||
expires_in: access_token_expires_in,
|
||||
scope
|
||||
access_token: at.signature,
|
||||
expires_in: access_token_expires_in
|
||||
};
|
||||
|
||||
if (include_refresh_token) {
|
||||
res.refresh_token = auth.sign ('refresh_token', refresh_token_expires_in);
|
||||
res.refresh_token_expires_in = refresh_token_expires_in;
|
||||
if (typeof this._cookie_name === 'string') {
|
||||
this.response.setHeader (
|
||||
'Set-Cookie',
|
||||
`${this._cookie_name}=${at.signature}`
|
||||
);
|
||||
}
|
||||
|
||||
if (include_refresh_token) {
|
||||
if (typeof refresh_token_expires_in !== 'number')
|
||||
throw new Error ('no expiry time defined for refresh tokens');
|
||||
const rt = auth.sign ('refresh_token', refresh_token_expires_in);
|
||||
res.refresh_token = rt.signature;
|
||||
res.refresh_expires_in = refresh_token_expires_in;
|
||||
result.refresh_token_id = rt.id;
|
||||
}
|
||||
this.response.writeHead (200);
|
||||
this.response.end (JSON.stringify (res));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public invalid (error_description) {
|
||||
public invalid (error_description?: string) {
|
||||
this.default_header ();
|
||||
this.response.writeHead (400);
|
||||
this.response.end (JSON.stringify ({
|
||||
@ -65,38 +109,67 @@ type AuthRequestHandler = (req: AuthRequest) => void|Promise<void>;
|
||||
interface CreateHandlerOptions {
|
||||
refresh?: AccessSettings;
|
||||
modules?: Record<string, AuthRequestHandler>;
|
||||
cookie_name?: string;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line max-lines-per-function
|
||||
export default function create_auth_handler (
|
||||
default_handler: AuthRequestHandler,
|
||||
{ refresh, modules }: CreateHandlerOptions
|
||||
options?: CreateHandlerOptions
|
||||
) {
|
||||
return function process_request (
|
||||
req: IncomingMessage,
|
||||
res: ServerResponse
|
||||
): Promise<void>|void {
|
||||
const request = new AuthRequest (req, res);
|
||||
const token = (/Bearer (?<token>.+)/ui).exec (req.headers.authorization);
|
||||
if (token === null)
|
||||
return default_handler (request);
|
||||
const request = new AuthRequest (req, res, options?.cookie_name);
|
||||
const token = (/(?<type>\S+) (?<token>.+)/ui)
|
||||
.exec (req.headers.authorization as string);
|
||||
|
||||
const token_data = auth.verify (token.groups.token);
|
||||
if (token === null) {
|
||||
request.deny ();
|
||||
return Promise.resolve ();
|
||||
}
|
||||
|
||||
if ((/Basic/ui).test (token?.groups?.type as string)) {
|
||||
request.is_basic = true;
|
||||
|
||||
let login = token?.groups?.token as string;
|
||||
if (!login.includes (':'))
|
||||
login = to_utf8 (login, 'base64');
|
||||
const login_data = login.split (':');
|
||||
request.user = login_data[0];
|
||||
request.password = login_data[1];
|
||||
|
||||
return default_handler (request);
|
||||
}
|
||||
|
||||
const token_data = auth.verify (token?.groups?.token as string);
|
||||
|
||||
if (!token_data.valid) {
|
||||
request.deny ();
|
||||
return Promise.resolve ();
|
||||
}
|
||||
|
||||
if (token_data.type === 'refresh_token') {
|
||||
request.allow_access (refresh);
|
||||
if (
|
||||
typeof options !== 'undefined'
|
||||
&& typeof options.refresh !== 'undefined'
|
||||
&& token_data.type === 'refresh_token'
|
||||
) {
|
||||
request.allow_access (options.refresh);
|
||||
return Promise.resolve ();
|
||||
}
|
||||
|
||||
if (token_data.type === 'part_token' && Object.keys (modules)
|
||||
.includes (token_data.next_module))
|
||||
return modules[token_data.next_module] (request);
|
||||
if (
|
||||
typeof options !== 'undefined'
|
||||
&& typeof options.modules !== 'undefined'
|
||||
&& token_data.type === 'part_token'
|
||||
&& typeof token_data.next_module !== 'undefined'
|
||||
&& Object.keys (options.modules)
|
||||
.includes (token_data.next_module)
|
||||
)
|
||||
return options.modules[token_data.next_module] (request);
|
||||
|
||||
request.invalid ('invalid bearer token');
|
||||
request.invalid ('invalid bearer type');
|
||||
return Promise.resolve ();
|
||||
};
|
||||
}
|
||||
|
Reference in New Issue
Block a user