github.com/dbernstein1/tyk@v2.9.0-beta9-dl-apic+incompatible/gateway/mw_js_plugin.go (about)

     1  package gateway
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/tls"
     6  	"encoding/base64"
     7  	"encoding/json"
     8  	"errors"
     9  	"io/ioutil"
    10  	"net/http"
    11  	"net/url"
    12  	"os"
    13  	"path/filepath"
    14  	"reflect"
    15  	"strings"
    16  	"time"
    17  
    18  	"github.com/robertkrimen/otto"
    19  	_ "github.com/robertkrimen/otto/underscore"
    20  
    21  	"github.com/TykTechnologies/tyk/config"
    22  	"github.com/TykTechnologies/tyk/user"
    23  
    24  	"github.com/sirupsen/logrus"
    25  )
    26  
    27  // Lets the user override and return a response from middleware
    28  type ReturnOverrides struct {
    29  	ResponseCode    int
    30  	ResponseError   string
    31  	ResponseHeaders map[string]string
    32  }
    33  
    34  // MiniRequestObject is marshalled to JSON string and passed into JSON middleware
    35  type MiniRequestObject struct {
    36  	Headers         map[string][]string
    37  	SetHeaders      map[string]string
    38  	DeleteHeaders   []string
    39  	Body            []byte
    40  	URL             string
    41  	Params          map[string][]string
    42  	AddParams       map[string]string
    43  	ExtendedParams  map[string][]string
    44  	DeleteParams    []string
    45  	ReturnOverrides ReturnOverrides
    46  	IgnoreBody      bool
    47  	Method          string
    48  	RequestURI      string
    49  	Scheme          string
    50  }
    51  
    52  type VMReturnObject struct {
    53  	Request     MiniRequestObject
    54  	SessionMeta map[string]string
    55  	Session     user.SessionState
    56  	AuthValue   string
    57  }
    58  
    59  // DynamicMiddleware is a generic middleware that will execute JS code before continuing
    60  type DynamicMiddleware struct {
    61  	BaseMiddleware
    62  	MiddlewareClassName string
    63  	Pre                 bool
    64  	UseSession          bool
    65  	Auth                bool
    66  }
    67  
    68  func (d *DynamicMiddleware) Name() string {
    69  	return "DynamicMiddleware"
    70  }
    71  
    72  func specToJson(spec *APISpec) string {
    73  	m := map[string]interface{}{
    74  		"OrgID": spec.OrgID,
    75  		"APIID": spec.APIID,
    76  		// For backwards compatibility within 2.x.
    77  		// TODO: simplify or refactor in 3.x or later.
    78  		"config_data": spec.ConfigData,
    79  	}
    80  	bs, err := json.Marshal(m)
    81  	if err != nil {
    82  		log.Error("Failed to encode configuration data: ", err)
    83  		return ""
    84  	}
    85  	return string(bs)
    86  }
    87  
    88  // ProcessRequest will run any checks on the request on the way through the system, return an error to have the chain fail
    89  func (d *DynamicMiddleware) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
    90  	t1 := time.Now().UnixNano()
    91  	logger := d.Logger()
    92  
    93  	// Create the proxy object
    94  	originalBody, err := ioutil.ReadAll(r.Body)
    95  	if err != nil {
    96  		logger.WithError(err).Error("Failed to read request body")
    97  		return nil, http.StatusOK
    98  	}
    99  	defer r.Body.Close()
   100  
   101  	headers := r.Header
   102  	host := r.Host
   103  	if host == "" && r.URL != nil {
   104  		host = r.URL.Host
   105  	}
   106  	if host != "" {
   107  		headers = make(http.Header)
   108  		for k, v := range r.Header {
   109  			headers[k] = v
   110  		}
   111  		headers.Set("Host", host)
   112  	}
   113  	scheme := "http"
   114  	if r.TLS != nil {
   115  		scheme = "https"
   116  	}
   117  
   118  	requestData := MiniRequestObject{
   119  		Headers:        headers,
   120  		SetHeaders:     map[string]string{},
   121  		DeleteHeaders:  []string{},
   122  		Body:           originalBody,
   123  		URL:            r.URL.String(),
   124  		Params:         r.URL.Query(),
   125  		AddParams:      map[string]string{},
   126  		ExtendedParams: map[string][]string{},
   127  		DeleteParams:   []string{},
   128  		Method:         r.Method,
   129  		RequestURI:     r.RequestURI,
   130  		Scheme:         scheme,
   131  	}
   132  
   133  	requestAsJson, err := json.Marshal(requestData)
   134  	if err != nil {
   135  		logger.WithError(err).Error("Failed to encode request object for dynamic middleware")
   136  		return nil, http.StatusOK
   137  	}
   138  
   139  	specAsJson := specToJson(d.Spec)
   140  
   141  	session := new(user.SessionState)
   142  
   143  	// Encode the session object (if not a pre-process)
   144  	if !d.Pre && d.UseSession {
   145  		session = ctxGetSession(r)
   146  	}
   147  
   148  	sessionAsJson, err := json.Marshal(session)
   149  	if err != nil {
   150  		logger.WithError(err).Error("Failed to encode session for VM")
   151  		return nil, http.StatusOK
   152  	}
   153  
   154  	// Run the middleware
   155  	middlewareClassname := d.MiddlewareClassName
   156  	vm := d.Spec.JSVM.VM.Copy()
   157  	vm.Interrupt = make(chan func(), 1)
   158  	logger.Debug("Running: ", middlewareClassname)
   159  	// buffered, leaving no chance of a goroutine leak since the
   160  	// spawned goroutine will send 0 or 1 values.
   161  	ret := make(chan otto.Value, 1)
   162  	errRet := make(chan error, 1)
   163  	go func() {
   164  		defer func() {
   165  			// the VM executes the panic func that gets it
   166  			// to stop, so we must recover here to not crash
   167  			// the whole Go program.
   168  			recover()
   169  		}()
   170  		returnRaw, err := vm.Run(middlewareClassname + `.DoProcessRequest(` + string(requestAsJson) + `, ` + string(sessionAsJson) + `, ` + specAsJson + `);`)
   171  		ret <- returnRaw
   172  		errRet <- err
   173  	}()
   174  	var returnRaw otto.Value
   175  	t := time.NewTimer(d.Spec.JSVM.Timeout)
   176  	select {
   177  	case returnRaw = <-ret:
   178  		if err := <-errRet; err != nil {
   179  			logger.WithError(err).Error("Failed to run JS middleware")
   180  			return nil, http.StatusOK
   181  		}
   182  		t.Stop()
   183  	case <-t.C:
   184  		t.Stop()
   185  		logger.Error("JS middleware timed out after ", d.Spec.JSVM.Timeout)
   186  		vm.Interrupt <- func() {
   187  			// only way to stop the VM is to send it a func
   188  			// that panics.
   189  			panic("stop")
   190  		}
   191  		return nil, http.StatusOK
   192  	}
   193  	returnDataStr, _ := returnRaw.ToString()
   194  
   195  	// Decode the return object
   196  	newRequestData := VMReturnObject{}
   197  	if err := json.Unmarshal([]byte(returnDataStr), &newRequestData); err != nil {
   198  		logger.WithError(err).Error("Failed to decode middleware request data on return from VM. Returned data: ", returnDataStr)
   199  		return nil, http.StatusOK
   200  	}
   201  
   202  	// Reconstruct the request parts
   203  	if newRequestData.Request.IgnoreBody {
   204  		r.ContentLength = int64(len(originalBody))
   205  		r.Body = ioutil.NopCloser(bytes.NewReader(originalBody))
   206  	} else {
   207  		r.ContentLength = int64(len(newRequestData.Request.Body))
   208  		r.Body = ioutil.NopCloser(bytes.NewReader(newRequestData.Request.Body))
   209  	}
   210  
   211  	r.URL, err = url.ParseRequestURI(newRequestData.Request.URL)
   212  	if err != nil {
   213  		return nil, http.StatusOK
   214  	}
   215  
   216  	// Delete and set headers
   217  	for _, dh := range newRequestData.Request.DeleteHeaders {
   218  		r.Header.Del(dh)
   219  	}
   220  
   221  	for h, v := range newRequestData.Request.SetHeaders {
   222  		r.Header.Set(h, v)
   223  	}
   224  
   225  	// Delete and set request parameters
   226  	values := r.URL.Query()
   227  	for _, k := range newRequestData.Request.DeleteParams {
   228  		values.Del(k)
   229  	}
   230  
   231  	for p, v := range newRequestData.Request.AddParams {
   232  		values.Set(p, v)
   233  	}
   234  
   235  	for p, v := range newRequestData.Request.ExtendedParams {
   236  		for _, val := range v {
   237  			values.Add(p, val)
   238  		}
   239  	}
   240  
   241  	r.URL.RawQuery = values.Encode()
   242  
   243  	// Save the session data (if modified)
   244  	if !d.Pre && d.UseSession {
   245  		newMeta := mapStrsToIfaces(newRequestData.SessionMeta)
   246  		if !reflect.DeepEqual(session.MetaData, newMeta) {
   247  			session.MetaData = newMeta
   248  			ctxScheduleSessionUpdate(r)
   249  		}
   250  	}
   251  
   252  	logger.Debug("JSVM middleware execution took: (ns) ", time.Now().UnixNano()-t1)
   253  
   254  	if newRequestData.Request.ReturnOverrides.ResponseCode >= http.StatusBadRequest {
   255  		return errors.New(newRequestData.Request.ReturnOverrides.ResponseError), newRequestData.Request.ReturnOverrides.ResponseCode
   256  	}
   257  
   258  	if newRequestData.Request.ReturnOverrides.ResponseCode != 0 {
   259  		responseObject := VMResponseObject{
   260  			Response: ResponseObject{
   261  				Body:    newRequestData.Request.ReturnOverrides.ResponseError,
   262  				Code:    newRequestData.Request.ReturnOverrides.ResponseCode,
   263  				Headers: newRequestData.Request.ReturnOverrides.ResponseHeaders,
   264  			},
   265  		}
   266  
   267  		forceResponse(w, r, &responseObject, d.Spec, session, d.Pre, logger)
   268  		return nil, mwStatusRespond
   269  	}
   270  
   271  	if d.Auth {
   272  		ctxSetSession(r, &newRequestData.Session, newRequestData.AuthValue, true)
   273  	}
   274  
   275  	return nil, http.StatusOK
   276  }
   277  
   278  func mapStrsToIfaces(m map[string]string) map[string]interface{} {
   279  	// TODO: do we really need this conversion? note that we can't
   280  	// make user.SessionState.MetaData a map[string]string, however.
   281  	m2 := make(map[string]interface{}, len(m))
   282  	for k, v := range m {
   283  		m2[k] = v
   284  	}
   285  	return m2
   286  }
   287  
   288  // --- Utility functions during startup to ensure a sane VM is present for each API Def ----
   289  
   290  type JSVM struct {
   291  	Spec    *APISpec
   292  	VM      *otto.Otto
   293  	Timeout time.Duration
   294  	Log     *logrus.Entry  // logger used by the JS code
   295  	RawLog  *logrus.Logger // logger used by `rawlog` func to avoid formatting
   296  }
   297  
   298  const defaultJSVMTimeout = 5
   299  
   300  // Init creates the JSVM with the core library and sets up a default
   301  // timeout.
   302  func (j *JSVM) Init(spec *APISpec, logger *logrus.Entry) {
   303  	vm := otto.New()
   304  	logger = logger.WithField("prefix", "jsvm")
   305  
   306  	// Init TykJS namespace, constructors etc.
   307  	if _, err := vm.Run(coreJS); err != nil {
   308  		logger.WithError(err).Error("Could not load TykJS")
   309  		return
   310  	}
   311  
   312  	// Load user's TykJS on top, if any
   313  	if path := config.Global().TykJSPath; path != "" {
   314  		f, err := os.Open(path)
   315  		if err == nil {
   316  			_, err = vm.Run(f)
   317  			f.Close()
   318  
   319  			if err != nil {
   320  				logger.WithError(err).Error("Could not load user's TykJS")
   321  			}
   322  		}
   323  	}
   324  
   325  	j.VM = vm
   326  	j.Spec = spec
   327  
   328  	// Add environment API
   329  	j.LoadTykJSApi()
   330  
   331  	if jsvmTimeout := config.Global().JSVMTimeout; jsvmTimeout <= 0 {
   332  		j.Timeout = time.Duration(defaultJSVMTimeout) * time.Second
   333  		logger.Debugf("Default JSVM timeout used: %v", j.Timeout)
   334  	} else {
   335  		j.Timeout = time.Duration(jsvmTimeout) * time.Second
   336  		logger.Debugf("Custom JSVM timeout: %v", j.Timeout)
   337  	}
   338  
   339  	j.Log = logger // use the global logger by default
   340  	j.RawLog = rawLog
   341  }
   342  
   343  // LoadJSPaths will load JS classes and functionality in to the VM by file
   344  func (j *JSVM) LoadJSPaths(paths []string, prefix string) {
   345  	for _, mwPath := range paths {
   346  		if prefix != "" {
   347  			mwPath = filepath.Join(prefix, mwPath)
   348  		}
   349  		j.Log.Info("Loading JS File: ", mwPath)
   350  		f, err := os.Open(mwPath)
   351  		if err != nil {
   352  			j.Log.WithError(err).Error("Failed to open JS middleware file")
   353  			continue
   354  		}
   355  		if _, err := j.VM.Run(f); err != nil {
   356  			j.Log.WithError(err).Error("Failed to load JS middleware")
   357  		}
   358  		f.Close()
   359  	}
   360  }
   361  
   362  type TykJSHttpRequest struct {
   363  	Method   string
   364  	Body     string
   365  	Headers  map[string]string
   366  	Domain   string
   367  	Resource string
   368  	FormData map[string]string
   369  }
   370  
   371  type TykJSHttpResponse struct {
   372  	Code    int
   373  	Body    string
   374  	Headers map[string][]string
   375  
   376  	// Make this compatible with BatchReplyUnit
   377  	CodeComp    int                 `json:"code"`
   378  	BodyComp    string              `json:"body"`
   379  	HeadersComp map[string][]string `json:"headers"`
   380  }
   381  
   382  func (j *JSVM) LoadTykJSApi() {
   383  	// Enable a log
   384  	j.VM.Set("log", func(call otto.FunctionCall) otto.Value {
   385  		j.Log.WithFields(logrus.Fields{
   386  			"type": "log-msg",
   387  		}).Info(call.Argument(0).String())
   388  		return otto.Value{}
   389  	})
   390  	j.VM.Set("rawlog", func(call otto.FunctionCall) otto.Value {
   391  		j.RawLog.Print(call.Argument(0).String() + "\n")
   392  		return otto.Value{}
   393  	})
   394  
   395  	// these two needed for non-utf8 bodies
   396  	j.VM.Set("b64dec", func(call otto.FunctionCall) otto.Value {
   397  		in := call.Argument(0).String()
   398  		out, err := base64.StdEncoding.DecodeString(in)
   399  
   400  		// Fallback to RawStdEncoding:
   401  		if err != nil {
   402  			out, err = base64.RawStdEncoding.DecodeString(in)
   403  			if err != nil {
   404  				j.Log.WithError(err).Error("Failed to base64 decode")
   405  				return otto.Value{}
   406  			}
   407  		}
   408  		returnVal, err := j.VM.ToValue(string(out))
   409  		if err != nil {
   410  			j.Log.WithError(err).Error("Failed to base64 decode")
   411  			return otto.Value{}
   412  		}
   413  		return returnVal
   414  	})
   415  	j.VM.Set("b64enc", func(call otto.FunctionCall) otto.Value {
   416  		in := []byte(call.Argument(0).String())
   417  		out := base64.StdEncoding.EncodeToString(in)
   418  		returnVal, err := j.VM.ToValue(out)
   419  		if err != nil {
   420  			j.Log.WithError(err).Error("Failed to base64 encode")
   421  			return otto.Value{}
   422  		}
   423  		return returnVal
   424  	})
   425  
   426  	j.VM.Set("rawb64dec", func(call otto.FunctionCall) otto.Value {
   427  		in := call.Argument(0).String()
   428  		out, err := base64.RawStdEncoding.DecodeString(in)
   429  		if err != nil {
   430  			if err != nil {
   431  				j.Log.WithError(err).Error("Failed to base64 decode")
   432  				return otto.Value{}
   433  			}
   434  		}
   435  		returnVal, err := j.VM.ToValue(string(out))
   436  		if err != nil {
   437  			j.Log.WithError(err).Error("Failed to base64 decode")
   438  			return otto.Value{}
   439  		}
   440  		return returnVal
   441  	})
   442  	j.VM.Set("rawb64enc", func(call otto.FunctionCall) otto.Value {
   443  		in := []byte(call.Argument(0).String())
   444  		out := base64.RawStdEncoding.EncodeToString(in)
   445  		returnVal, err := j.VM.ToValue(out)
   446  		if err != nil {
   447  			j.Log.WithError(err).Error("Failed to base64 encode")
   448  			return otto.Value{}
   449  		}
   450  		return returnVal
   451  	})
   452  
   453  	// Enable the creation of HTTP Requsts
   454  	j.VM.Set("TykMakeHttpRequest", func(call otto.FunctionCall) otto.Value {
   455  		jsonHRO := call.Argument(0).String()
   456  		if jsonHRO == "undefined" {
   457  			// Nope, return nothing
   458  			return otto.Value{}
   459  		}
   460  		hro := TykJSHttpRequest{}
   461  		if err := json.Unmarshal([]byte(jsonHRO), &hro); err != nil {
   462  			j.Log.WithError(err).Error("JSVM: Failed to deserialise HTTP Request object")
   463  			return otto.Value{}
   464  		}
   465  
   466  		// Make the request
   467  		domain := hro.Domain
   468  		data := url.Values{}
   469  		for k, v := range hro.FormData {
   470  			data.Set(k, v)
   471  		}
   472  
   473  		u, _ := url.ParseRequestURI(domain + hro.Resource)
   474  		urlStr := u.String() // "https://api.com/user/"
   475  
   476  		var d string
   477  		if hro.Body != "" {
   478  			d = hro.Body
   479  		} else if len(hro.FormData) > 0 {
   480  			d = data.Encode()
   481  		}
   482  
   483  		r, _ := http.NewRequest(hro.Method, urlStr, nil)
   484  
   485  		if d != "" {
   486  			r, _ = http.NewRequest(hro.Method, urlStr, strings.NewReader(d))
   487  		}
   488  
   489  		for k, v := range hro.Headers {
   490  			r.Header.Set(k, v)
   491  		}
   492  		r.Close = true
   493  
   494  		tr := &http.Transport{TLSClientConfig: &tls.Config{}}
   495  		if cert := getUpstreamCertificate(r.Host, j.Spec); cert != nil {
   496  			tr.TLSClientConfig.Certificates = []tls.Certificate{*cert}
   497  		}
   498  
   499  		if config.Global().ProxySSLInsecureSkipVerify {
   500  			tr.TLSClientConfig.InsecureSkipVerify = true
   501  		}
   502  
   503  		if j.Spec.Proxy.Transport.SSLInsecureSkipVerify {
   504  			tr.TLSClientConfig.InsecureSkipVerify = true
   505  		}
   506  
   507  		tr.DialTLS = dialTLSPinnedCheck(j.Spec, tr.TLSClientConfig)
   508  
   509  		tr.Proxy = proxyFromAPI(j.Spec)
   510  
   511  		// using new Client each time should be ok, since we closing connection every time
   512  		client := &http.Client{Transport: tr}
   513  		resp, err := client.Do(r)
   514  		if err != nil {
   515  			j.Log.WithError(err).Error("Request failed")
   516  			return otto.Value{}
   517  		}
   518  
   519  		body, _ := ioutil.ReadAll(resp.Body)
   520  		bodyStr := string(body)
   521  		tykResp := TykJSHttpResponse{
   522  			Code:        resp.StatusCode,
   523  			Body:        bodyStr,
   524  			Headers:     resp.Header,
   525  			CodeComp:    resp.StatusCode,
   526  			BodyComp:    bodyStr,
   527  			HeadersComp: resp.Header,
   528  		}
   529  
   530  		retAsStr, _ := json.Marshal(tykResp)
   531  		returnVal, err := j.VM.ToValue(string(retAsStr))
   532  		if err != nil {
   533  			j.Log.WithError(err).Error("Failed to encode return value")
   534  			return otto.Value{}
   535  		}
   536  
   537  		return returnVal
   538  	})
   539  
   540  	// Expose Setters and Getters in the REST API for a key:
   541  	j.VM.Set("TykGetKeyData", func(call otto.FunctionCall) otto.Value {
   542  		apiKey := call.Argument(0).String()
   543  		apiId := call.Argument(1).String()
   544  
   545  		obj, _ := handleGetDetail(apiKey, apiId, false)
   546  		bs, _ := json.Marshal(obj)
   547  
   548  		returnVal, err := j.VM.ToValue(string(bs))
   549  		if err != nil {
   550  			j.Log.WithError(err).Error("Failed to encode return value")
   551  			return otto.Value{}
   552  		}
   553  
   554  		return returnVal
   555  	})
   556  
   557  	j.VM.Set("TykSetKeyData", func(call otto.FunctionCall) otto.Value {
   558  		apiKey := call.Argument(0).String()
   559  		encoddedSession := call.Argument(1).String()
   560  		suppressReset := call.Argument(2).String()
   561  
   562  		newSession := user.SessionState{}
   563  		err := json.Unmarshal([]byte(encoddedSession), &newSession)
   564  		if err != nil {
   565  			j.Log.WithError(err).Error("Failed to decode the sesison data")
   566  			return otto.Value{}
   567  		}
   568  
   569  		doAddOrUpdate(apiKey, &newSession, suppressReset == "1", false)
   570  
   571  		return otto.Value{}
   572  	})
   573  
   574  	// Batch request method
   575  	unsafeBatchHandler := BatchRequestHandler{}
   576  	j.VM.Set("TykBatchRequest", func(call otto.FunctionCall) otto.Value {
   577  		requestSet := call.Argument(0).String()
   578  		j.Log.Debug("Batch input is: ", requestSet)
   579  
   580  		bs, err := unsafeBatchHandler.ManualBatchRequest([]byte(requestSet))
   581  		if err != nil {
   582  			j.Log.WithError(err).Error("Batch request error")
   583  			return otto.Value{}
   584  		}
   585  
   586  		returnVal, err := j.VM.ToValue(string(bs))
   587  		if err != nil {
   588  			j.Log.WithError(err).Error("Failed to encode return value")
   589  			return otto.Value{}
   590  		}
   591  
   592  		return returnVal
   593  	})
   594  
   595  	j.VM.Run(`function TykJsResponse(response, session_meta) {
   596  		return JSON.stringify({Response: response, SessionMeta: session_meta})
   597  	}`)
   598  }
   599  
   600  const coreJS = `
   601  var TykJS = {
   602  	TykMiddleware: {
   603  		MiddlewareComponentMeta: function(configuration) {
   604  			this.configuration = configuration
   605  		}
   606  	},
   607  	TykEventHandlers: {
   608  		EventHandlerComponentMeta: function() {}
   609  	}
   610  }
   611  
   612  TykJS.TykMiddleware.MiddlewareComponentMeta.prototype.ProcessRequest = function(request, session, config) {
   613  	log("Process Request Not Implemented")
   614  	return request
   615  }
   616  
   617  TykJS.TykMiddleware.MiddlewareComponentMeta.prototype.DoProcessRequest = function(request, session, config) {
   618  	request.Body = b64dec(request.Body)
   619  	var processed_request = this.ProcessRequest(request, session, config)
   620  
   621  	if (!processed_request) {
   622  		log("Middleware didn't return request object!")
   623  		return
   624  	}
   625  
   626  	// Reset the headers object
   627  	processed_request.Request.Headers = {}
   628  	processed_request.Request.Body = b64enc(processed_request.Request.Body)
   629  
   630  	return JSON.stringify(processed_request)
   631  }
   632  
   633  // The user-level middleware component
   634  TykJS.TykMiddleware.NewMiddleware = function(configuration) {
   635  	TykJS.TykMiddleware.MiddlewareComponentMeta.call(this, configuration)
   636  }
   637  
   638  // Set up object inheritance
   639  TykJS.TykMiddleware.NewMiddleware.prototype = Object.create(TykJS.TykMiddleware.MiddlewareComponentMeta.prototype)
   640  TykJS.TykMiddleware.NewMiddleware.prototype.constructor = TykJS.TykMiddleware.NewMiddleware
   641  
   642  TykJS.TykMiddleware.NewMiddleware.prototype.NewProcessRequest = function(callback) {
   643  	this.ProcessRequest = callback
   644  }
   645  
   646  TykJS.TykMiddleware.NewMiddleware.prototype.ReturnData = function(request, session) {
   647  	return {Request: request, SessionMeta: session}
   648  }
   649  
   650  TykJS.TykMiddleware.NewMiddleware.prototype.ReturnAuthData = function(request, session) {
   651  	return {Request: request, Session: session}
   652  }
   653  
   654  // Event Handler implementation
   655  
   656  TykJS.TykEventHandlers.EventHandlerComponentMeta.prototype.DoProcessEvent = function(event, context) {
   657  	// call the handler
   658  	log("Calling built - in handle")
   659  	this.Handle(event, context)
   660  	return
   661  }
   662  
   663  TykJS.TykEventHandlers.EventHandlerComponentMeta.prototype.Handle = function(request, context) {
   664  	log("Handler not implemented!")
   665  	return request
   666  }
   667  
   668  // The user-level event handler component
   669  TykJS.TykEventHandlers.NewEventHandler = function() {
   670  	TykJS.TykEventHandlers.EventHandlerComponentMeta.call(this)
   671  }
   672  
   673  // Set up object inheritance for events
   674  TykJS.TykEventHandlers.NewEventHandler.prototype = Object.create(TykJS.TykEventHandlers.EventHandlerComponentMeta.prototype)
   675  TykJS.TykEventHandlers.NewEventHandler.prototype.constructor = TykJS.TykEventHandlers.NewEventHandler
   676  
   677  TykJS.TykEventHandlers.NewEventHandler.prototype.NewHandler = function(callback) {
   678  	this.Handle = callback
   679  };`