|
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' |
5 | 4 | import url from 'url' |
6 | 5 |
|
| 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 | + |
7 | 25 | const URL = 'https://auth.simperium.com/1'; |
8 | 26 |
|
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 | + } |
12 | 34 | } |
13 | 35 |
|
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 |
15 | 42 |
|
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 | + } |
19 | 54 |
|
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 | + } |
22 | 66 |
|
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 ); |
27 | 74 | } |
28 | | - var body = JSON.stringify( userData ), |
29 | | - promise = this.request( 'create/', body ); |
30 | 75 |
|
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 | + } |
33 | 84 |
|
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 = ''; |
38 | 89 |
|
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 | + } ); |
43 | 93 |
|
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 | + } ); |
46 | 103 | } ); |
47 | 104 |
|
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 ); |
58 | 107 | } ); |
59 | | - } ); |
60 | 108 |
|
61 | | - req.on( 'error', ( e ) => { |
62 | | - reject( e ); |
| 109 | + req.end( body ); |
63 | 110 | } ); |
| 111 | + } |
| 112 | +}; |
64 | 113 |
|
65 | | - req.end( body ); |
66 | | - } ); |
67 | | -} |
| 114 | +export default ( appId: string, appSecret: string ) => { |
| 115 | + return new Auth( appId, appSecret ); |
| 116 | +}; |
0 commit comments