pusher-js 7.0.6 → 7.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/README.md +27 -87
- package/dist/node/pusher.js +325 -73
- package/dist/node/pusher.js.map +1 -1
- package/dist/react-native/pusher.js +2 -2
- package/dist/react-native/pusher.js.map +1 -1
- package/dist/web/pusher-with-encryption.js +330 -78
- package/dist/web/pusher-with-encryption.js.map +1 -1
- package/dist/web/pusher-with-encryption.min.js +2 -2
- package/dist/web/pusher-with-encryption.min.js.map +1 -1
- package/dist/web/pusher.js +330 -78
- package/dist/web/pusher.js.map +1 -1
- package/dist/web/pusher.min.js +2 -2
- package/dist/web/pusher.min.js.map +1 -1
- package/dist/worker/pusher-with-encryption.worker.js +314 -69
- package/dist/worker/pusher-with-encryption.worker.js.map +1 -1
- package/dist/worker/pusher-with-encryption.worker.min.js +2 -2
- package/dist/worker/pusher-with-encryption.worker.min.js.map +1 -1
- package/dist/worker/pusher.worker.js +314 -69
- package/dist/worker/pusher.worker.js.map +1 -1
- package/dist/worker/pusher.worker.min.js +2 -2
- package/dist/worker/pusher.worker.min.js.map +1 -1
- package/index.d.ts +8 -3
- package/package.json +2 -2
- package/spec/config/karma/config.worker.js +3 -0
- package/spec/config/karma/integration.js +4 -2
- package/spec/javascripts/helpers/mocks.js +41 -8
- package/spec/javascripts/helpers/worker/mock-dom-dependencies.js +1 -0
- package/spec/javascripts/integration/core/cluster_config_spec.js +8 -0
- package/spec/javascripts/integration/core/timeout_configuration_spec.js +1 -0
- package/spec/javascripts/integration/index.worker.js +12 -1
- package/spec/javascripts/unit/core/channels/channel_spec.js +25 -0
- package/spec/javascripts/unit/core/channels/encrypted_channel_spec.js +64 -66
- package/spec/javascripts/unit/core/channels/presence_channel_spec.js +51 -41
- package/spec/javascripts/unit/core/channels/private_channel_spec.js +8 -46
- package/spec/javascripts/unit/core/config_spec.js +307 -7
- package/spec/javascripts/unit/core/connection/connection_manager_spec.js +1 -0
- package/spec/javascripts/unit/core/http/http_socket_spec.js +1 -0
- package/spec/javascripts/unit/core/logger_spec.js +21 -20
- package/spec/javascripts/unit/core/pusher_spec.js +67 -39
- package/spec/javascripts/unit/core/pusher_with_encryption_spec.js +2 -0
- package/spec/javascripts/unit/core/strategies/cached_strategy_spec.js +1 -0
- package/spec/javascripts/unit/core/strategies/delayed_strategy_spec.js +1 -0
- package/spec/javascripts/unit/core/strategies/sequential_strategy_spec.js +1 -0
- package/spec/javascripts/unit/core/strategies/transport_strategy_spec.js +1 -0
- package/spec/javascripts/unit/core/transports/assistant_to_the_transport_manager_spec.js +1 -0
- package/spec/javascripts/unit/core/user_spec.js +295 -0
- package/spec/javascripts/unit/core/utils/periodic_timer_spec.js +4 -1
- package/spec/javascripts/unit/core/utils/timers_spec.js +6 -0
- package/spec/javascripts/unit/core/utils/url_store_spec.js +1 -1
- package/spec/javascripts/unit/core_with_runtime/auth/channel_authorizer_spec.js +55 -0
- package/spec/javascripts/unit/core_with_runtime/auth/deprecated_channel_authorizer_spec.js +48 -0
- package/spec/javascripts/unit/core_with_runtime/auth/user_authorizer_spec.js +52 -0
- package/spec/javascripts/unit/core_with_runtime/readme.md +5 -0
- package/spec/javascripts/unit/index.node.js +3 -0
- package/spec/javascripts/unit/index.web.js +3 -0
- package/spec/javascripts/unit/index.worker.js +3 -0
- package/spec/javascripts/unit/web/pusher_authorizer_spec.js +15 -16
- package/spec/javascripts/unit/web/transports/hosts_and_ports_spec.js +1 -0
- package/spec/javascripts/unit/worker/channel_authorizer_spec.js +110 -0
- package/src/core/auth/auth_transports.ts +8 -1
- package/src/core/auth/channel_authorizer.ts +53 -0
- package/src/core/auth/deprecated_channel_authorizer.ts +58 -0
- package/src/core/auth/options.ts +52 -17
- package/src/core/auth/user_authenticator.ts +51 -0
- package/src/core/channels/channel.ts +17 -3
- package/src/core/channels/channels.ts +4 -0
- package/src/core/channels/encrypted_channel.ts +26 -20
- package/src/core/channels/presence_channel.ts +5 -2
- package/src/core/channels/private_channel.ts +9 -4
- package/src/core/config.ts +76 -11
- package/src/core/defaults.ts +15 -0
- package/src/core/errors.ts +9 -0
- package/src/core/options.ts +18 -5
- package/src/core/pusher.ts +9 -1
- package/src/core/user.ts +143 -0
- package/src/core/utils/factory.ts +1 -10
- package/src/core/utils/url_store.ts +4 -1
- package/src/runtimes/isomorphic/auth/xhr_auth.ts +32 -19
- package/src/runtimes/web/auth/jsonp_auth.ts +13 -7
- package/src/runtimes/worker/auth/fetch_auth.ts +17 -12
- package/types/src/core/auth/auth_transports.d.ts +2 -1
- package/types/src/core/auth/channel_authorizer.d.ts +3 -0
- package/types/src/core/auth/deprecated_channel_authorizer.d.ts +18 -0
- package/types/src/core/auth/options.d.ts +34 -15
- package/types/src/core/auth/user_authenticator.d.ts +3 -0
- package/types/src/core/channels/channel.d.ts +4 -2
- package/types/src/core/channels/encrypted_channel.d.ts +2 -2
- package/types/src/core/channels/private_channel.d.ts +2 -2
- package/types/src/core/config.d.ts +4 -6
- package/types/src/core/defaults.d.ts +3 -0
- package/types/src/core/errors.d.ts +3 -0
- package/types/src/core/options.d.ts +6 -3
- package/types/src/core/pusher.d.ts +3 -0
- package/types/src/core/user.d.ts +15 -0
- package/types/src/core/utils/factory.d.ts +0 -2
- package/types/src/runtimes/isomorphic/auth/xhr_auth.d.ts +1 -1
- package/worker/with-encryption/index.js +1 -1
- package/spec/javascripts/unit/core/pusher_authorizer_spec.js +0 -160
- package/spec/javascripts/unit/worker/pusher_authorizer_spec.js +0 -111
- package/src/core/auth/pusher_authorizer.ts +0 -64
- package/types/index.d.ts +0 -15
- package/types/src/core/auth/pusher_authorizer.d.ts +0 -13
- package/types/src/core/index.d.ts +0 -6
- package/types/src/runtimes/react-native/tweetnacl-dummy.d.ts +0 -5
- package/types/src/runtimes/react-native/tweetnacl-util-dummy.d.ts +0 -7
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
var fetchAuth = require('worker/auth/fetch_auth').default;
|
|
2
|
+
var Runtime = require('runtime').default;
|
|
3
|
+
var fetchMock = require('fetch-mock');
|
|
4
|
+
var ChannelAuthorizer = require('core/auth/channel_authorizer').default;
|
|
5
|
+
|
|
6
|
+
var endpoint = 'http://example.org/pusher/auth';
|
|
7
|
+
|
|
8
|
+
describe('Fetch Authorizer', function() {
|
|
9
|
+
|
|
10
|
+
afterEach(function() {
|
|
11
|
+
fetchMock.restore();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('should pass headers in the request', function() {
|
|
15
|
+
fetchMock.mock(endpoint, { body: { hello: 'world' } });
|
|
16
|
+
|
|
17
|
+
var headers = { foo: 'bar', n: 42 };
|
|
18
|
+
var channelAuthorizer = ChannelAuthorizer({
|
|
19
|
+
transport: 'ajax',
|
|
20
|
+
endpoint: endpoint,
|
|
21
|
+
headers: headers
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
channelAuthorizer({
|
|
25
|
+
socketId: '1.23',
|
|
26
|
+
channelName: 'chan'
|
|
27
|
+
}, function() {});
|
|
28
|
+
|
|
29
|
+
var lastCall = fetchMock.lastCall(endpoint)[0];
|
|
30
|
+
var sentHeaders = lastCall.headers;
|
|
31
|
+
expect(sentHeaders.get('Content-Type')).toEqual(
|
|
32
|
+
'application/x-www-form-urlencoded'
|
|
33
|
+
);
|
|
34
|
+
expect(sentHeaders.get('foo')).toEqual('bar');
|
|
35
|
+
expect(sentHeaders.get('n')).toEqual('42');
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('should pass params in the query string', async function() {
|
|
39
|
+
fetchMock.mock(endpoint, { body: { hello: 'world' } });
|
|
40
|
+
|
|
41
|
+
var params = { a: 1, b: 2 };
|
|
42
|
+
var channelAuthorizer = ChannelAuthorizer({
|
|
43
|
+
transport: 'ajax',
|
|
44
|
+
endpoint: endpoint,
|
|
45
|
+
params: params
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
channelAuthorizer({
|
|
49
|
+
socketId: '1.23',
|
|
50
|
+
channelName: 'chan'
|
|
51
|
+
}, function() {});
|
|
52
|
+
|
|
53
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
54
|
+
var lastRequest = fetchMock.lastCall(endpoint)[0];
|
|
55
|
+
const body = await lastRequest.text()
|
|
56
|
+
expect(body).toEqual("socket_id=1.23&channel_name=chan&a=1&b=2");
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('should call back with the auth result on success', async function() {
|
|
60
|
+
var data = { foo: 'bar', number: 1 };
|
|
61
|
+
var dataJSON = JSON.stringify(data);
|
|
62
|
+
|
|
63
|
+
fetchMock.mock(endpoint, {
|
|
64
|
+
body: dataJSON
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
var channelAuthorizer = ChannelAuthorizer({
|
|
68
|
+
transport: 'ajax',
|
|
69
|
+
endpoint: endpoint,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
var callback = jasmine.createSpy('callback123');
|
|
73
|
+
channelAuthorizer({
|
|
74
|
+
socketId: '1.23',
|
|
75
|
+
channelName: 'chan'
|
|
76
|
+
}, callback);
|
|
77
|
+
|
|
78
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
79
|
+
expect(callback.calls.count()).toEqual(1);
|
|
80
|
+
expect(callback).toHaveBeenCalledWith(null, data);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('should call back with an error if JSON is invalid', async function() {
|
|
84
|
+
var channelAuthorizer = ChannelAuthorizer({
|
|
85
|
+
transport: 'ajax',
|
|
86
|
+
endpoint: endpoint,
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
var invalidJSON = 'INVALID { "something": "something"}';
|
|
90
|
+
fetchMock.mock(endpoint, {
|
|
91
|
+
body: invalidJSON
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
var callback = jasmine.createSpy('callback456');
|
|
95
|
+
channelAuthorizer({
|
|
96
|
+
socketId: '1.23',
|
|
97
|
+
channelName: 'chan'
|
|
98
|
+
}, callback);
|
|
99
|
+
|
|
100
|
+
await new Promise(resolve => setTimeout(resolve, 200));
|
|
101
|
+
expect(callback.calls.count()).toEqual(1);
|
|
102
|
+
expect(callback).toHaveBeenCalledWith(
|
|
103
|
+
new Error('JSON returned from auth endpoint was invalid, yet status code was 200. ' +
|
|
104
|
+
'Data was: ' +
|
|
105
|
+
invalidJSON),
|
|
106
|
+
null
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
});
|
|
110
|
+
});
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import AbstractRuntime from '../../runtimes/interface';
|
|
2
|
+
import { AuthRequestType, InternalAuthOptions } from './options';
|
|
2
3
|
|
|
3
4
|
interface AuthTransport {
|
|
4
|
-
(
|
|
5
|
+
(
|
|
6
|
+
context: AbstractRuntime,
|
|
7
|
+
query: string,
|
|
8
|
+
authOptions: InternalAuthOptions,
|
|
9
|
+
authRequestType: AuthRequestType,
|
|
10
|
+
callback: Function
|
|
11
|
+
): void;
|
|
5
12
|
}
|
|
6
13
|
|
|
7
14
|
interface AuthTransports {
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AuthRequestType,
|
|
3
|
+
InternalAuthOptions,
|
|
4
|
+
ChannelAuthorizationHandler,
|
|
5
|
+
ChannelAuthorizationRequestParams,
|
|
6
|
+
ChannelAuthorizationCallback
|
|
7
|
+
} from './options';
|
|
8
|
+
|
|
9
|
+
import Runtime from 'runtime';
|
|
10
|
+
|
|
11
|
+
const composeChannelQuery = (
|
|
12
|
+
params: ChannelAuthorizationRequestParams,
|
|
13
|
+
authOptions: InternalAuthOptions
|
|
14
|
+
) => {
|
|
15
|
+
var query = 'socket_id=' + encodeURIComponent(params.socketId);
|
|
16
|
+
|
|
17
|
+
query += '&channel_name=' + encodeURIComponent(params.channelName);
|
|
18
|
+
|
|
19
|
+
for (var i in authOptions.params) {
|
|
20
|
+
query +=
|
|
21
|
+
'&' +
|
|
22
|
+
encodeURIComponent(i) +
|
|
23
|
+
'=' +
|
|
24
|
+
encodeURIComponent(authOptions.params[i]);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return query;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const ChannelAuthorizer = (
|
|
31
|
+
authOptions: InternalAuthOptions
|
|
32
|
+
): ChannelAuthorizationHandler => {
|
|
33
|
+
if (typeof Runtime.getAuthorizers()[authOptions.transport] === 'undefined') {
|
|
34
|
+
throw `'${authOptions.transport}' is not a recognized auth transport`;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
params: ChannelAuthorizationRequestParams,
|
|
39
|
+
callback: ChannelAuthorizationCallback
|
|
40
|
+
) => {
|
|
41
|
+
const query = composeChannelQuery(params, authOptions);
|
|
42
|
+
|
|
43
|
+
Runtime.getAuthorizers()[authOptions.transport](
|
|
44
|
+
Runtime,
|
|
45
|
+
query,
|
|
46
|
+
authOptions,
|
|
47
|
+
AuthRequestType.ChannelAuthorization,
|
|
48
|
+
callback
|
|
49
|
+
);
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export default ChannelAuthorizer;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import Channel from '../channels/channel';
|
|
2
|
+
import {
|
|
3
|
+
ChannelAuthorizationCallback,
|
|
4
|
+
ChannelAuthorizationHandler,
|
|
5
|
+
ChannelAuthorizationRequestParams,
|
|
6
|
+
InternalAuthOptions
|
|
7
|
+
} from './options';
|
|
8
|
+
|
|
9
|
+
export interface DeprecatedChannelAuthorizer {
|
|
10
|
+
authorize(socketId: string, callback: ChannelAuthorizationCallback): void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface ChannelAuthorizerGenerator {
|
|
14
|
+
(
|
|
15
|
+
channel: Channel,
|
|
16
|
+
options: DeprecatedAuthorizerOptions
|
|
17
|
+
): DeprecatedChannelAuthorizer;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface DeprecatedAuthOptions {
|
|
21
|
+
params?: any;
|
|
22
|
+
headers?: any;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface DeprecatedAuthorizerOptions {
|
|
26
|
+
authTransport: 'ajax' | 'jsonp';
|
|
27
|
+
authEndpoint: string;
|
|
28
|
+
auth?: DeprecatedAuthOptions;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const ChannelAuthorizerProxy = (
|
|
32
|
+
pusher,
|
|
33
|
+
authOptions: InternalAuthOptions,
|
|
34
|
+
channelAuthorizerGenerator: ChannelAuthorizerGenerator
|
|
35
|
+
): ChannelAuthorizationHandler => {
|
|
36
|
+
const deprecatedAuthorizerOptions: DeprecatedAuthorizerOptions = {
|
|
37
|
+
authTransport: authOptions.transport,
|
|
38
|
+
authEndpoint: authOptions.endpoint,
|
|
39
|
+
auth: {
|
|
40
|
+
params: authOptions.params,
|
|
41
|
+
headers: authOptions.headers
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
return (
|
|
45
|
+
params: ChannelAuthorizationRequestParams,
|
|
46
|
+
callback: ChannelAuthorizationCallback
|
|
47
|
+
) => {
|
|
48
|
+
const channel = pusher.channel(params.channelName);
|
|
49
|
+
// This line creates a new channel authorizer every time.
|
|
50
|
+
// In the past, this was only done once per channel and reused.
|
|
51
|
+
// We can do that again if we want to keep this behavior intact.
|
|
52
|
+
const channelAuthorizer: DeprecatedChannelAuthorizer = channelAuthorizerGenerator(
|
|
53
|
+
channel,
|
|
54
|
+
deprecatedAuthorizerOptions
|
|
55
|
+
);
|
|
56
|
+
channelAuthorizer.authorize(params.socketId, callback);
|
|
57
|
+
};
|
|
58
|
+
};
|
package/src/core/auth/options.ts
CHANGED
|
@@ -1,32 +1,67 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
params?: any;
|
|
5
|
-
headers?: any;
|
|
1
|
+
export enum AuthRequestType {
|
|
2
|
+
UserAuthentication = 'user-authentication',
|
|
3
|
+
ChannelAuthorization = 'channel-authorization'
|
|
6
4
|
}
|
|
7
5
|
|
|
8
|
-
export interface
|
|
6
|
+
export interface ChannelAuthorizationData {
|
|
9
7
|
auth: string;
|
|
10
8
|
channel_data?: string;
|
|
11
9
|
shared_secret?: string;
|
|
12
10
|
}
|
|
13
11
|
|
|
14
|
-
export type
|
|
12
|
+
export type ChannelAuthorizationCallback = (
|
|
13
|
+
error: Error | null,
|
|
14
|
+
authData: ChannelAuthorizationData | null
|
|
15
|
+
) => void;
|
|
16
|
+
|
|
17
|
+
export interface ChannelAuthorizationRequestParams {
|
|
18
|
+
socketId: string;
|
|
19
|
+
channelName: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface ChannelAuthorizationHandler {
|
|
23
|
+
(
|
|
24
|
+
params: ChannelAuthorizationRequestParams,
|
|
25
|
+
callback: ChannelAuthorizationCallback
|
|
26
|
+
): void;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface UserAuthenticationData {
|
|
30
|
+
auth: string;
|
|
31
|
+
user_data: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export type UserAuthenticationCallback = (
|
|
15
35
|
error: Error | null,
|
|
16
|
-
authData:
|
|
36
|
+
authData: UserAuthenticationData | null
|
|
17
37
|
) => void;
|
|
18
38
|
|
|
19
|
-
export interface
|
|
20
|
-
|
|
39
|
+
export interface UserAuthenticationRequestParams {
|
|
40
|
+
socketId: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface UserAuthenticationHandler {
|
|
44
|
+
(
|
|
45
|
+
params: UserAuthenticationRequestParams,
|
|
46
|
+
callback: UserAuthenticationCallback
|
|
47
|
+
): void;
|
|
21
48
|
}
|
|
22
49
|
|
|
23
|
-
export
|
|
24
|
-
|
|
50
|
+
export type AuthTransportCallback =
|
|
51
|
+
| ChannelAuthorizationCallback
|
|
52
|
+
| UserAuthenticationCallback;
|
|
53
|
+
|
|
54
|
+
export interface AuthOptions<AuthHandler> {
|
|
55
|
+
transport: 'ajax' | 'jsonp';
|
|
56
|
+
endpoint: string;
|
|
57
|
+
params?: any;
|
|
58
|
+
headers?: any;
|
|
59
|
+
customHandler?: AuthHandler;
|
|
25
60
|
}
|
|
26
61
|
|
|
27
|
-
export interface
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
62
|
+
export interface InternalAuthOptions {
|
|
63
|
+
transport: 'ajax' | 'jsonp';
|
|
64
|
+
endpoint: string;
|
|
65
|
+
params?: any;
|
|
66
|
+
headers?: any;
|
|
32
67
|
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import {
|
|
2
|
+
UserAuthenticationCallback,
|
|
3
|
+
InternalAuthOptions,
|
|
4
|
+
UserAuthenticationHandler,
|
|
5
|
+
UserAuthenticationRequestParams,
|
|
6
|
+
AuthRequestType
|
|
7
|
+
} from './options';
|
|
8
|
+
|
|
9
|
+
import Runtime from 'runtime';
|
|
10
|
+
|
|
11
|
+
const composeChannelQuery = (
|
|
12
|
+
params: UserAuthenticationRequestParams,
|
|
13
|
+
authOptions: InternalAuthOptions
|
|
14
|
+
) => {
|
|
15
|
+
var query = 'socket_id=' + encodeURIComponent(params.socketId);
|
|
16
|
+
|
|
17
|
+
for (var i in authOptions.params) {
|
|
18
|
+
query +=
|
|
19
|
+
'&' +
|
|
20
|
+
encodeURIComponent(i) +
|
|
21
|
+
'=' +
|
|
22
|
+
encodeURIComponent(authOptions.params[i]);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return query;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const UserAuthenticator = (
|
|
29
|
+
authOptions: InternalAuthOptions
|
|
30
|
+
): UserAuthenticationHandler => {
|
|
31
|
+
if (typeof Runtime.getAuthorizers()[authOptions.transport] === 'undefined') {
|
|
32
|
+
throw `'${authOptions.transport}' is not a recognized auth transport`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
params: UserAuthenticationRequestParams,
|
|
37
|
+
callback: UserAuthenticationCallback
|
|
38
|
+
) => {
|
|
39
|
+
const query = composeChannelQuery(params, authOptions);
|
|
40
|
+
|
|
41
|
+
Runtime.getAuthorizers()[authOptions.transport](
|
|
42
|
+
Runtime,
|
|
43
|
+
query,
|
|
44
|
+
authOptions,
|
|
45
|
+
AuthRequestType.UserAuthentication,
|
|
46
|
+
callback
|
|
47
|
+
);
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export default UserAuthenticator;
|
|
@@ -5,7 +5,10 @@ import Pusher from '../pusher';
|
|
|
5
5
|
import { PusherEvent } from '../connection/protocol/message-types';
|
|
6
6
|
import Metadata from './metadata';
|
|
7
7
|
import UrlStore from '../utils/url_store';
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
ChannelAuthorizationData,
|
|
10
|
+
ChannelAuthorizationCallback
|
|
11
|
+
} from '../auth/options';
|
|
9
12
|
import { HTTPAuthError } from '../errors';
|
|
10
13
|
|
|
11
14
|
/** Provides base public channel interface with an event emitter.
|
|
@@ -23,6 +26,7 @@ export default class Channel extends EventsDispatcher {
|
|
|
23
26
|
subscribed: boolean;
|
|
24
27
|
subscriptionPending: boolean;
|
|
25
28
|
subscriptionCancelled: boolean;
|
|
29
|
+
subscriptionCount: null;
|
|
26
30
|
|
|
27
31
|
constructor(name: string, pusher: Pusher) {
|
|
28
32
|
super(function(event, data) {
|
|
@@ -40,7 +44,7 @@ export default class Channel extends EventsDispatcher {
|
|
|
40
44
|
*
|
|
41
45
|
* @param {Function} callback
|
|
42
46
|
*/
|
|
43
|
-
authorize(socketId: string, callback:
|
|
47
|
+
authorize(socketId: string, callback: ChannelAuthorizationCallback) {
|
|
44
48
|
return callback(null, { auth: '' });
|
|
45
49
|
}
|
|
46
50
|
|
|
@@ -75,6 +79,8 @@ export default class Channel extends EventsDispatcher {
|
|
|
75
79
|
var data = event.data;
|
|
76
80
|
if (eventName === 'pusher_internal:subscription_succeeded') {
|
|
77
81
|
this.handleSubscriptionSucceededEvent(event);
|
|
82
|
+
} else if (eventName === 'pusher_internal:subscription_count') {
|
|
83
|
+
this.handleSubscriptionCountEvent(event);
|
|
78
84
|
} else if (eventName.indexOf('pusher_internal:') !== 0) {
|
|
79
85
|
var metadata: Metadata = {};
|
|
80
86
|
this.emit(eventName, data, metadata);
|
|
@@ -91,6 +97,14 @@ export default class Channel extends EventsDispatcher {
|
|
|
91
97
|
}
|
|
92
98
|
}
|
|
93
99
|
|
|
100
|
+
handleSubscriptionCountEvent(event: PusherEvent) {
|
|
101
|
+
if (event.data.subscription_count) {
|
|
102
|
+
this.subscriptionCount = event.data.subscription_count;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
this.emit('pusher:subscription_count', event.data);
|
|
106
|
+
}
|
|
107
|
+
|
|
94
108
|
/** Sends a subscription request. For internal use only. */
|
|
95
109
|
subscribe() {
|
|
96
110
|
if (this.subscribed) {
|
|
@@ -100,7 +114,7 @@ export default class Channel extends EventsDispatcher {
|
|
|
100
114
|
this.subscriptionCancelled = false;
|
|
101
115
|
this.authorize(
|
|
102
116
|
this.pusher.connection.socket_id,
|
|
103
|
-
(error: Error | null, data:
|
|
117
|
+
(error: Error | null, data: ChannelAuthorizationData) => {
|
|
104
118
|
if (error) {
|
|
105
119
|
this.subscriptionPending = false;
|
|
106
120
|
// Why not bind to 'pusher:subscription_error' a level up, and log there?
|
|
@@ -76,6 +76,10 @@ function createChannel(name: string, pusher: Pusher): Channel {
|
|
|
76
76
|
return Factory.createPrivateChannel(name, pusher);
|
|
77
77
|
} else if (name.indexOf('presence-') === 0) {
|
|
78
78
|
return Factory.createPresenceChannel(name, pusher);
|
|
79
|
+
} else if (name.indexOf('#') === 0) {
|
|
80
|
+
throw new Errors.BadChannelName(
|
|
81
|
+
'Cannot create a channel with name "' + name + '".'
|
|
82
|
+
);
|
|
79
83
|
} else {
|
|
80
84
|
return Factory.createChannel(name, pusher);
|
|
81
85
|
}
|
|
@@ -6,7 +6,10 @@ import { decode as encodeUTF8 } from '@stablelib/utf8';
|
|
|
6
6
|
import { decode as decodeBase64 } from '@stablelib/base64';
|
|
7
7
|
import Dispatcher from '../events/dispatcher';
|
|
8
8
|
import { PusherEvent } from '../connection/protocol/message-types';
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
ChannelAuthorizationData,
|
|
11
|
+
ChannelAuthorizationCallback
|
|
12
|
+
} from '../auth/options';
|
|
10
13
|
import * as nacl from 'tweetnacl';
|
|
11
14
|
|
|
12
15
|
/** Extends private channels to provide encrypted channel interface.
|
|
@@ -28,26 +31,29 @@ export default class EncryptedChannel extends PrivateChannel {
|
|
|
28
31
|
* @param {String} socketId
|
|
29
32
|
* @param {Function} callback
|
|
30
33
|
*/
|
|
31
|
-
authorize(socketId: string, callback:
|
|
32
|
-
super.authorize(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
34
|
+
authorize(socketId: string, callback: ChannelAuthorizationCallback) {
|
|
35
|
+
super.authorize(
|
|
36
|
+
socketId,
|
|
37
|
+
(error: Error | null, authData: ChannelAuthorizationData) => {
|
|
38
|
+
if (error) {
|
|
39
|
+
callback(error, authData);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
let sharedSecret = authData['shared_secret'];
|
|
43
|
+
if (!sharedSecret) {
|
|
44
|
+
callback(
|
|
45
|
+
new Error(
|
|
46
|
+
`No shared_secret key in auth payload for encrypted channel: ${this.name}`
|
|
47
|
+
),
|
|
48
|
+
null
|
|
49
|
+
);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
this.key = decodeBase64(sharedSecret);
|
|
53
|
+
delete authData['shared_secret'];
|
|
54
|
+
callback(null, authData);
|
|
46
55
|
}
|
|
47
|
-
|
|
48
|
-
delete authData['shared_secret'];
|
|
49
|
-
callback(null, authData);
|
|
50
|
-
});
|
|
56
|
+
);
|
|
51
57
|
}
|
|
52
58
|
|
|
53
59
|
trigger(event: string, data: any): boolean {
|
|
@@ -5,7 +5,7 @@ import Pusher from '../pusher';
|
|
|
5
5
|
import UrlStore from 'core/utils/url_store';
|
|
6
6
|
import { PusherEvent } from '../connection/protocol/message-types';
|
|
7
7
|
import Metadata from './metadata';
|
|
8
|
-
import {
|
|
8
|
+
import { ChannelAuthorizationData } from '../auth/options';
|
|
9
9
|
|
|
10
10
|
export default class PresenceChannel extends PrivateChannel {
|
|
11
11
|
members: Members;
|
|
@@ -28,7 +28,7 @@ export default class PresenceChannel extends PrivateChannel {
|
|
|
28
28
|
authorize(socketId: string, callback: Function) {
|
|
29
29
|
super.authorize(socketId, (error, authData) => {
|
|
30
30
|
if (!error) {
|
|
31
|
-
authData = authData as
|
|
31
|
+
authData = authData as ChannelAuthorizationData;
|
|
32
32
|
if (authData.channel_data === undefined) {
|
|
33
33
|
let suffix = UrlStore.buildLogSuffix('authenticationEndpoint');
|
|
34
34
|
Logger.error(
|
|
@@ -69,6 +69,9 @@ export default class PresenceChannel extends PrivateChannel {
|
|
|
69
69
|
case 'pusher_internal:subscription_succeeded':
|
|
70
70
|
this.handleSubscriptionSucceededEvent(event);
|
|
71
71
|
break;
|
|
72
|
+
case 'pusher_internal:subscription_count':
|
|
73
|
+
this.handleSubscriptionCountEvent(event);
|
|
74
|
+
break;
|
|
72
75
|
case 'pusher_internal:member_added':
|
|
73
76
|
var addedMember = this.members.addMember(data);
|
|
74
77
|
this.emit('pusher:member_added', addedMember);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import Factory from '../utils/factory';
|
|
2
2
|
import Channel from './channel';
|
|
3
|
-
import {
|
|
3
|
+
import { ChannelAuthorizationCallback } from '../auth/options';
|
|
4
4
|
|
|
5
5
|
/** Extends public channels to provide private channel interface.
|
|
6
6
|
*
|
|
@@ -13,8 +13,13 @@ export default class PrivateChannel extends Channel {
|
|
|
13
13
|
* @param {String} socketId
|
|
14
14
|
* @param {Function} callback
|
|
15
15
|
*/
|
|
16
|
-
authorize(socketId: string, callback:
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
authorize(socketId: string, callback: ChannelAuthorizationCallback) {
|
|
17
|
+
return this.pusher.config.channelAuthorizer(
|
|
18
|
+
{
|
|
19
|
+
channelName: this.name,
|
|
20
|
+
socketId: socketId
|
|
21
|
+
},
|
|
22
|
+
callback
|
|
23
|
+
);
|
|
19
24
|
}
|
|
20
25
|
}
|