From ff5c2a50a3f2b5e96523325916b5c846f8fb1d9c Mon Sep 17 00:00:00 2001 From: thosakwe Date: Sat, 3 Jun 2017 14:13:38 -0400 Subject: [PATCH] Fixed auth --- README.md | 2 +- lib/browser.dart | 5 +++- lib/server.dart | 38 +++++++++++++++--------------- pubspec.yaml | 10 ++++---- test/auth_test.dart | 56 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 85 insertions(+), 26 deletions(-) create mode 100644 test/auth_test.dart diff --git a/README.md b/README.md index 8df23a03..eb21d1cf 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # angel_websocket -[![1.0.6+1](https://img.shields.io/badge/pub-1.0.6+1-brightgreen.svg)](https://pub.dartlang.org/packages/angel_websocket) +[![1.0.7](https://img.shields.io/badge/pub-1.0.7-brightgreen.svg)](https://pub.dartlang.org/packages/angel_websocket) [![build status](https://travis-ci.org/angel-dart/websocket.svg)](https://travis-ci.org/angel-dart/websocket) WebSocket plugin for Angel. diff --git a/lib/browser.dart b/lib/browser.dart index 0cdee541..7f3afa6d 100644 --- a/lib/browser.dart +++ b/lib/browser.dart @@ -35,6 +35,7 @@ class WebSockets extends BaseWebSocketClient { var wnd = window.open(url, 'angel_client_auth_popup'); Timer t; + StreamSubscription sub; t = new Timer.periodic(new Duration(milliseconds: 500), (timer) { if (!ctrl.isClosed) { if (wnd.closed) { @@ -43,16 +44,18 @@ class WebSockets extends BaseWebSocketClient { errorMessage ?? 'Authentication via popup window failed.')); ctrl.close(); timer.cancel(); + sub?.cancel(); } } else timer.cancel(); }); - window.on[eventName ?? 'token'].listen((CustomEvent e) { + sub = window.on[eventName ?? 'token'].listen((CustomEvent e) { if (!ctrl.isClosed) { ctrl.add(e.detail); t.cancel(); ctrl.close(); + sub.cancel(); } }); diff --git a/lib/server.dart b/lib/server.dart index 9c219580..51670e04 100644 --- a/lib/server.dart +++ b/lib/server.dart @@ -13,6 +13,7 @@ import 'angel_websocket.dart'; export 'angel_websocket.dart'; part 'websocket_context.dart'; + part 'websocket_controller.dart'; /// Used to assign routes to a given handler. @@ -25,12 +26,12 @@ class AngelWebSocket extends AngelPlugin { final List _servicesAlreadyWired = []; final StreamController _onAction = - new StreamController(); + new StreamController(); final StreamController _onData = new StreamController(); final StreamController _onConnection = - new StreamController.broadcast(); + new StreamController.broadcast(); final StreamController _onDisconnect = - new StreamController.broadcast(); + new StreamController.broadcast(); /// If this is not `true`, then all client-side service parameters will be /// discarded, other than `params['query']`. @@ -81,16 +82,15 @@ class AngelWebSocket extends AngelPlugin { /// Deserializes data from WebSockets. Function deserializer; - AngelWebSocket( - {this.endpoint: '/ws', - this.debug: false, - bool sendErrors, - this.allowClientParams: false, - this.allowAuth: true, - this.register, - this.synchronizer, - this.serializer, - this.deserializer}) { + AngelWebSocket({this.endpoint: '/ws', + this.debug: false, + bool sendErrors, + this.allowClientParams: false, + this.allowAuth: true, + this.register, + this.synchronizer, + this.serializer, + this.deserializer}) { _sendErrors = sendErrors; if (serializer == null) serializer = god.serialize; @@ -143,9 +143,6 @@ class AngelWebSocket extends AngelPlugin { /// Responds to an incoming action on a WebSocket. Future handleAction(WebSocketAction action, WebSocketContext socket) async { - if (action.eventName == ACTION_AUTHENTICATE) - return await handleAuth(action, socket); - var split = action.eventName.split("::"); if (split.length < 2) @@ -229,9 +226,8 @@ class AngelWebSocket extends AngelPlugin { token = new AuthToken.validate(jwt, auth.hmac); var user = await auth.deserializer(token.userId); var req = socket.request; - req - ..inject(AuthToken, req.properties['token'] = token) - ..inject(user.runtimeType, req.properties["user"] = user); + req..inject(AuthToken, req.properties['token'] = token)..inject( + user.runtimeType, req.properties["user"] = user); socket.send(EVENT_AUTHENTICATED, {'token': token.serialize(auth.hmac), 'data': user}); } catch (e, st) { @@ -286,6 +282,9 @@ class AngelWebSocket extends AngelPlugin { .add(fromJson["data"]); } + if (action.eventName == ACTION_AUTHENTICATE) + await handleAuth(action, socket); + if (action.eventName.contains("::")) { var split = action.eventName.split("::"); @@ -389,5 +388,6 @@ class AngelWebSocket extends AngelPlugin { /// notifications from other nodes. abstract class WebSocketSynchronizer { Stream get stream; + void notifyOthers(WebSocketEvent e); } diff --git a/pubspec.yaml b/pubspec.yaml index cbf4defd..d7b1ae4e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,18 +2,18 @@ name: angel_websocket description: WebSocket plugin for Angel. environment: sdk: ">=1.19.0" -version: 1.0.6+1 +version: 1.0.7 author: Tobe O homepage: https://github.com/angel-dart/angel_websocket dependencies: - angel_auth: "^1.0.0-dev" + angel_auth: ^1.0.0-dev angel_client: "^1.0.0" - angel_framework: "^1.0.0-dev" - http: "^0.11.3" + angel_framework: ^1.0.0-dev + http: ">=0.11.0 <0.12.0" json_god: ^2.0.0-beta merge_map: ^1.0.0 uuid: "^0.5.3" web_socket_channel: "^1.0.0" dev_dependencies: - angel_diagnostics: "^1.0.0-dev" + angel_diagnostics: "^1.0.0" test: "^0.12.15" diff --git a/test/auth_test.dart b/test/auth_test.dart new file mode 100644 index 00000000..1118affc --- /dev/null +++ b/test/auth_test.dart @@ -0,0 +1,56 @@ +import 'dart:async'; +import 'package:angel_auth/angel_auth.dart'; +import 'package:angel_client/io.dart' as c; +import 'package:angel_diagnostics/angel_diagnostics.dart'; +import 'package:angel_framework/angel_framework.dart'; +import 'package:angel_websocket/io.dart' as c; +import 'package:angel_websocket/server.dart'; +import 'package:test/test.dart'; + +const Map USER = const {'username': 'foo', 'password': 'bar'}; + +main() { + Angel app; + c.Angel client; + c.WebSockets ws; + + setUp(() async { + app = new Angel(); + var auth = new AngelAuth(); + + auth.serializer = (_) async => 'baz'; + auth.deserializer = (_) async => USER; + + auth.strategies.add(new LocalAuthStrategy((username, password) async { + if (username == 'foo' && password == 'bar') return USER; + })); + + app.post('/auth/local', auth.authenticate('local')); + + await app.configure(auth); + var sock = new AngelWebSocket(); + await app.configure(sock); + await app.configure(logRequests()); + + var server = await app.startServer(); + client = new c.Rest('http://${server.address.address}:${server.port}'); + ws = new c.WebSockets('ws://${server.address.address}:${server.port}/ws'); + await ws.connect(); + }); + + tearDown(() => + Future.wait([ + app.close(), + client.close(), + ws.close() + ])); + + test('auth event fires', () async { + var localAuth = await client.authenticate(type: 'local', credentials: USER); + print('JWT: ${localAuth.token}'); + + ws.authenticateViaJwt(localAuth.token); + var auth = await ws.onAuthenticated.first; + expect(auth.token, localAuth.token); + }); +}