Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[socketio v3] SOCKET MIDDLEWARE ISSUE - removal of socket level middleware #3678

Closed
1 of 2 tasks
p3x-robot opened this issue Nov 6, 2020 · 24 comments
Closed
1 of 2 tasks
Milestone

Comments

@p3x-robot
Copy link

p3x-robot commented Nov 6, 2020

You want to:

  • report a bug
  • request a feature

Current behaviour

Removal of this crucial middleware function on a v3 socket, now, some functions are impawssible!!!!!
Please keep this function running as it is in v2.3, it gives widely sprectum of functional programming faster to get done, if it is removal, i will stick to v2.3, but i love to upgrading, but this paradigm is facing us issues.

@p3x-robot
Copy link
Author

p3x-robot commented Nov 6, 2020

this new function is an event emitter listener. now you(we) have removed the socket middleware, which is very functional. how can i do this function, like the old middleware (passing/blocking) in a socket - our middleware is using more than authorization, many things are based on variables and we block or pass based on these, but now this is impossible, how do we do this now?

it is removal of important function, we depend on 6 projects. i hope other people feel the same way!

@p3x-robot p3x-robot changed the title socketio v3: TypeError: socket.use is not a function socketio v3: TypeError: socket.use is not a function, removal of a crucial middleware function on a socket now some functions are impossible!!!!! Nov 6, 2020
@p3x-robot p3x-robot changed the title socketio v3: TypeError: socket.use is not a function, removal of a crucial middleware function on a socket now some functions are impossible!!!!! [socketio v3] SOCKET MIDDLEWARE ISSUE: removal of a crucial middleware function on a v3 socket, now, some functions are impawssible!!!!! Nov 6, 2020
@p3x-robot p3x-robot changed the title [socketio v3] SOCKET MIDDLEWARE ISSUE: removal of a crucial middleware function on a v3 socket, now, some functions are impawssible!!!!! [socketio v3] SOCKET MIDDLEWARE ISSUE - removal of socket level middleware Nov 6, 2020
@p3x-robot
Copy link
Author

p3x-robot commented Nov 6, 2020

interesting:
#3456

@darrachequesne
Copy link
Member

@p3x-robot first, thanks a lot for your feedback.

We've indeed removed socket.use() when adding the socket.onAny() method (in 5c73733), in order not to have two distinct ways to do the same thing (catch all listeners, as discussed in #434).

But, as you have pointed out, socket.use() can be used for other things, like authorization / error handling.

My only concern with this method is about the handling of errors. In Socket.IO v2.3:

// server-side
io.use((socket, next) => {
  next(new Error("namespace error"));
});

io.on("connect", (socket) => {
  socket.use((packet, next) => {
    next(new Error("socket error"));
  });
});

// client-side
socket.on("error", (err) => {
  // either an error in the Namespace middleware or in the Socket middleware, which feels a bit weird to me
});

What do you think?

@daveisfera
Copy link

@darrachequesne What's the recommend method of doing auth in 3.0 that used to be done with a middleware in .use?

darrachequesne referenced this issue Nov 6, 2020
Inspired from EventEmitter2 [1]

```js
io.on("connect", socket => {

  socket.onAny((event, ...args) => {});

  socket.prependAny((event, ...args) => {});

  socket.offAny(); // remove all listeners

  socket.offAny(listener);

  const listeners = socket.listenersAny();
});
```

Breaking change: the socket.use() method is removed

This method was introduced in [2] for the same feature (having a
catch-all listener), but there were two issues:

- the API is not very user-friendly, since the user has to know the structure of the packet argument
- it uses an ERROR packet, which is reserved for Namespace authentication issues (see [3])

[1]: https://github.com/EventEmitter2/EventEmitter2
[2]: #434
[3]: https://github.com/socketio/socket.io-protocol
@darrachequesne
Copy link
Member

@daveisfera could you please give some details about how you are currently using the socket.use() method? It would help a lot in order to decide whether we add it back or not. Thanks!

@daveisfera
Copy link

We're using express-session and connect-redis to authenticate that the socket is by a valid user that has authenticated with our system and that they have access to the resource that they're requesting. This is done using a middleware in a socket.use() method.

@p3x-robot
Copy link
Author

can we keep this function running somehow? if we do not have a packet interceptor (or middleware however you name it). how can we induce this function or just keep in v2.3?

