1+ var OAuth = require ( "../src/oauth/OAuth1Client" ) ;
2+ var request = require ( 'request' ) ;
3+
4+ describe ( 'OAuth' , function ( ) {
5+
6+ it ( "Nonce should have right length" , ( done ) => {
7+ jequal ( OAuth . nonce ( ) . length , 30 ) ;
8+ done ( ) ;
9+ } ) ;
10+
11+ it ( "Should properly build parameter string" , ( done ) => {
12+ var string = OAuth . buildParameterString ( { c :1 , a :2 , b :3 } )
13+ jequal ( string , "a=2&b=3&c=1" ) ;
14+ done ( ) ;
15+ } ) ;
16+
17+ it ( "Should properly build empty parameter string" , ( done ) => {
18+ var string = OAuth . buildParameterString ( )
19+ jequal ( string , "" ) ;
20+ done ( ) ;
21+ } ) ;
22+
23+ it ( "Should properly build signature string" , ( done ) => {
24+ var string = OAuth . buildSignatureString ( "get" , "http://dummy.com" , "" ) ;
25+ jequal ( string , "GET&http%3A%2F%2Fdummy.com&" ) ;
26+ done ( ) ;
27+ } ) ;
28+
29+ it ( "Should properly generate request signature" , ( done ) => {
30+ var request = {
31+ host : "dummy.com" ,
32+ path : "path"
33+ } ;
34+
35+ var oauth_params = {
36+ oauth_timestamp : 123450000 ,
37+ oauth_nonce : "AAAAAAAAAAAAAAAAA" ,
38+ oauth_consumer_key : "hello" ,
39+ oauth_token : "token"
40+ } ;
41+
42+ var consumer_secret = "world" ;
43+ var auth_token_secret = "secret" ;
44+ request = OAuth . signRequest ( request , oauth_params , consumer_secret , auth_token_secret ) ;
45+ jequal ( request . headers [ 'Authorization' ] , 'OAuth oauth_consumer_key="hello", oauth_nonce="AAAAAAAAAAAAAAAAA", oauth_signature="8K95bpQcDi9Nd2GkhumTVcw4%2BXw%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="123450000", oauth_token="token", oauth_version="1.0"' ) ;
46+ done ( ) ;
47+ } ) ;
48+
49+ it ( "Should properly build request" , ( done ) => {
50+ var options = {
51+ host : "dummy.com" ,
52+ consumer_key : "hello" ,
53+ consumer_secret : "world" ,
54+ auth_token : "token" ,
55+ auth_token_secret : "secret" ,
56+ // Custom oauth params for tests
57+ oauth_params : {
58+ oauth_timestamp : 123450000 ,
59+ oauth_nonce : "AAAAAAAAAAAAAAAAA"
60+ }
61+ } ;
62+ var path = "path" ;
63+ var method = "get" ;
64+
65+ var oauthClient = new OAuth ( options ) ;
66+ var req = oauthClient . buildRequest ( method , path , { "query" : "param" } ) ;
67+
68+ jequal ( req . host , options . host ) ;
69+ jequal ( req . path , "/" + path + "?query=param" ) ;
70+ jequal ( req . method , "GET" ) ;
71+ jequal ( req . headers [ 'Content-Type' ] , 'application/x-www-form-urlencoded' ) ;
72+ jequal ( req . headers [ 'Authorization' ] , 'OAuth oauth_consumer_key="hello", oauth_nonce="AAAAAAAAAAAAAAAAA", oauth_signature="wNkyEkDE%2F0JZ2idmqyrgHdvC0rs%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="123450000", oauth_token="token", oauth_version="1.0"' )
73+ done ( ) ;
74+ } ) ;
75+
76+
77+ function validateCannotAuthenticateError ( data , done ) {
78+ jequal ( typeof data , "object" ) ;
79+ jequal ( typeof data . errors , "object" ) ;
80+ var errors = data . errors ;
81+ jequal ( typeof errors [ 0 ] , "object" ) ;
82+ // Cannot authenticate error
83+ jequal ( errors [ 0 ] . code , 32 ) ;
84+ done ( ) ;
85+ }
86+
87+ it ( "Should fail a GET request" , ( done ) => {
88+ var options = {
89+ host : "api.twitter.com" ,
90+ consumer_key : "XXXXXXXXXXXXXXXXXXXXXXXXX" ,
91+ consumer_secret : "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" ,
92+ } ;
93+ var path = "/1.1/help/configuration.json" ;
94+ var params = { "lang" : "en" } ;
95+ var oauthClient = new OAuth ( options ) ;
96+ oauthClient . get ( path , params ) . then ( function ( data ) {
97+ validateCannotAuthenticateError ( data , done ) ;
98+ } )
99+ } ) ;
100+
101+ it ( "Should fail a POST request" , ( done ) => {
102+ var options = {
103+ host : "api.twitter.com" ,
104+ consumer_key : "XXXXXXXXXXXXXXXXXXXXXXXXX" ,
105+ consumer_secret : "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" ,
106+ } ;
107+ var body = {
108+ lang : "en"
109+ } ;
110+ var path = "/1.1/account/settings.json" ;
111+
112+ var oauthClient = new OAuth ( options ) ;
113+ oauthClient . post ( path , null , body ) . then ( function ( data ) {
114+ validateCannotAuthenticateError ( data , done ) ;
115+ } )
116+ } ) ;
117+
118+ it ( "Should fail a request" , ( done ) => {
119+ var options = {
120+ host : "localhost" ,
121+ consumer_key : "XXXXXXXXXXXXXXXXXXXXXXXXX" ,
122+ consumer_secret : "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" ,
123+ } ;
124+ var body = {
125+ lang : "en"
126+ } ;
127+ var path = "/" ;
128+
129+ var oauthClient = new OAuth ( options ) ;
130+ oauthClient . post ( path , null , body ) . then ( function ( data ) {
131+ jequal ( false , true ) ;
132+ done ( ) ;
133+ } ) . catch ( function ( ) {
134+ jequal ( true , true ) ;
135+ done ( ) ;
136+ } )
137+ } ) ;
138+
139+ [ "facebook" , "github" , "instagram" , "google" , "linkedin" , "meetup" , "twitter" ] . map ( function ( providerName ) {
140+ it ( "Should validate structure of " + providerName , ( done ) => {
141+ var provider = require ( "../src/oauth/" + providerName ) ;
142+ jequal ( typeof provider . validateAuthData , "function" ) ;
143+ jequal ( typeof provider . validateAppId , "function" ) ;
144+ jequal ( provider . validateAuthData ( { } , { } ) . constructor , Promise . prototype . constructor ) ;
145+ jequal ( provider . validateAppId ( "app" , "key" , { } ) . constructor , Promise . prototype . constructor ) ;
146+ done ( ) ;
147+ } ) ;
148+ } ) ;
149+
150+ var getMockMyOauthProvider = function ( ) {
151+ return {
152+ authData : {
153+ id : "12345" ,
154+ access_token : "12345" ,
155+ expiration_date : new Date ( ) . toJSON ( ) ,
156+ } ,
157+ shouldError : false ,
158+ loggedOut : false ,
159+ synchronizedUserId : null ,
160+ synchronizedAuthToken : null ,
161+ synchronizedExpiration : null ,
162+
163+ authenticate : function ( options ) {
164+ if ( this . shouldError ) {
165+ options . error ( this , "An error occurred" ) ;
166+ } else if ( this . shouldCancel ) {
167+ options . error ( this , null ) ;
168+ } else {
169+ options . success ( this , this . authData ) ;
170+ }
171+ } ,
172+ restoreAuthentication : function ( authData ) {
173+ if ( ! authData ) {
174+ this . synchronizedUserId = null ;
175+ this . synchronizedAuthToken = null ;
176+ this . synchronizedExpiration = null ;
177+ return true ;
178+ }
179+ this . synchronizedUserId = authData . id ;
180+ this . synchronizedAuthToken = authData . access_token ;
181+ this . synchronizedExpiration = authData . expiration_date ;
182+ return true ;
183+ } ,
184+ getAuthType : function ( ) {
185+ return "myoauth" ;
186+ } ,
187+ deauthenticate : function ( ) {
188+ this . loggedOut = true ;
189+ this . restoreAuthentication ( null ) ;
190+ }
191+ } ;
192+ } ;
193+
194+ var ExtendedUser = Parse . User . extend ( {
195+ extended : function ( ) {
196+ return true ;
197+ }
198+ } ) ;
199+
200+ var createOAuthUser = function ( callback ) {
201+ var jsonBody = {
202+ authData : {
203+ myoauth : getMockMyOauthProvider ( ) . authData
204+ }
205+ } ;
206+ var headers = { 'X-Parse-Application-Id' : 'test' ,
207+ 'X-Parse-REST-API-Key' : 'rest' ,
208+ 'Content-Type' : 'application/json' }
209+
210+ var options = {
211+ headers : { 'X-Parse-Application-Id' : 'test' ,
212+ 'X-Parse-REST-API-Key' : 'rest' ,
213+ 'Content-Type' : 'application/json' } ,
214+ url : 'http://localhost:8378/1/users' ,
215+ body : JSON . stringify ( jsonBody )
216+ } ;
217+
218+ return request . post ( options , callback ) ;
219+ }
220+
221+ it ( "should create user with REST API" , ( done ) => {
222+
223+ createOAuthUser ( ( error , response , body ) => {
224+ expect ( error ) . toBe ( null ) ;
225+ var b = JSON . parse ( body ) ;
226+ expect ( b . objectId ) . not . toBeNull ( ) ;
227+ expect ( b . objectId ) . not . toBeUndefined ( ) ;
228+ done ( ) ;
229+ } ) ;
230+
231+ } ) ;
232+
233+ it ( "should only create a single user with REST API" , ( done ) => {
234+ var objectId ;
235+ createOAuthUser ( ( error , response , body ) => {
236+ expect ( error ) . toBe ( null ) ;
237+ var b = JSON . parse ( body ) ;
238+ expect ( b . objectId ) . not . toBeNull ( ) ;
239+ expect ( b . objectId ) . not . toBeUndefined ( ) ;
240+ objectId = b . objectId ;
241+
242+ createOAuthUser ( ( error , response , body ) => {
243+ expect ( error ) . toBe ( null ) ;
244+ var b = JSON . parse ( body ) ;
245+ expect ( b . objectId ) . not . toBeNull ( ) ;
246+ expect ( b . objectId ) . not . toBeUndefined ( ) ;
247+ expect ( b . objectId ) . toBe ( objectId ) ;
248+ done ( ) ;
249+ } ) ;
250+ } ) ;
251+
252+ } ) ;
253+
254+ it ( "unlink and link with custom provider" , ( done ) => {
255+ var provider = getMockMyOauthProvider ( ) ;
256+ Parse . User . _registerAuthenticationProvider ( provider ) ;
257+ Parse . User . _logInWith ( "myoauth" , {
258+ success : function ( model ) {
259+ ok ( model instanceof Parse . User , "Model should be a Parse.User" ) ;
260+ strictEqual ( Parse . User . current ( ) , model ) ;
261+ ok ( model . extended ( ) , "Should have used the subclass." ) ;
262+ strictEqual ( provider . authData . id , provider . synchronizedUserId ) ;
263+ strictEqual ( provider . authData . access_token , provider . synchronizedAuthToken ) ;
264+ strictEqual ( provider . authData . expiration_date , provider . synchronizedExpiration ) ;
265+ ok ( model . _isLinked ( "myoauth" ) , "User should be linked to myoauth" ) ;
266+
267+ model . _unlinkFrom ( "myoauth" , {
268+ success : function ( model ) {
269+ ok ( ! model . _isLinked ( "myoauth" ) ,
270+ "User should not be linked to myoauth" ) ;
271+ ok ( ! provider . synchronizedUserId , "User id should be cleared" ) ;
272+ ok ( ! provider . synchronizedAuthToken , "Auth token should be cleared" ) ;
273+ ok ( ! provider . synchronizedExpiration ,
274+ "Expiration should be cleared" ) ;
275+
276+ model . _linkWith ( "myoauth" , {
277+ success : function ( model ) {
278+ ok ( provider . synchronizedUserId , "User id should have a value" ) ;
279+ ok ( provider . synchronizedAuthToken ,
280+ "Auth token should have a value" ) ;
281+ ok ( provider . synchronizedExpiration ,
282+ "Expiration should have a value" ) ;
283+ ok ( model . _isLinked ( "myoauth" ) ,
284+ "User should be linked to myoauth" ) ;
285+ done ( ) ;
286+ } ,
287+ error : function ( model , error ) {
288+ ok ( false , "linking again should succeed" ) ;
289+ done ( ) ;
290+ }
291+ } ) ;
292+ } ,
293+ error : function ( model , error ) {
294+ ok ( false , "unlinking should succeed" ) ;
295+ done ( ) ;
296+ }
297+ } ) ;
298+ } ,
299+ error : function ( model , error ) {
300+ ok ( false , "linking should have worked" ) ;
301+ done ( ) ;
302+ }
303+ } ) ;
304+ } ) ;
305+
306+
307+ } )
0 commit comments