2016-02-11 16:16:42 +00:00
|
|
|
"use strict";
|
|
|
|
|
|
|
|
var cl = global.botanLoader;
|
|
|
|
var Dragonfly = global.Dragonfly;
|
|
|
|
|
|
|
|
var EventEmitter = require( "events" ).EventEmitter;
|
|
|
|
|
|
|
|
var HttpRequest = cl.load( "botanss.net.HttpRequest" );
|
2016-06-16 07:25:05 +00:00
|
|
|
var Rand = cl.load( "botansx.utils.random" );
|
|
|
|
|
2016-02-11 16:16:42 +00:00
|
|
|
var Notis = cl.load( "notifyterm.Notis" );
|
|
|
|
var Model = cl.load( "notifyterm.schema" );
|
|
|
|
|
|
|
|
// private static var
|
|
|
|
var AuthTokenName = "WNSAuthToken";
|
|
|
|
var AuthToken = false;
|
|
|
|
|
|
|
|
class WNSAuth extends EventEmitter
|
|
|
|
{
|
|
|
|
constructor()
|
|
|
|
{
|
|
|
|
super();
|
|
|
|
this.__inAuth = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
get IsAuthenticated() { return Boolean( AuthToken ); }
|
|
|
|
|
|
|
|
Authenticate()
|
|
|
|
{
|
|
|
|
if( this.IsAuthenticated )
|
|
|
|
{
|
|
|
|
this.__emitAuthComplete();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( this.__inAuth ) return;
|
|
|
|
|
|
|
|
this.__inAuth = true;
|
|
|
|
var _self = this;
|
|
|
|
|
2016-02-12 13:16:36 +00:00
|
|
|
Model.Tokens.findOne({ name: AuthTokenName, date_created: { $gt: Date.now() - 83200 } })
|
2016-02-11 16:16:42 +00:00
|
|
|
.exec( ( err, data ) => {
|
|
|
|
if( err || !( data && data.token ) )
|
|
|
|
{
|
|
|
|
Dragonfly.Info( "Database does not contain access token, authenticating" );
|
|
|
|
_self.__authWNS();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Dragonfly.Info( "Access token found in database, using it" );
|
|
|
|
AuthToken = data.token;
|
|
|
|
_self.__emitAuthComplete();
|
|
|
|
}
|
|
|
|
} );
|
|
|
|
}
|
|
|
|
|
2016-02-12 00:38:42 +00:00
|
|
|
Register( uuid, ChannelUri, handler )
|
2016-02-11 16:16:42 +00:00
|
|
|
{
|
|
|
|
var _self = this;
|
|
|
|
var VerifyChannel = () =>
|
|
|
|
{
|
|
|
|
var N = new Notis({
|
|
|
|
id: "Null"
|
|
|
|
, title: "Channel Registration"
|
|
|
|
, message: "Registration success"
|
|
|
|
});
|
|
|
|
|
2016-02-12 00:38:42 +00:00
|
|
|
if( uuid )
|
|
|
|
{
|
|
|
|
Dragonfly.Info( "Renewal request: " + uuid );
|
|
|
|
this.__updateToken( uuid, ChannelUri, handler );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
uuid = Rand.uuid();
|
2016-02-11 16:16:42 +00:00
|
|
|
|
2016-04-28 08:39:13 +00:00
|
|
|
Dragonfly.Debug( "ChannelUri: " + ChannelUri );
|
|
|
|
|
2016-02-11 16:16:42 +00:00
|
|
|
_self.__send( ChannelUri, N, ( sender, e ) => {
|
2016-02-11 19:12:38 +00:00
|
|
|
|
|
|
|
if( typeof( e ) == "string" )
|
|
|
|
{
|
|
|
|
handler( _self, e );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-02-11 16:16:42 +00:00
|
|
|
if( e.statusCode == 200 )
|
|
|
|
{
|
2016-02-12 00:38:42 +00:00
|
|
|
this.__updateToken( uuid, ChannelUri, handler );
|
2016-02-11 21:10:14 +00:00
|
|
|
return;
|
2016-02-11 16:16:42 +00:00
|
|
|
}
|
2016-02-11 21:10:14 +00:00
|
|
|
|
2016-04-28 08:39:13 +00:00
|
|
|
Dragonfly.Debug( e.statusCode + ": " + e.ResponseString );
|
2016-02-11 16:16:42 +00:00
|
|
|
handler( _self, e.statusCode + " Server Error: Unable to push message to channel" );
|
|
|
|
} );
|
|
|
|
};
|
|
|
|
|
|
|
|
if( !this.Authenticated )
|
|
|
|
{
|
|
|
|
this.once( "AuthComplete", VerifyChannel );
|
|
|
|
this.Authenticate();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
VerifyChannel();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-11 21:10:14 +00:00
|
|
|
Unregister( uuid, handler )
|
|
|
|
{
|
|
|
|
if( uuid == AuthTokenName )
|
|
|
|
{
|
|
|
|
handler( "Malicious action: Trying to remove AuthToken" );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Model.Tokens.remove({ name: uuid }).exec( handler );
|
|
|
|
}
|
|
|
|
|
2016-02-11 16:16:42 +00:00
|
|
|
Deliver( NotisQ )
|
|
|
|
{
|
2016-02-14 14:15:38 +00:00
|
|
|
var _self = this;
|
2016-02-11 16:16:42 +00:00
|
|
|
Model.Tokens
|
2016-06-29 04:08:23 +00:00
|
|
|
.findOne({ name: NotisQ.id, expired: false })
|
2016-02-11 16:16:42 +00:00
|
|
|
.exec( ( err, data ) => {
|
|
|
|
if( err )
|
|
|
|
{
|
|
|
|
Dragonfly.Error( err );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( data && data.token )
|
|
|
|
{
|
|
|
|
this.__send( data.token, NotisQ, ( sender, e ) => {
|
2016-02-11 21:10:14 +00:00
|
|
|
Dragonfly.Debug( "Send: " + e.statusCode );
|
2016-02-14 14:15:38 +00:00
|
|
|
|
2016-06-29 04:08:23 +00:00
|
|
|
switch( e.statusCode )
|
2016-02-14 14:15:38 +00:00
|
|
|
{
|
2016-06-29 04:08:23 +00:00
|
|
|
case 200: break;
|
|
|
|
case 410:
|
|
|
|
Dragonfly.Info( "Channel is expired: " + NotisQ.id );
|
|
|
|
data.expired = true;
|
|
|
|
data.save( x => {
|
|
|
|
Dragonfly.Info( "Mark expired: " + NotisQ.id );
|
2016-02-14 14:15:38 +00:00
|
|
|
});
|
|
|
|
|
2016-06-29 04:08:23 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
AuthToken = null;
|
|
|
|
Dragonfly.Info( "Perhaps access token is expired, retrying ..." );
|
|
|
|
|
|
|
|
if( NotisQ.Retry < 2 )
|
|
|
|
{
|
|
|
|
_self.once( "AuthComplete", () => {
|
|
|
|
NotisQ.Retry ++;
|
|
|
|
_self.Deliver( NotisQ );
|
|
|
|
});
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Dragonfly.Info( "Retrying exceeded the limit, dropping the message" );
|
|
|
|
}
|
|
|
|
|
|
|
|
_self.Authenticate();
|
2016-02-14 14:15:38 +00:00
|
|
|
}
|
2016-02-11 16:16:42 +00:00
|
|
|
} );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Dragonfly.Info( "Channel not found: " + NotisQ.id );
|
|
|
|
}
|
|
|
|
} );
|
|
|
|
}
|
|
|
|
|
2016-02-12 00:38:42 +00:00
|
|
|
__updateToken( uuid, ChannelUri, handler )
|
|
|
|
{
|
|
|
|
var _self = this;
|
|
|
|
Model.Tokens.update(
|
|
|
|
{ name: uuid }
|
2016-06-29 04:08:23 +00:00
|
|
|
, {
|
|
|
|
name: uuid
|
|
|
|
, token: ChannelUri
|
|
|
|
, date_created: Date.now()
|
|
|
|
, expired: false
|
|
|
|
}
|
2016-02-12 00:38:42 +00:00
|
|
|
, { upsert: true }
|
|
|
|
)
|
|
|
|
.exec( ( err, data ) => {
|
|
|
|
|
|
|
|
if( err )
|
|
|
|
{
|
|
|
|
Dragonfly.Error( err );
|
|
|
|
handler( _self, "Server Error: Cannot save channel information" );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Success
|
|
|
|
handler( _self, uuid );
|
2016-02-12 13:24:42 +00:00
|
|
|
Dragonfly.Info( "Register: " + uuid );
|
2016-02-12 00:38:42 +00:00
|
|
|
} );
|
|
|
|
}
|
|
|
|
|
2016-02-11 16:16:42 +00:00
|
|
|
__send( ChannelUri, NotisQ, handler )
|
|
|
|
{
|
|
|
|
if( !ChannelUri )
|
|
|
|
{
|
|
|
|
handler( this, "Channel is undefined" );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-02-11 19:12:38 +00:00
|
|
|
try
|
2016-02-11 16:16:42 +00:00
|
|
|
{
|
2016-02-11 19:12:38 +00:00
|
|
|
var Request = new HttpRequest( ChannelUri, {
|
|
|
|
"Authorization": "Bearer " + AuthToken
|
|
|
|
, "X-WNS-RequestForStatus": "true"
|
|
|
|
, "X-WNS-Type": "wns/toast"
|
|
|
|
} );
|
|
|
|
|
|
|
|
if( !Request.Hostname.match( /.*\.notify\.windows\.com$/ ) )
|
|
|
|
{
|
|
|
|
handler( this, "Malicious hostname: " + Request.Hostname );
|
|
|
|
return;
|
|
|
|
}
|
2016-02-11 16:16:42 +00:00
|
|
|
|
2016-02-11 19:12:38 +00:00
|
|
|
Request.PostData( NotisQ.Xml );
|
|
|
|
Request.Headers[ "Content-Type" ] = "text/xml";
|
2016-02-11 16:16:42 +00:00
|
|
|
|
2016-02-11 19:12:38 +00:00
|
|
|
Request.addListener( "RequestComplete", handler );
|
2016-02-11 16:16:42 +00:00
|
|
|
|
2016-02-11 19:12:38 +00:00
|
|
|
Request.Send();
|
|
|
|
}
|
|
|
|
catch( ex )
|
|
|
|
{
|
|
|
|
handler( this, ex.message );
|
|
|
|
return;
|
|
|
|
}
|
2016-02-11 16:16:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
__authWNS()
|
|
|
|
{
|
2016-02-11 21:47:57 +00:00
|
|
|
var serviceAuth = cl.load( "notifyterm.config.auth", true );
|
2016-02-11 16:16:42 +00:00
|
|
|
|
|
|
|
var Request = new HttpRequest( serviceAuth.Uri );
|
|
|
|
|
|
|
|
Request.PostData(
|
|
|
|
"grant_type=client_credentials"
|
|
|
|
+ "&client_id=" + serviceAuth.Id
|
|
|
|
+ "&client_secret=" + encodeURIComponent( serviceAuth.Secret )
|
|
|
|
+ "&scope=notify.windows.com"
|
|
|
|
);
|
|
|
|
|
|
|
|
Request.addListener( "RequestComplete", this.__requestComplete.bind( this ) );
|
|
|
|
|
|
|
|
Request.Send();
|
|
|
|
}
|
|
|
|
|
|
|
|
__requestComplete( sender, e )
|
|
|
|
{
|
|
|
|
var _self = this;
|
|
|
|
let JResponse = JSON.parse( e.ResponseString );
|
|
|
|
|
|
|
|
if( JResponse && JResponse.access_token )
|
|
|
|
{
|
|
|
|
AuthToken = JResponse.access_token;
|
|
|
|
Dragonfly.Info( "Authorization Success" );
|
|
|
|
|
2016-04-28 08:39:13 +00:00
|
|
|
Dragonfly.Debug( AuthTokenName + ": " + AuthToken );
|
2016-02-11 16:16:42 +00:00
|
|
|
Model.Tokens
|
|
|
|
.update(
|
|
|
|
{ name: AuthTokenName }
|
2016-02-12 13:16:36 +00:00
|
|
|
, { name: AuthTokenName, token: AuthToken, date_created: Date.now() }
|
2016-02-11 16:16:42 +00:00
|
|
|
, { upsert: true }
|
|
|
|
)
|
2016-06-29 04:08:23 +00:00
|
|
|
.exec( ( err, data ) => {
|
|
|
|
if( err ) Dragonfly.Error( err );
|
|
|
|
_self.__emitAuthComplete();
|
|
|
|
});
|
2016-02-11 16:16:42 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Dragonfly.Error( "Unable to authenticate: " + e.ResponseString );
|
|
|
|
_self.__emitAuthComplete();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
__emitAuthComplete()
|
|
|
|
{
|
|
|
|
this.__inAuth = false;
|
|
|
|
this.emit( "AuthComplete", this );
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = WNSAuth;
|