import compression from 'compression' ; import cors from 'cors' ; import buildDebug from 'debug' ; import express , { Application } from 'express' ; import RateLimit from 'express-rate-limit' ; import { HttpError } from 'http-errors' ; import _ from 'lodash' ; import AuditMiddleware from 'verdaccio-audit' ; import apiEndpoint from '@verdaccio/api' ; import { Auth , IBasicAuth } from '@verdaccio/auth' ; import { Config as AppConfig } from '@verdaccio/config' ; import { API_ERROR , HTTP_STATUS , errorUtils } from '@verdaccio/core' ; import { loadPlugin } from '@verdaccio/loaders' ; import { logger } from '@verdaccio/logger' ; import { errorReportingMiddleware , final , log } from '@verdaccio/middleware' ; import { Storage } from '@verdaccio/store' ; import { ConfigRuntime } from '@verdaccio/types' ; import { Config as IConfig , IPlugin , IPluginStorageFilter } from '@verdaccio/types' ; import webMiddleware from '@verdaccio/web' ; import { $NextFunctionVer , $RequestExtend , $ResponseExtend } from '../types/custom' ; import hookDebug from './debug' ; export interface IPluginMiddleware < T > extends IPlugin < T > { register_middlewares ( app , auth , storage ) : void ; } const debug = buildDebug ( 'verdaccio:server' ) ; const defineAPI = function ( config , storage ) : any { const auth = new Auth ( config ) ; const app = express ( ) ; const limiter = new RateLimit ( config . serverSettings . rateLimit ) ; app . set ( 'env' , process . env . NODE_ENV || 'production' ) ; app . use ( cors ( ) ) ; app . use ( limiter ) ; app . use ( log ) ; app . use ( errorReportingMiddleware ) ; app . use ( function ( req , res , next ) : void { res . setHeader ( 'X-Powered-By' , config . user_agent ) ; next ( ) ; } ) ; app . use ( compression ( ) ) ; app . get ( '/favicon.ico' , function ( req , res , next ) : void { req . url = '/-/static/favicon.png' ; next ( ) ; } ) ; if ( config . _debug ) { hookDebug ( app , config . config_path ) ; } const plugin_params = { config : config , logger : logger , } ; const plugins = loadPlugin ( config , config . middlewares , plugin_params , function ( plugin ) { return plugin . register_middlewares ; } ) ; if ( _ . isEmpty ( plugins ) ) { plugins . push ( new AuditMiddleware ( { ... config , enabled : true , strict_ssl : true } , { config , logger : logger } ) ) ; } plugins . forEach ( ( plugin ) => { plugin . register_middlewares ( app , auth , storage ) ; } ) ; app . use ( apiEndpoint ( config , auth , storage ) ) ; if ( _ . get ( config , 'web.enable' , true ) ) { app . use ( webMiddleware ( config , auth , storage ) ) ; } else { app . get ( '/' , function ( req , res , next ) { next ( errorUtils . getNotFound ( API_ERROR . WEB_DISABLED ) ) ; } ) ; } app . get ( '/*' , function ( req , res , next ) { next ( errorUtils . getNotFound ( API_ERROR . FILE_NOT_FOUND ) ) ; } ) ; app . use ( function ( err , req , res , next ) { if ( _ . isError ( err ) ) { if ( err . code === 'ECONNABORT' && res . statusCode === HTTP_STATUS . NOT_MODIFIED ) { return next ( ) ; } if ( _ . isFunction ( res . locals . report_error ) === false ) { errorReportingMiddleware ( req , res , _ . noop ) ; } res . locals . report_error ( err ) ; } else { return next ( err ) ; } } ) ; app . use ( final ) ; return app ; } ; export default ( async function ( configHash ) : Promise < any > { debug ( 'start server' ) ; const config = new AppConfig ( _ . cloneDeep ( configHash ) ) ; const plugin_params = { config : config , logger : logger , } ; const filters = loadPlugin ( config , config . filters || { } , plugin_params , ( plugin ) => plugin . filter_metadata ) ; debug ( 'loaded filter plugin' ) ; const storage = new Storage ( config ) ; try { debug ( 'storage init start' ) ; await storage . init ( config , filters ) ; debug ( 'storage init end' ) ; } catch ( err ) { logger . error ( { error : err . msg } , 'storage has failed: @{error}' ) ; throw new Error ( err ) ; } return defineAPI ( config , storage ) ; } ) ;