@p3x-robot
Copy link
Author

if we have no packet middleware, every time we re-new the token we have to disconnect and re-connect, with v2.3, we can keep the flow and we can re-new the auth as the token expires, now can we renew the auth token? right now in v3, we can only do auth once on connecting but this flow of renewing is missing since v3....

@tayler-king
Copy link

Yeah, this should most definitely be added back in.

@pruhstal
Copy link

pruhstal commented Nov 7, 2020

Would definitely like to see this added back. Example from my chat service:

   this.io
      .use((socket: any, next: any) => {
        this.sessionMiddleware(socket.request, socket.request.res || {}, next)
      })

wherein sessionMiddleware is an instance of express-session.

@p3x-robot
Copy link
Author

Would definitely like to see this added back. Example from my chat service:

   this.io
      .use((socket: any, next: any) => {
        this.sessionMiddleware(socket.request, socket.request.res || {}, next)
      })

wherein sessionMiddleware is an instance of express-session.

this is not a socket middleware, but a global io middleware. this issue is about the socket middleware, where i can use for re-newing tokens other functions, that is very useful like express middleware-s on every level.

@p3x-robot
Copy link
Author

Would definitely like to see this added back. Example from my chat service:

   this.io
      .use((socket: any, next: any) => {
        this.sessionMiddleware(socket.request, socket.request.res || {}, next)
      })

wherein sessionMiddleware is an instance of express-session.

https://socket.io/docs/migrating-from-2-x-to-3-0/#Socket-use-is-removed

@pruhstal
Copy link

pruhstal commented Nov 7, 2020

Would definitely like to see this added back. Example from my chat service:

   this.io
      .use((socket: any, next: any) => {
        this.sessionMiddleware(socket.request, socket.request.res || {}, next)
      })

wherein sessionMiddleware is an instance of express-session.

https://socket.io/docs/migrating-from-2-x-to-3-0/#Socket-use-is-removed

Cheers!

@p3x-robot
Copy link
Author

@p3x-robot first, thanks a lot for your feedback.

We've indeed removed socket.use() when adding the socket.onAny() method (in 5c73733), in order not to have two distinct ways to do the same thing (catch all listeners, as discussed in #434).

But, as you have pointed out, socket.use() can be used for other things, like authorization / error handling.

My only concern with this method is about the handling of errors. In Socket.IO v2.3:

// server-side
io.use((socket, next) => {
  next(new Error("namespace error"));
});

io.on("connect", (socket) => {
  socket.use((packet, next) => {
    next(new Error("socket error"));
  });
});

// client-side
socket.on("error", (err) => {
  // either an error in the Namespace middleware or in the Socket middleware, which feels a bit weird to me
});

What do you think?

why can't we use a client side 2 events: connect_error, error (or packet_error)

@p3x-robot
Copy link
Author

p3x-robot commented Nov 18, 2020

@darrachequesne do you know if socket.io middleware will be removed in v3 as it is now and have to stick to v2 or v3 will have middleware (not connect, but every request/message could be validated)

@Natashkinsasha
Copy link

Hi. I use library https://www.npmjs.com/package/socket.io-routers, where used socket middleware function. And now, i can't upgrade to v3. Please, add function socket.use in v3.

@darrachequesne
Copy link
Member

Given the feedback in this thread, I think we might add socket.use() back in version 3.1.0.

I'm wondering if it would make sense to include error handling:

// same API as in v2
socket.use(({ data }, next) => {
  next(new Error("cancelled"));
});

// user-defined error handler
socket.use((err, { data }, next) => {
  // either handle it
  socket.disconnect();
  // or forward the error to the default error handler
  next(err);
});

// default error handler
socket.use((err, { data }, next) => {
  socket.emit("error", err);
});

