Skip to content
This repository has been archived by the owner on Jul 21, 2020. It is now read-only.

Commit

Permalink
feat(dev-registration): provide client id to oauth generated requests (
Browse files Browse the repository at this point in the history
  • Loading branch information
ProbablePrime committed May 19, 2018
1 parent 85f1b56 commit 250eb9c
Show file tree
Hide file tree
Showing 7 changed files with 334 additions and 213 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
@@ -1,6 +1,6 @@
language: node_js
node_js:
- 6
- 7
- 8
git:
depth: 10
21 changes: 11 additions & 10 deletions package.json
Expand Up @@ -6,8 +6,10 @@
"typings": "dist/module/index.d.ts",
"description": "Client library for interacting with the mixer API.",
"scripts": {
"test:unit": "cross-env TS_NODE_COMPILER_OPTIONS={\\\"module\\\":\\\"commonjs\\\"} mocha --compilers ts:ts-node/register test/unit/**/*.test.js",
"test:integrate": "cross-env TS_NODE_COMPILER_OPTIONS={\\\"module\\\":\\\"commonjs\\\"} mocha --compilers ts:ts-node/register test/integration/**/*.test.js",
"test:unit":
"cross-env TS_NODE_COMPILER_OPTIONS={\\\"module\\\":\\\"commonjs\\\"} mocha --compilers ts:ts-node/register test/unit/**/*.test.js",
"test:integrate":
"cross-env TS_NODE_COMPILER_OPTIONS={\\\"module\\\":\\\"commonjs\\\"} mocha --compilers ts:ts-node/register test/integration/**/*.test.js",
"test": "npm run test:unit && npm run lint",
"build:ts:module": "tsc --declaration",
"build:ts:commonjs": "tsc --outDir dist/commonjs --module commonjs --target es6",
Expand All @@ -19,14 +21,7 @@
"type": "git",
"url": "https://github.com/mixer/beam-client-node.git"
},
"keywords": [
"mixer",
"client",
"api",
"library",
"oauth",
"mixer"
],
"keywords": ["mixer", "client", "api", "library", "oauth", "mixer"],
"author": "Microsoft <contact@mixer.com>",
"license": "MIT",
"bugs": {
Expand Down Expand Up @@ -58,5 +53,11 @@
"deepmerge": "^1.4.4",
"request": "^2.79.0",
"ws": "^1.1.5"
},
"prettier": {
"trailingComma": "all",
"singleQuote": true,
"printWidth": 100,
"parser": "typescript"
}
}
27 changes: 22 additions & 5 deletions src/Client.ts
Expand Up @@ -2,13 +2,15 @@
import { all } from 'deepmerge';
import * as querystring from 'querystring';

import { OAuthProvider } from './providers/OAuth';
import { Provider } from './providers/Provider';
import {
IOptionalUrlRequestOptions,
IRequestOptions,
IRequestRunner,
IResponse,
} from './RequestRunner';
import { IGenericWebSocket, ISocketOptions, Socket } from './ws/Socket';

