UNPKG

@ngx-addons/omni-auth-core

Version:

Core library for authentication in Angular applications.

301 lines (286 loc) 11.9 kB
import * as i0 from '@angular/core'; import { signal, Injectable, inject, computed, Pipe, InjectionToken } from '@angular/core'; import { from, switchMap, skipWhile, map, take } from 'rxjs'; import { createUrlTreeFromSnapshot, Router } from '@angular/router'; import { toObservable } from '@angular/core/rxjs-interop'; class ActionErrorCollectorService { #currentError = signal(null, ...(ngDevMode ? [{ debugName: "#currentError" }] : [])); currentError = this.#currentError; reset() { this.#currentError.set(null); } handle(error) { this.#currentError.set(error); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: ActionErrorCollectorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: ActionErrorCollectorService, providedIn: 'root' }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: ActionErrorCollectorService, decorators: [{ type: Injectable, args: [{ providedIn: 'root', }] }] }); class ErrorMessagePipe { #collector = inject(ActionErrorCollectorService); transform(source, messages) { return computed(() => { const error = this.#collector.currentError(); if (!error) { return null; } if (error.source !== source) { return null; } if (error.silent) { return null; } return messages[error.code] ?? messages.unknown; }); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: ErrorMessagePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.1.4", ngImport: i0, type: ErrorMessagePipe, isStandalone: true, name: "errorMessage" }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: ErrorMessagePipe, decorators: [{ type: Pipe, args: [{ name: 'errorMessage', standalone: true }] }] }); class OmniAuthError { error; constructor(error) { this.error = error; } getErrorMessage() { return this.error instanceof Error ? this.error.message : 'Unknown error'; } } class RuntimeError extends OmniAuthError { error; possibleSolution; constructor(error, possibleSolution) { super(error); this.error = error; this.possibleSolution = possibleSolution; } } class FlowError extends OmniAuthError { source; code; error; silent; constructor(source, code, error, silent = false) { super(error); this.source = source; this.code = code; this.error = error; this.silent = silent; } } /** * Defines common patterns used for validation in the OmniAuth Core library. * * These patterns are used for validating passwords and email addresses. */ const passwordPattern = /^(?!\s+)(?!.*\s+$)(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[$^*.[\]{}()?"!@#%&/\\,><':;|_~`=+\- ])[A-Za-z0-9$^*.[\]{}()?"!@#%&/\\,><':;|_~`=+\- ]{8,256}$/; const emailPattern = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|.(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; var patterns$1 = /*#__PURE__*/Object.freeze({ __proto__: null, emailPattern: emailPattern, passwordPattern: passwordPattern }); const isError = (response) => { return response instanceof OmniAuthError; }; class OmniAuthService { } const AUTH_CONFIG = new InjectionToken('AUTH_CONFIG'); const configureAuth = (params) => { return [ { provide: OmniAuthService, useClass: params.authService, }, { provide: AUTH_CONFIG, useValue: params, }, ]; }; const jwtInterceptor = (request, next) => { const config = inject(AUTH_CONFIG); const authService = inject(OmniAuthService); const bearerConfig = config.bearerAuthentication; if (bearerConfig?.whitelistedEndpoints?.length) { const whiteListed = bearerConfig?.whitelistedEndpoints.find((url) => { if (url instanceof RegExp) { return url.test(request.url); } return request.url.includes(url); }); if (!whiteListed) { return next(request.clone()); } } const token$ = from(authService.getToken()); return token$.pipe(switchMap((token) => { if (!token) { return next(request.clone()); } let headers = request.headers; headers = headers.append(bearerConfig?.headerName ?? 'Authorization', `${bearerConfig?.headerValuePrefix ?? 'Bearer '}${token}`); const newReq = request.clone({ headers }); return next(newReq); })); }; const defaultContent = { loggedIn: { welcomeMessage: 'Welcome back, {{displayName}}!', welcomeMessageNoDisplayName: 'Welcome back!', }, common: { emailLabel: 'Email', passwordLabel: 'Password', nameLabel: 'Name', nameErrorRequiredText: 'Name is required', nameErrorMinLengthText: 'Name needs to be at least 2 characters long', namePlaceholder: 'Joe Doe', emailErrorRequiredText: 'Email is required', emailErrorPatternText: 'Email is invalid', emailPlaceholder: 'joe.doe@example.com', passwordErrorRequiredText: 'Password is required', passwordErrorMinLengthText: 'Password needs to be at least 8 characters long', passwordPatternText: 'Password must contain at least 8 characters, one uppercase letter,' + ' one lowercase letter, one number and one special character', passwordPlaceholder: '********', codeLabel: 'Code', codeErrorRequiredText: 'Code is required', codePlaceholder: '000000', backToSignInLabel: 'Back to login', icons: { back: 'chevron_backward', email: 'email', }, }, signIn: { title: 'Login', errorSubmitMessage: 'Error while signing in', submitLabel: 'Login', forgetPassword: 'I forgot my password', }, signUp: { title: 'Register', errorSubmitMessage: 'Error while signing up', submitLabel: 'Create account', termsAndConditionsText: 'By continuing, you agree to our', termsAndConditionsLinkText: 'Terms and Conditions', }, confirmationSignUp: { subTitle: 'Confirm your e-mail address', paragraph: 'A confirmation e-mail has been sent.\n' + 'Check your inbox and write the code below to confirm your e-mail address.', errorSubmitMessage: 'Error while signing up', submitLabel: 'Verify', resendLabel: 'Resend code', errorResendMessage: 'Error while resending code', }, resetPassword: { title: 'Confirmation code', sendCodeMessage: 'Enter the e-mail address you used to sign up, we will send you a code to reset your password.', providePasswordMessage: 'Enter code and new password', repeatPassword: 'Repeat password', errorSubmitMessage: 'Error while resetting password', errorSendCodeMessage: 'Error while sending code', sendCodeLabel: 'Send code', submitLabel: 'Reset password', }, socialButtons: { orLine: 'or use one of these options', signInWithGoogle: 'Sign in with Google', signInWithApple: 'Sign in with Apple', signInWithFacebook: 'Sign in with Facebook', }, errors: { invalidCode: 'Provided code is invalid', usernameNotFound: 'Username not found', incorrectUsernameOrPassword: 'Password or email is incorrect', userDoesNotExist: 'User does not exist', alreadySignedIn: 'You are already signed in', signInWithRedirectFailure: 'Sign in using external provider failed', invalidConfiguration: 'Missing or invalid configuration, see console for details', cancelledFlow: 'Flow was cancelled by user', unknown: 'An unknown error occurred', }, }; /** * @description Guard that checks if the user is authenticated user otherwise redirects to the specified route. * @param config */ const onlyAuthenticated = (config) => (route) => { const authService = inject(OmniAuthService); const libConfig = inject(AUTH_CONFIG); const loading$ = toObservable(authService.authState.isLoading); console.log('Checking authentication state...'); return loading$.pipe(skipWhile((loading) => loading), map(() => { const authenticated = authService.authState.value().state === 'authenticated'; if (!authenticated) { console.log('User is not authenticated, redirecting...', config?.redirectTo ?? libConfig.routing?.guest ?? ['/']); return createUrlTreeFromSnapshot(route, config?.redirectTo ?? libConfig.routing?.guest ?? ['/']); } console.log('User is authenticated, allowing access to the route'); return true; }), take(1)); }; /** * @description Guard that checks if the user is not authenticated otherwise redirects to the specified route. * @param config */ const onlyGuest = (config) => { return (route) => { const authService = inject(OmniAuthService); const libConfig = inject(AUTH_CONFIG); const loading$ = toObservable(authService.authState.isLoading); return loading$.pipe(skipWhile((loading) => loading), map(() => { const authenticated = authService.authState.value().state === 'authenticated'; if (authenticated) { return createUrlTreeFromSnapshot(route, config?.redirectTo ?? libConfig.routing?.secured ?? ['/']); } return true; }), take(1)); }; }; class AuthRouteService { #router = inject(Router); #env = inject(AUTH_CONFIG); currentStep = signal('login', ...(ngDevMode ? [{ debugName: "currentStep" }] : [])); currentEmail = signal(null, ...(ngDevMode ? [{ debugName: "currentEmail" }] : [])); nextStep(state, details = {}) { this.currentStep.set(state); this.currentEmail.set(details.email ?? null); } navigateToGuestPage(rememberPage = false) { // todo - implement rememberPage logic if (!this.#env.routing?.guest) { return; } return this.#router.navigate(this.#env.routing.guest); } navigateToSecuredPage() { if (!this.#env.routing?.secured) { return; } return this.#router.navigate(this.#env.routing.secured); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: AuthRouteService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: AuthRouteService, providedIn: 'root' }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: AuthRouteService, decorators: [{ type: Injectable, args: [{ providedIn: 'root', }] }] }); /** * Generated bundle index. Do not edit. */ export { AUTH_CONFIG, ActionErrorCollectorService, AuthRouteService, ErrorMessagePipe, FlowError, OmniAuthError, OmniAuthService, RuntimeError, configureAuth, defaultContent, isError, jwtInterceptor, onlyAuthenticated, onlyGuest, patterns$1 as patterns }; //# sourceMappingURL=ngx-addons-omni-auth-core.mjs.map