Skip to content

Commit e3a4386

Browse files
authored
Merge pull request #58 from Simperium/cleanup/auth
Modernizes the Auth module
2 parents 8cdbfb0 + 3caa5bd commit e3a4386

File tree

7 files changed

+151
-90
lines changed

7 files changed

+151
-90
lines changed

.babelrc

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
{
22
"presets": [
3-
[ "env", { "targets": { "browsers": "last 2 versions"} } ]
4-
]
5-
}
3+
[ "env", { "targets": { "browsers": "last 2 versions"} } ],
4+
"flow"
5+
],
6+
"plugins": [ "transform-object-rest-spread" ]
7+
}

.flowconfig

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[ignore]
2+
3+
[include]
4+
src/
5+
6+
[libs]
7+
8+
[lints]
9+
10+
[options]
11+
12+
[strict]

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"lib/"
1212
],
1313
"scripts": {
14+
"flow": "flow",
1415
"test:coverage": "nyc npm test",
1516
"test": "mocha --reporter dot --require babel-core/register test/**",
1617
"babel": "babel -q -d lib/ src/",
@@ -27,7 +28,9 @@
2728
"babel-cli": "^6.26.0",
2829
"babel-core": "^6.26.0",
2930
"babel-eslint": "^8.2.1",
31+
"babel-plugin-transform-object-rest-spread": "^6.26.0",
3032
"babel-preset-env": "^1.6.1",
33+
"babel-preset-flow": "^6.23.0",
3134
"eslint": "^4.17.0",
3235
"mocha": "^5.0.0",
3336
"nyc": "^11.4.1"

src/simperium/auth.js

Lines changed: 96 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,116 @@
1-
import { EventEmitter } from 'events'
2-
import User from './user'
3-
import { format, inherits } from 'util'
4-
import https from 'https'
1+
// @flow
2+
import events from 'events'
3+
import { request } from 'https'
54
import url from 'url'
65

6+
// @flow
7+
type User = {
8+
options: {},
9+
access_token: string,
10+
};
11+
12+
const fromJSON = ( json: string ): User => {
13+
const data: {} = JSON.parse( json );
14+
if ( ! data.access_token && typeof data.access_token !== 'string' ) {
15+
throw new Error( 'access_token not present' );
16+
}
17+
return {
18+
options: data,
19+
access_token: new String( data.access_token ).toString()
20+
};
21+
};
22+
23+
const { EventEmitter } = events;
24+
725
const URL = 'https://auth.simperium.com/1';
826

9-
export default function Auth( appId, appSecret ) {
10-
this.appId = appId;
11-
this.appSecret = appSecret;
27+
export class AuthError extends Error {
28+
underlyingError: Error
29+
30+
constructor( underlyingError: Error ) {
31+
super( 'Failed to authenticate user.' );
32+
this.underlyingError = underlyingError;
33+
}
1234
}
1335

14-
inherits( Auth, EventEmitter );
36+
/**
37+
* Client for creating and authenticating Simperium.com user accounts.
38+
*/
39+
export class Auth extends EventEmitter {
40+
appId: string
41+
appSecret: string
1542

16-
Auth.prototype.authorize = function( username, password ) {
17-
var body = JSON.stringify( { username: username, password: password } ),
18-
promise = this.request( 'authorize/', body );
43+
/**
44+
* Creates an instance of the Auth client
45+
*
46+
* @param {string} appId - Simperium.com application ID
47+
* @param {string} appSecret - Simperium.com application secret
48+
*/
49+
constructor( appId: string, appSecret: string ) {
50+
super();
51+
this.appId = appId;
52+
this.appSecret = appSecret;
53+
}
1954

20-
return promise;
21-
}
55+
/**
56+
* Authorizes a user account with username and password
57+
*
58+
* @param {string} username account username
59+
* @param {string} password account password
60+
* @returns {Promise<User>} user account data
61+
*/
62+
authorize( username: string, password: string ) {
63+
const body = JSON.stringify( { username: username, password: password } );
64+
return this.request( 'authorize/', body );
65+
}
2266

23-
Auth.prototype.create = function( username, password, provider ) {
24-
var userData = { username, password };
25-
if ( provider ) {
26-
userData.provider = provider;
67+
create( username: String, password: String, provider: ?String ) {
68+
const userData: { username: String, password: String, provider?: String } = { username, password };
69+
if ( provider ) {
70+
userData.provider = provider;
71+
}
72+
const body = JSON.stringify( userData );
73+
return this.request( 'create/', body );
2774
}
28-
var body = JSON.stringify( userData ),
29-
promise = this.request( 'create/', body );
3075

31-
return promise;
32-
}
76+
getUrlOptions( path: string ) {
77+
const options = url.parse( `${URL}/${ this.appId }/${ path}` );
78+
return {
79+
... options,
80+
method: 'POST',
81+
headers: {'X-Simperium-API-Key': this.appSecret }
82+
};
83+
}
3384

34-
Auth.prototype.getUrlOptions = function( path ) {
35-
const options = url.parse( format( '%s/%s/%s', URL, this.appId, path ) );
36-
return Object.assign( options, { method: 'POST', headers: {'X-Simperium-API-Key': this.appSecret}} );
37-
}
85+
request( endpoint: string, body: string ): Promise<User> {
86+
return new Promise( ( resolve, reject ) => {
87+
const req = request( this.getUrlOptions( endpoint ), ( res ) => {
88+
let responseData = '';
3889

39-
Auth.prototype.request = function( endpoint, body ) {
40-
return new Promise( ( resolve, reject ) => {
41-
const req = https.request( this.getUrlOptions( endpoint ), ( res ) => {
42-
var responseData = '';
90+
res.on( 'data', ( data ) => {
91+
responseData += data.toString();
92+
} );
4393

44-
res.on( 'data', ( data ) => {
45-
responseData += data.toString();
94+
res.on( 'end', () => {
95+
try {
96+
const user = fromJSON( responseData );
97+
resolve( user );
98+
this.emit( 'authorize', user );
99+
} catch ( error ) {
100+
return reject( new AuthError( error ) );
101+
}
102+
} );
46103
} );
47104

48-
res.on( 'end', () => {
49-
var user;
50-
51-
try {
52-
user = User.fromJSON( responseData );
53-
} catch ( e ) {
54-
return reject( new Error( responseData ) );
55-
}
56-
this.emit( 'authorize', user );
57-
resolve( user );
105+
req.on( 'error', ( e ) => {
106+
reject( e );
58107
} );
59-
} );
60108

61-
req.on( 'error', ( e ) => {
62-
reject( e );
109+
req.end( body );
63110
} );
111+
}
112+
};
64113

65-
req.end( body );
66-
} );
67-
}
114+
export default ( appId: string, appSecret: string ) => {
115+
return new Auth( appId, appSecret );
116+
};

src/simperium/index.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import User from './user'
21
import Client from './client'
32
import Auth from './auth'
43
import * as util from './util'
@@ -7,4 +6,4 @@ export default function( appId, token, options ) {
76
return new Client( appId, token, options );
87
}
98

10-
export { Auth, User, Client, util }
9+
export { Auth, Client, util }

src/simperium/user.js

Lines changed: 0 additions & 9 deletions
This file was deleted.

test/simperium/auth_test.js

Lines changed: 34 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import Auth from '../../src/simperium/auth'
1+
import buildAuth from '../../src/simperium/auth'
22
import https from 'https'
33
import { equal, deepEqual } from 'assert'
44
import { EventEmitter } from 'events'
@@ -19,11 +19,11 @@ const stubResponse = ( data ) => stub( ( body, handler ) => {
1919
} )
2020

2121
describe( 'Auth', () => {
22-
var auth
22+
let auth;
2323

2424
beforeEach( () => {
25-
auth = new Auth( 'token', 'secret' );
26-
} )
25+
auth = buildAuth( 'token', 'secret' );
26+
} );
2727

2828
it( 'getUrlOptions', () => {
2929
const { hostname, headers, pathname, method } = auth.getUrlOptions( 'path' )
@@ -33,7 +33,7 @@ describe( 'Auth', () => {
3333
deepEqual( headers, { 'X-Simperium-API-Key': 'secret' } )
3434
} )
3535

36-
it( 'should request auth token', ( done ) => {
36+
it( 'should request auth token', () => {
3737
stub( ( data, handler ) => {
3838
const { username, password } = JSON.parse( data )
3939
const response = new EventEmitter()
@@ -45,24 +45,31 @@ describe( 'Auth', () => {
4545
response.emit( 'end' );
4646
} )
4747

48-
auth.authorize( 'username', 'password' )
49-
.then( ( user ) => {
50-
equal( user.access_token, 'secret-token' )
51-
done()
52-
} )
53-
} )
48+
return auth.authorize( 'username', 'password' )
49+
.then( ( user ) => {
50+
equal( user.access_token, 'secret-token' );
51+
} );
52+
} );
53+
54+
it( 'should fail if missing access_token', () => {
55+
stubResponse( '{"hello":"world"}' );
56+
return auth.authorize( 'username', 'password' )
57+
.catch( error => {
58+
equal( error.message, 'Failed to authenticate user.' );
59+
equal( error.underlyingError.message, 'access_token not present' );
60+
} );
61+
} );
5462

55-
it( 'should fail to auth with invalid credentials', ( done ) => {
63+
it( 'should fail to auth with invalid credentials', () => {
5664
stubResponse( 'this is not json' )
5765

58-
auth.authorize( 'username', 'bad-password' )
59-
.catch( ( e ) => {
60-
equal( e.message, 'this is not json' )
61-
done()
62-
} )
66+
return auth.authorize( 'username', 'bad-password' )
67+
.catch( ( e ) => {
68+
equal( e.message, 'Failed to authenticate user.' );
69+
} );
6370
} )
6471

65-
it( 'should create an account with valid credentials', ( done ) => {
72+
it( 'should create an account with valid credentials', () => {
6673
stub( ( data, handler ) => {
6774
const { username, password } = JSON.parse( data )
6875
const response = new EventEmitter()
@@ -74,20 +81,18 @@ describe( 'Auth', () => {
7481
response.emit( 'end' );
7582
} )
7683

77-
auth.create( 'username', 'password' )
78-
.then( ( user ) => {
79-
equal( user.access_token, 'secret-token' )
80-
done()
81-
} )
84+
return auth.create( 'username', 'password' )
85+
.then( user => {
86+
equal( user.access_token, 'secret-token' )
87+
} );
8288
} )
8389

84-
it( 'should fail to create an account with invalid credentials', ( done ) => {
90+
it( 'should fail to create an account with invalid credentials', () => {
8591
stubResponse( 'this is not json' )
8692

87-
auth.create( 'username', 'bad-password' )
88-
.catch( ( e ) => {
89-
equal( e.message, 'this is not json' )
90-
done()
91-
} )
93+
return auth.create( 'username', 'bad-password' )
94+
.catch( ( e ) => {
95+
equal( e.message, 'Failed to authenticate user.' );
96+
} );
9297
} )
9398
} )

0 commit comments

Comments
 (0)