// DO NOT EDIT, THIS IS UPDATE BY THE BUILD SCRIPT
const packageVersion = '0.13.0'; // package version
Expand All @@ -34,7 +36,8 @@ export class Client {
private buildUserAgent() {
const client = `MixerClient/${packageVersion}`;
// tslint:disable-next-line no-typeof-undefined
if (typeof navigator !== 'undefined') { // in-browser
if (typeof navigator !== 'undefined') {
// in-browser
return navigator.userAgent + ' ' + client;
}

Expand All @@ -52,7 +55,7 @@ export class Client {
/**
* Builds a path to the Mixer API by concating it with the address.
*/
public buildAddress(base: string, path: string, querystr?: (string | Object)): string {
public buildAddress(base: string, path: string, querystr?: string | Object): string {
let url = base;

// Strip any trailing slash from the base
Expand Down Expand Up @@ -94,7 +97,11 @@ export class Client {
/**
* Attempts to run a given request.
*/
public request<T>(method: string, path: string, data: IOptionalUrlRequestOptions = {}): Promise<IResponse<T>> {
public request<T>(
method: string,
path: string,
data: IOptionalUrlRequestOptions = {},
): Promise<IResponse<T>> {
const req = all([
this.provider ? this.provider.getRequest() : {},
{
Expand All @@ -108,12 +115,22 @@ export class Client {
data,
]);

return this.requestRunner.run(<IRequestOptions>req)
.catch(err => {
return this.requestRunner.run(<IRequestOptions>req).catch(err => {
if (this.provider) {
return this.provider.handleResponseError(err, <IRequestOptions>req);
}
throw err;
});
}

public createChatSocket(
ws: IGenericWebSocket,
endpoints: string[],
options: ISocketOptions,
): Socket {
return new Socket(ws, endpoints, {
clientId: this.provider instanceof OAuthProvider ? this.provider.getClientId() : null,
...options,
});
}
}
61 changes: 36 additions & 25 deletions src/providers/OAuth.ts
Expand Up @@ -100,7 +100,7 @@ export class OAuthProvider extends Provider {
* Returns the set of tokens. These can be saved and used to
* reload the provider later using OAuthProvider.fromTokens.
*/
public getTokens(): IParsedTokens {
public getTokens(): IParsedTokens {
return this.tokens;
}

Expand Down Expand Up @@ -132,7 +132,7 @@ export class OAuthProvider extends Provider {
this.tokens = {
access: res.body.access_token,
refresh: res.body.refresh_token,
expires: new Date(Date.now() + (res.body.expires_in * 1000)),
expires: new Date(Date.now() + res.body.expires_in * 1000),
};
}

Expand All @@ -146,64 +146,75 @@ export class OAuthProvider extends Provider {
public attempt(redirect: string, qs: IQueryAttemptQueryString): Promise<void> {
if (qs.error) {
return Promise.reject(
new AuthenticationFailedError(qs.error_description || 'Error from oauth: ' + qs.error),
new AuthenticationFailedError(
qs.error_description || 'Error from oauth: ' + qs.error,
),
);
}

if (!qs.code) {
return Promise.reject(new AuthenticationFailedError('No error was given, ' +
'but a code was not present in the query string. Make sure ' +
'you\'re using the oauth client correctly.')); // silly devlopers
// XXX: https://github.com/prettier/prettier/issues/3804
return Promise.reject(
new AuthenticationFailedError(
'No error was given, but a code was not present in the query string. ' +
`Make sure you're using the oauth client correctly.`,
),
); // silly devlopers
}

return this.client.request<IOAuthTokenResponse>(
'post',
'/oauth/token',
{
return this.client
.request<IOAuthTokenResponse>('post', '/oauth/token', {
form: {
grant_type: 'authorization_code',
code: qs.code,
redirect_uri: redirect,
...this.details,
},
},
)
.then(res => this.unpackResponse(res));
})
.then(res => this.unpackResponse(res));
}

/**
* Refreshes the authentication tokens, bumping the expires time.
*/
public refresh(): Promise<void> {
if (!this.tokens.refresh) {
return Promise.reject(new AuthenticationFailedError('Attempted to ' +
'refresh without a refresh token present.'));
return Promise.reject(
new AuthenticationFailedError(
'Attempted to refresh without a refresh token present.',
),
);
}

return this.client.request<IOAuthTokenResponse>(
'post',
'/oauth/token',
{
return this.client
.request<IOAuthTokenResponse>('post', '/oauth/token', {
form: {
grant_type: 'refresh_token',
refresh_token: this.tokens.refresh,
...this.details,
},
},
)
.then(res => this.unpackResponse(res));
})
.then(res => this.unpackResponse(res));
}

/**
* Returns info to add to the client's request.
*/
public getRequest() {
if (!this.isAuthenticated()) {
return {};
const headers: { [key: string]: string } = {
'Client-ID': this.details.client_id,
};

if (this.isAuthenticated()) {
headers['Authorization'] = `Bearer ${this.tokens.access}`;
}

return {
headers: { Authorization: 'Bearer ' + this.tokens.access },
headers,
};
}

public getClientId() {
return this.details.client_id;
}
}

0 comments on commit 250eb9c

Please sign in to comment.