1

I'm trying to create a middleware that sets the user's IP to the cloudflare header it gives us, for the rest of the app. This used to work on my projects, but now for some reason, it doesn't.

When I try to navigate to the app, it gives me the following error:

TypeError: Cannot set property ip of #<IncomingMessage> which has only a getter
    at /media/chen/storage/development/urlshortener/index.ts:67:11
    at Layer.handle [as handle_request] (/media/chen/storage/development/urlshortener/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix (/media/chen/storage/development/urlshortener/node_modules/express/lib/router/index.js:317:13)
    at /media/chen/storage/development/urlshortener/node_modules/express/lib/router/index.js:284:7
    at Function.process_params (/media/chen/storage/development/urlshortener/node_modules/express/lib/router/index.js:335:12)
    at next (/media/chen/storage/development/urlshortener/node_modules/express/lib/router/index.js:275:10)
    at jsonParser (/media/chen/storage/development/urlshortener/node_modules/body-parser/lib/types/json.js:110:7)
    at Layer.handle [as handle_request] (/media/chen/storage/development/urlshortener/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix (/media/chen/storage/development/urlshortener/node_modules/express/lib/router/index.js:317:13)
    at /media/chen/storage/development/urlshortener/node_modules/express/lib/router/index.js:284:7
app.use((req, res, next) => {
  req.ip = req.header('cf-connecting-ip') || req.ip; // Line 67, which the error is mentioning
  next()
})

If I should include the rest of my code, please tell me. This is all there is except app.listen after the promise that all routes, middlewares, and express settings, are included in

I'm using Express 4.17.1

Chen
  • 107
  • 1
  • 12

1 Answers1

3

You're trying to set a request property that is defined as getter.

This throws an error when running in strict mode.

Proof:

(function() {
  'use strict';
  
  let obj = {};

  Object.defineProperty(obj, 'myProp', {
    configurable: true,
    enumerable: true,
    get: () => { return 'from getter' }
  });

  // with 'strict mode': Uncaught TypeError: Cannot set property myProp of #<Object> which has only a getter
  // without 'strict mode': executed silently and has no effect on the `myProp`.
  obj.myProp = 'explicitly set';

  // with 'strict mode': never reached
  // without 'strict mode': prints 'from getter'
  console.log(obj.myProp);
}());

You can introduce a new property on the request object, e.g. req.endUserIp and use that later in your code instead.

Since you labeled the question with TypeScript, you will probably want to extend the Request interface with new property as well.

Max Ivanov
  • 5,695
  • 38
  • 52
  • Also, `res.locals` can be used as it is provided to pass data among middleware. – Abrar Hossain Jan 09 '21 at 17:06
  • When I try to extend the request interface, Typescript keeps throwing errors when ever I try to use the property in a route or app.use, saying `Property 'realIp' does not exist on type 'Request'.ts(2339)` and I have to keep using `// @ts-expect-error` on every line i use it in. Extending the interface works perfectly, typescript just doesn't like it for whatever reason. – Chen Jan 09 '21 at 18:39
  • @AbrarHossain I will definently try to make use of that – Chen Jan 09 '21 at 18:42
  • @Flleeppyy looks like TS does not see your interface declaration. Make sure the file where you added it is included in tsconfig file. That's out of the scope of this question though, you may want to check other answers and comments on the linked SO post. Cheers. – Max Ivanov Jan 10 '21 at 14:19
  • Yep, that was the issue! I got it fixed with the question you linked, thanks! – Chen Jan 11 '21 at 19:37