Skip to content

Commit

Permalink
fix: move tests into root/test/ directory
Browse files Browse the repository at this point in the history
  • Loading branch information
dancastillo committed Aug 5, 2024
1 parent 1af4cfc commit b19ffb3
Show file tree
Hide file tree
Showing 51 changed files with 815 additions and 30 deletions.
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
"name": "@fastify/passport",
"version": "2.5.0",
"description": "Simple, unobtrusive authentication for Fastify.",
"main": "dist/index.js",
"main": "dist/src/index.js",
"type": "commonjs",
"types": "dist/index.d.ts",
"types": "dist/src/index.d.ts",
"scripts": {
"build": "rimraf ./dist && mkdir dist && tsc --outDir dist && git rev-parse HEAD > BUILD_SHA",
"build": "rimraf ./dist && tsc && git rev-parse HEAD > BUILD_SHA",
"lint": "eslint \"*/**/*.{js,ts,tsx}\"",
"lint:fix": "prettier --loglevel warn --write \"src/**/*.{ts,tsx}\" && eslint \"*/**/*.{js,ts,tsx}\" --quiet --fix",
"prepublishOnly": "npm run build",
Expand Down
48 changes: 48 additions & 0 deletions src/AuthenticationRoute.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import Authenticator from './Authenticator';
import { AnyStrategy, Strategy } from './strategies';
import { FastifyReply, FastifyRequest } from 'fastify';
type FlashObject = {
type?: string;
message?: string;
};
type FailureObject = {
challenge?: string | FlashObject;
status?: number;
type?: string;
};
export interface AuthenticateOptions {
scope?: string | string[];
failureFlash?: boolean | string | FlashObject;
failureMessage?: boolean | string;
successRedirect?: string;
failureRedirect?: string;
failWithError?: boolean;
successFlash?: boolean | string | FlashObject;
successMessage?: boolean | string;
assignProperty?: string;
successReturnToOrRedirect?: string;
state?: string;
authInfo?: boolean;
session?: boolean;
pauseStream?: boolean;
keepSessionInfo?: boolean;
}
export type SingleStrategyCallback = (request: FastifyRequest, reply: FastifyReply, err: null | Error, user?: unknown, info?: unknown, status?: number) => Promise<void>;
export type MultiStrategyCallback = (request: FastifyRequest, reply: FastifyReply, err: null | Error, user?: unknown, info?: unknown, statuses?: (number | undefined)[]) => Promise<void>;
export type AuthenticateCallback<StrategyOrStrategies extends string | Strategy | (string | Strategy)[]> = StrategyOrStrategies extends any[] ? MultiStrategyCallback : SingleStrategyCallback;
export declare class AuthenticationRoute<StrategyOrStrategies extends string | Strategy | (string | Strategy)[]> {
readonly authenticator: Authenticator;
readonly callback?: AuthenticateCallback<StrategyOrStrategies> | undefined;
readonly options: AuthenticateOptions;
readonly strategies: (string | Strategy)[];
readonly isMultiStrategy: boolean;
constructor(authenticator: Authenticator, strategyOrStrategies: StrategyOrStrategies, options?: AuthenticateOptions, callback?: AuthenticateCallback<StrategyOrStrategies> | undefined);
handler: (request: FastifyRequest, reply: FastifyReply) => Promise<void>;
attemptStrategy(failures: FailureObject[], name: string, prototype: AnyStrategy, request: FastifyRequest, reply: FastifyReply): Promise<void>;
onAllFailed(failures: FailureObject[], request: FastifyRequest, reply: FastifyReply): Promise<void>;
applyFlashOrMessage(event: 'success' | 'failure', request: FastifyRequest, result?: FlashObject): void;
toFlashObject(input: string | FlashObject | undefined, type: string): FlashObject | undefined;
private getStrategyName;
private getStrategy;
}
export {};
230 changes: 230 additions & 0 deletions src/AuthenticationRoute.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AuthenticationRoute = void 0;
const http = require("http");
const errors_1 = require("./errors");
const util_1 = require("util");
const addMessage = (request, message) => {
const existing = request.session.get('messages');
const messages = existing ? [...existing, message] : [message];
request.session.set('messages', messages);
};
const Unhandled = Symbol.for('passport-unhandled');
class AuthenticationRoute {
constructor(authenticator, strategyOrStrategies, options, callback) {
this.authenticator = authenticator;
this.callback = callback;
this.handler = async (request, reply) => {
if (!request.passport) {
throw new Error('passport.initialize() plugin not in use');
}
const failures = [];
for (const nameOrInstance of this.strategies) {
try {
return await this.attemptStrategy(failures, this.getStrategyName(nameOrInstance), this.getStrategy(nameOrInstance), request, reply);
}
catch (e) {
if (e == Unhandled) {
continue;
}
else {
throw e;
}
}
}
return this.onAllFailed(failures, request, reply);
};
this.options = options || {};
if (Array.isArray(strategyOrStrategies)) {
this.strategies = strategyOrStrategies;
this.isMultiStrategy = false;
}
else {
this.strategies = [strategyOrStrategies];
this.isMultiStrategy = false;
}
}
attemptStrategy(failures, name, prototype, request, reply) {
const strategy = Object.create(prototype);
return new Promise((resolve, reject) => {
strategy.success = (user, info) => {
request.log.debug({ strategy: name }, 'passport strategy success');
if (this.callback) {
return resolve(this.callback(request, reply, null, user, info));
}
info = info || {};
this.applyFlashOrMessage('success', request, info);
if (this.options.assignProperty) {
request[this.options.assignProperty] = user;
return resolve();
}
void request
.logIn(user, this.options)
.catch(reject)
.then(() => {
const complete = () => {
if (this.options.successReturnToOrRedirect) {
let url = this.options.successReturnToOrRedirect;
if (request.session && request.session.get('returnTo')) {
url = request.session.get('returnTo');
request.session.set('returnTo', undefined);
}
void reply.redirect(url);
}
else if (this.options.successRedirect) {
void reply.redirect(this.options.successRedirect);
}
return resolve();
};
if (this.options.authInfo !== false) {
void this.authenticator
.transformAuthInfo(info, request)
.catch(reject)
.then((transformedInfo) => {
request.authInfo = transformedInfo;
complete();
});
}
else {
complete();
}
});
};
strategy.fail = function (challengeOrStatus, status) {
request.log.trace({ strategy: name }, 'passport strategy failed');
let challenge;
if (typeof challengeOrStatus === 'number') {
status = challengeOrStatus;
challenge = undefined;
}
else {
challenge = challengeOrStatus;
}
failures.push({ challenge, status: status });
reject(Unhandled);
};
strategy.redirect = (url, status) => {
request.log.trace({ strategy: name, url }, 'passport strategy redirecting');
void reply.status(status || 302);
void reply.redirect(url);
resolve();
};
strategy.pass = () => {
request.log.trace({ strategy: name }, 'passport strategy passed');
resolve();
};
const error = (err) => {
request.log.trace({ strategy: name, err }, 'passport strategy errored');
if (this.callback) {
return resolve(this.callback(request, reply, err));
}
reject(err);
};
strategy.error = error;
request.log.trace({ strategy: name }, 'attempting passport strategy authentication');
try {
const result = strategy.authenticate(request, this.options);
if (util_1.types.isPromise(result)) {
void result.catch(error);
}
}
catch (err) {
error(err);
}
});
}
async onAllFailed(failures, request, reply) {
var _a;
request.log.trace('all passport strategies failed');
if (this.callback) {
if (this.isMultiStrategy) {
const challenges = failures.map((f) => f.challenge);
const statuses = failures.map((f) => f.status);
return await this.callback(request, reply, null, false, challenges, statuses);
}
else {
return await this.callback(request, reply, null, false, failures[0].challenge, failures[0].status);
}
}
this.applyFlashOrMessage('failure', request, this.toFlashObject((_a = failures[0]) === null || _a === void 0 ? void 0 : _a.challenge, 'error'));
if (this.options.failureRedirect) {
return reply.redirect(this.options.failureRedirect);
}
const rchallenge = [];
let rstatus;
for (const failure of failures) {
rstatus = rstatus || failure.status;
if (typeof failure.challenge === 'string') {
rchallenge.push(failure.challenge);
}
}
rstatus = rstatus || 401;
void reply.code(rstatus);
if (reply.statusCode === 401 && rchallenge.length) {
void reply.header('WWW-Authenticate', rchallenge);
}
if (this.options.failWithError) {
throw new errors_1.default(http.STATUS_CODES[reply.statusCode], rstatus);
}
void reply.send(http.STATUS_CODES[reply.statusCode]);
}
applyFlashOrMessage(event, request, result) {
var _a;
const flashOption = this.options[`${event}Flash`];
const level = event == 'success' ? 'success' : 'error';
if (flashOption) {
let flash;
if (typeof flashOption === 'boolean') {
flash = this.toFlashObject(result, level);
}
else {
flash = this.toFlashObject(flashOption, level);
}
if (flash && flash.type && flash.message) {
request.flash(flash.type, flash.message);
}
}
const messageOption = this.options[`${event}Message`];
if (messageOption) {
const message = typeof messageOption === 'boolean' ? (_a = this.toFlashObject(result, level)) === null || _a === void 0 ? void 0 : _a.message : messageOption;
if (message) {
addMessage(request, message);
}
}
}
toFlashObject(input, type) {
if (input === undefined) {
return;
}
else if (typeof input == 'string') {
return { type, message: input };
}
else {
return input;
}
}
getStrategyName(nameOrInstance) {
if (typeof nameOrInstance === 'string') {
return nameOrInstance;
}
else if (nameOrInstance.name) {
return nameOrInstance.name;
}
else {
return nameOrInstance.constructor.name;
}
}
getStrategy(nameOrInstance) {
if (typeof nameOrInstance === 'string') {
const prototype = this.authenticator.strategy(nameOrInstance);
if (!prototype) {
throw new Error(`Unknown authentication strategy ${nameOrInstance}, no strategy with this name has been registered.`);
}
return prototype;
}
else {
return nameOrInstance;
}
}
}
exports.AuthenticationRoute = AuthenticationRoute;
45 changes: 45 additions & 0 deletions src/Authenticator.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { FastifyPluginAsync, FastifyRequest, RouteHandlerMethod } from 'fastify';
import { AuthenticateCallback, AuthenticateOptions } from './AuthenticationRoute';
import { SecureSessionManager } from './session-managers/SecureSessionManager';
import { AnyStrategy, Strategy } from './strategies';
export type SerializeFunction<User = any, SerializedUser = any> = (user: User, req: FastifyRequest) => Promise<SerializedUser>;
export type DeserializeFunction<SerializedUser = any, User = any> = (serialized: SerializedUser, req: FastifyRequest) => Promise<User>;
export type InfoTransformerFunction = (info: any) => Promise<any>;
export interface AuthenticatorOptions {
key?: string;
userProperty?: string;
clearSessionOnLogin?: boolean;
clearSessionIgnoreFields?: string[];
}
export declare class Authenticator {
key: string;
userProperty: string;
sessionManager: SecureSessionManager;
private strategies;
private serializers;
private deserializers;
private infoTransformers;
private clearSessionOnLogin;
private clearSessionIgnoreFields;
constructor(options?: AuthenticatorOptions);
use(strategy: AnyStrategy): this;
use(name: string, strategy: AnyStrategy): this;
unuse(name: string): this;
initialize(): FastifyPluginAsync;
authenticate<StrategyOrStrategies extends string | Strategy | (string | Strategy)[]>(strategy: StrategyOrStrategies, callback?: AuthenticateCallback<StrategyOrStrategies>): RouteHandlerMethod;
authenticate<StrategyOrStrategies extends string | Strategy | (string | Strategy)[]>(strategy: StrategyOrStrategies, options?: AuthenticateOptions): RouteHandlerMethod;
authenticate<StrategyOrStrategies extends string | Strategy | (string | Strategy)[]>(strategy: StrategyOrStrategies, options?: AuthenticateOptions, callback?: AuthenticateCallback<StrategyOrStrategies>): RouteHandlerMethod;
authorize<StrategyOrStrategies extends string | Strategy | (string | Strategy)[]>(strategy: StrategyOrStrategies, callback?: AuthenticateCallback<StrategyOrStrategies>): RouteHandlerMethod;
authorize<StrategyOrStrategies extends string | Strategy | (string | Strategy)[]>(strategy: StrategyOrStrategies, options?: AuthenticateOptions): RouteHandlerMethod;
authorize<StrategyOrStrategies extends string | Strategy | (string | Strategy)[]>(strategy: StrategyOrStrategies, options?: AuthenticateOptions, callback?: AuthenticateCallback<StrategyOrStrategies>): RouteHandlerMethod;
secureSession(options?: AuthenticateOptions): FastifyPluginAsync;
registerUserSerializer<User, StoredUser>(fn: SerializeFunction<User, StoredUser>): void;
serializeUser<User, StoredUser = any>(user: User, request: FastifyRequest): Promise<StoredUser>;
registerUserDeserializer<StoredUser, User>(fn: DeserializeFunction<StoredUser, User>): void;
deserializeUser<StoredUser>(stored: StoredUser, request: FastifyRequest): Promise<StoredUser | false>;
registerAuthInfoTransformer(fn: InfoTransformerFunction): void;
transformAuthInfo(info: any, request: FastifyRequest): Promise<any>;
strategy(name: string): AnyStrategy | undefined;
private runStack;
}
export default Authenticator;
Loading

0 comments on commit b19ffb3

Please sign in to comment.