Async error could be caught too with captureRejections (well, once it's stable):

socket.on("test", async () => {
  throw new Error('kaboom');
});

What do you think?

@p3x-robot
Copy link
Author

Given the feedback in this thread, I think we might add socket.use() back in version 3.1.0.

I'm wondering if it would make sense to include error handling:

// same API as in v2
socket.use(({ data }, next) => {
  next(new Error("cancelled"));
});

// user-defined error handler
socket.use((err, { data }, next) => {
  // either handle it
  socket.disconnect();
  // or forward the error to the default error handler
  next(err);
});

// default error handler
socket.use((err, { data }, next) => {
  socket.emit("error", err);
});

Async error could be caught too with captureRejections (well, once it's stable):

socket.on("test", async () => {
  throw new Error('kaboom');
});

What do you think?

That is awesome!
But,

socket.use(({ data }, next) => {
  next(new Error("cancelled"));
});

socket v2 is:

socket.use((packet, next) => {
  packet[0] // event
 packet[1] // data
  next(new Error("cancelled"));
});

if we omit event we still need that option though.

@p3x-robot
Copy link
Author

maybe:

socket.use(({ event, data }, next) => {

   if (event === 'logging' ) {
      return next() 
    } 
    if (event === 'token') {
       return verify(data, next)
    }
    next()
});

@darrachequesne
Copy link
Member

@p3x-robot you're absolutely right, the destructuring should have been written: socket.use(([event, ...args], next) => {}), I updated the code above.

@ejose19
Copy link

ejose19 commented Nov 27, 2020

Another use case besides auth is ratelimiting, which is needed on each event (socket level) instead of root (io level).

@p3x-robot
Copy link
Author

@darrachequesne do you know when this is gonna be implmeneted? is it in 3.04?

@rip057
Copy link

rip057 commented Dec 14, 2020

i know im beating a broken drum but socket.use is important for custom middlewares.

For myself it is more for a security mindset, unless im using it wrong it allows for validation of an incoming packet and action on said connection if packet is malformed. Maybe this could be done another way, but i dont see how.

darrachequesne added a commit that referenced this issue Jan 5, 2021
This functionality was removed in [1] (included in 3.0.0), but
catch-all listeners and socket middleware features are complementary
rather than mutually exclusive.

The only difference with the previous implementation is that passing an
error to the `next` handler will create an error on the server-side,
and not on the client-side anymore.

```js
io.on("connection", (socket) => {

  socket.use(([ event, ...args ], next) => {
    next(new Error("stop"));
  });

  socket.on("error", (err) => {
    // to restore the previous behavior
    socket.emit("error", err);

    // or close the connection, depending on your use case
    socket.disconnect(true);
  });
});
```

This creates additional possibilities about custom error handlers, which
may be implemented in the future.

```js
// user-defined error handler
socket.use((err, [ event ], next) => {
  // either handle it
  socket.disconnect();

  // or forward the error to the default error handler
  next(err);
});

// default error handler
socket.use((err, _, next) => {
  socket.emit("error", err);
});
```

Related: #3678

[1]: 5c73733
@darrachequesne
Copy link
Member

The functionality has been restored in socket.io@3.0.5 (bf54327).

As noted in the commit message, the only difference with the previous implementation is that passing an error to the next handler will create an error on the server-side, and not on the client-side anymore.

io.on("connection", (socket) => {

  socket.use(([ event, ...args ], next) => {
    next(new Error("stop"));
  });

  socket.on("error", (err) => {
    // to restore the previous behavior
    socket.emit("error", err);

    // or close the connection, depending on your use case
    socket.disconnect(true);
  });
});

@darrachequesne darrachequesne added this to the 3.0.5 milestone Jan 5, 2021
dzad pushed a commit to dzad/socket.io that referenced this issue May 29, 2023
This functionality was removed in [1] (included in 3.0.0), but
catch-all listeners and socket middleware features are complementary
rather than mutually exclusive.

The only difference with the previous implementation is that passing an
error to the `next` handler will create an error on the server-side,
and not on the client-side anymore.

```js
io.on("connection", (socket) => {

  socket.use(([ event, ...args ], next) => {
    next(new Error("stop"));
  });

  socket.on("error", (err) => {
    // to restore the previous behavior
    socket.emit("error", err);

    // or close the connection, depending on your use case
    socket.disconnect(true);
  });
});
```

This creates additional possibilities about custom error handlers, which
may be implemented in the future.

```js
// user-defined error handler
socket.use((err, [ event ], next) => {
  // either handle it
  socket.disconnect();

  // or forward the error to the default error handler
  next(err);
});

// default error handler
socket.use((err, _, next) => {
  socket.emit("error", err);
});
```

Related: socketio#3678

[1]: socketio@6e969d0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants