OptimalBits / redbird

A modern reverse proxy for node
BSD 2-Clause "Simplified" License
4.4k stars 279 forks source link

TypeError: Cannot read property 'some' of undefined #233

Open Gabbersaurus opened 4 years ago

Gabbersaurus commented 4 years ago

Had to reinstall my server and while setting up the proxy I got this error:

TypeError: Cannot read property 'some' of undefined at /opt/server/proxy/node_modules/acme-v2/index.js:1219:30 at processTicksAndRejections (internal/process/task_queues.js:93:5) {"name":"redbird","hostname":"arm","pid":5257,"level":50,"err":{"message":"Cannot read property 'some' of undefined","name":"TypeError","stack":"TypeError: Cannot read property 'some' of undefined\n at /opt/server/proxy/node_modules/acme-v2/index.js:1219:30\n at processTicksAndRejections (internal/process/task_queues.js:93:5)"},"msg":"Error registering LetsEncrypt certificates","time":"2019-12-18T15:36:05.256Z","v":0}

The proxy won't work on HTTPS now sadly. Is there any fix to this?

I'm running it on an ARM based Wandboard running Node 12 (but it also did not work on Node 10)

manast commented 4 years ago

with that information I am afraid it is not possible to give you any hint... 1) which version of redbird are you using? 2) do you have example code that reproduces the issue?

Gabbersaurus commented 4 years ago

Thank you for your quick response.

I tried it on the latest (0.10.0) and on 0.9.1. Both gave the exact same error. This is the current code that I use:

var proxy = require('redbird')({                                                                                                                                        
  port: 80, // http port is needed for LetsEncrypt challenge during request / renewal. Also enables automatic http->https redirection for registered https routes.     
  letsencrypt: {                                                                                                                                                       
    path: __dirname + '/certs',                                                                                                                                        
    port: 9999 // LetsEncrypt minimal web server port for handling challenges. Routed 80->9999, no need to open 9999 in firewall. Default 3000 if not defined.         
  },                                                                                                                                                                   
  ssl: {                                                                                                                                                               
    port: 443, // SSL port used to serve registered https routes with LetsEncrypt certificate.                                                                         
  }                                                                                                                                                                    
});                                                                                                                                                                    

proxy.register('x', 'x', {                                                                                         
  ssl: {                                                                                                                                                               
    letsencrypt: {                                                                                                                                                     
      email: 'x', // Domain owner/admin email                                                                                         
      production: false, // WARNING: Only use this flag when the proxy is verified to work correctly to avoid being banned!                                            
    }                                                                                                                                                                  
  }                                                                                                                                                                    
});    

(sorry, deleted my original reply because I forgot to remove my personal info)

Gabbersaurus commented 4 years ago

Downgraded to node 9 to test it and I get the same error.

{"level":30,"time":1576685909494,"pid":6572,"hostname":"arm","name":"redbird","msg":"LetsEncrypt CA trying to validate challenge /opt/server/proxy/certs/**x**/.well-known/acme-challenge/test-**x**","v":1} [acme-v2] handled(?) rejection as errback: TypeError: Cannot read property 'some' of undefined at /opt/server/proxy/node_modules/acme-v2/index.js:1219:30 at <anonymous> at process._tickCallback (internal/process/next_tick.js:182:7)

Gabbersaurus commented 4 years ago

Tried it on another Debian server where it used to work, same error.

manast commented 4 years ago

the example above is not complete, I need something I can copy paste locally and reproduce...

aschenoni commented 4 years ago

After hitting this same issue for several hours I discovered setting production: true fixes the 405 method not allowed that causes this rejection.

cmawhorter commented 4 years ago

i'm using greenlock not redbird and i'm seeing this too. something is wrong in a greenlock dependency but i haven't figured out what yet. i'd recommend pegging the greenlock version in package.json. their releases are.... flakey.

Edit: it looks like this scheduled LE change is the issue. the acme-v2 client backing greenlock (same author) hasn't been updated.

boid-com commented 4 years ago

Any updates on this?

RezaErfani67 commented 4 years ago

after i change {production:true} problem resolved... any update?

ZeusTheMighty commented 4 years ago

Downgrading to Node v11 fixed the issue for me. Below is my implementation in Typescript.

import * as Proxy from 'redbird';
const proxy = new Proxy({
  port: '80',
  letsencrypt: {
    path: __dirname + '/certs',
    port: 9999,
  },
  ssl: {
    http2: true,
    port: 443,
  },
});

and then calling it like so

proxy.register("example.com", "localhost", {
      ssl: {
        letsencrypt: {
          email: 'your@email.com',
          production: true,
        },
      },
    });

Hope I was able to help you, stranger from the future!

nbriz commented 3 years ago

i'm also having this issue.

i've tried various different ways to resolve it, including switching between prouction: true and production: false as @aschenoni mentioned, trying different versions of node (switching between various using nvm) as well as different variatons on the general config code. all that said, it's hard to share exactly what my code looks like (as i've written variations). but...

// generally speaking, it looks like this...
const proxy = require('redbird')({
  port: 80,
  letsencrypt: { path: 'certs', port: 3000 },
  ssl: { port: 443 }
})

// ..with a config that looks like this...
const config = {
  ssl: { letsencrypt: { email: 'my@email.com', production: false } }
}

// ...which i use like this...

proxy.register('firstdomain.com', `http://localhost:${port}`, config)
proxy.register('seconddomain.com', `http://localhost:${port}`, config)
// ...etc...

but despite the variations, i keep getting this redibrd error:

LetsEncrypt CA trying to validate challenge certs/mydomain.com/.well-known/acme-challenge/test-4476763e84d465b0b304b68c5157bb36-0

followed by this:

[acme-v2] handled(?) rejection as errback:
TypeError: Cannot read property 'some' of undefined
    at /root/SERVER/node_modules/acme-v2/index.js:1219:30
    at processTicksAndRejections (node:internal/process/task_queues:93:5)

which as @cmawhorter mentions, does seem to be a dependency. i edited the file referenced in the error in order to log the undefined object causing the issue, and when i did i got:

{
  type: 'urn:ietf:params:acme:error:malformed',
  detail: 'Method not allowed',
  status: 405
}

if it helps, here's the chain of redbird error messages that follow:

mattwelke commented 3 years ago

Ran into this today while putting together a minimal example from the readme and some GitHub issues. Switching to production: true got me past this error too, but resulted in me getting a different error:

{"level":30,"time":1609194195775,"pid":40765,"hostname":"redbird-test","name":"redbird","0":false,"1":"setChallenge called for 'REDACTED'","msg":"Lets encrypt debugger","v":1}
[acme-v2] handled(?) rejection as errback:
Error: [acme-v2] (E_STATE_INVALID) challenge state for 'REDACTED': 'invalid'
    at /home/REDACTED/redbird-test/node_modules/acme-v2/index.js:794:27
    at processTicksAndRejections (internal/process/task_queues.js:93:5)
{"level":50,"time":1609194217524,"pid":40765,"hostname":"redbird-test","name":"redbird","msg":"Error registering LetsEncrypt certificates","stack":"Error: [acme-v2] (E_STATE_INVALID) challenge state for 'REDACTED': 'invalid'\n    at /home/REDACTED/redbird-test/node_modules/acme-v2/index.js:794:27\n    at processTicksAndRejections (internal/process/task_queues.js:93:5)","type":"Error","v":1}
{"level":30,"time":1609194217525,"pid":40765,"hostname":"redbird-test","name":"redbird","msg":"Could not get any certs for REDACTED","v":1}

My code:

var proxy = require('redbird')({
  port: 80,
  ssl: {
    port: 443,
  },
  letsencrypt: {
    path: '/home/REDACTED/redbird/certs',
  },
});

proxy.register('REDACTED', 'http://localhost:8081', {
  ssl: {
    letsencrypt: {
      email: 'REDACTED', // Domain owner/admin email
      production: true, // WARNING: Only use this flag when the proxy is verified to work correctly to avoid being banned!
    }
  }
});

Version:

node: 14.15.3 npm: 6.14.10

EDIT:

That error was my fault. I forgot I had switched to using port 80 after learning that Let's Encrypt only supported using port 80 for the challenges. I had to unblock port 80 on my firewall. I also unblocked port 443 since I'm now using that for the HTTPS routes.

Now, I'm getting a different error:

{"level":30,"time":1609194677545,"pid":40868,"hostname":"redbird-test","name":"redbird","msg":"LetsEncrypt CA trying to validate challenge /home/REDACTED/redbird/certs/REDACTED/.well-known/acme-challenge/p0p2uG2DsUoBpDihXkgtiz2PaW5szfZyOvXStTQLcDo","v":1}
{"level":30,"time":1609194678513,"pid":40868,"hostname":"redbird-test","name":"redbird","0":false,"1":"removeChallenge called for 'REDACTED'","msg":"Lets encrypt debugger","v":1}
{"level":50,"time":1609194679275,"pid":40868,"hostname":"redbird-test","name":"redbird","code":"ERR_INVALID_ARG_TYPE","msg":"Error registering LetsEncrypt certificates","stack":"TypeError [ERR_INVALID_ARG_TYPE]: The \"data\" argument must be of type string or an instance of Buffer, TypedArray, or DataView. Received undefined\n    at writeFile (fs.js:1436:5)\n    at internal/util.js:297:30\n    at new Promise (<anonymous>)\n    at writeFile (internal/util.js:296:12)\n    at Object.stageAsync (/home/REDACTED/redbird-test/node_modules/safe-replace/index.js:65:14)\n    at Object.writeFileAsync (/home/REDACTED/redbird-test/node_modules/safe-replace/index.js:57:18)\n    at /home/REDACTED/redbird-test/node_modules/le-store-certbot/index.js:288:19","type":"Error","v":1}
{"level":30,"time":1609194679275,"pid":40868,"hostname":"redbird-test","name":"redbird","msg":"Could not get any certs for REDACTED","v":1}
{"level":50,"time":1609194689786,"pid":40868,"hostname":"redbird-test","name":"redbird","library":"SSL routines","function":"tls_post_process_client_hello","reason":"no shared cipher","code":"ERR_SSL_NO_SHARED_CIPHER","msg":"HTTPS Client  Error","stack":"Error: 139811388987264:error:1417A0C1:SSL routines:tls_post_process_client_hello:no shared cipher:../deps/openssl/openssl/ssl/statem/statem_srvr.c:2284:\n","type":"Error","v":1}

Chrome shows the error "ERR_SSL_VERSION_OR_CIPHER_MISMATCH". Looks like the cert fetching stuff is working now and it's just a matter of me getting my system set up properly to support serving the TLS certs.

EDIT 2:

Switching from Node.js 14 to 12 fixed that error. Also worth mentioning, for those reading this with the same issue, that I'm using Ubuntu 20.04.

pcnate commented 2 years ago

for me this seems to happen only when using production: false which I am using for testing and diagnosing other issues....

safe-replace.stageAsync seems to get undefined for data when trying to write the pem file (for one of the many times it is called) for some reason which breaks the save process. Certificate appears to be successfully gotten but not saved properly

https://git.coolaj86.com/coolaj86/fs-safe-replace.js/issues/2

Trace: {
  filename: '/var/www/certs/archive/mytestdomain.example.com/bundle0.pem',
  data: undefined,
  options: 'ascii'
}
    at Object.writeFileAsync (/var/www/html/proxy/node_modules/safe-replace/index.js:58:17)
    at /var/www/html/proxy/node_modules/le-store-certbot/index.js:288:19
{
  tmpname: '/var/www/certs/archive/mytestdomain.example.com/bundle0.pem.9a0b00f6cad1c731.tmp',
  filename: '/var/www/certs/archive/mytestdomain.example.com/bundle0.pem',
  data: "contents of '/var/www/certs/archive/mytestdomain.example.com/bundle0.pem' were not provided to safe-replace.\r\n" +
    `option: '"ascii"'`,
  options: 'ascii'
}