New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

stormpath-js

Package Overview
Dependencies
Maintainers
2
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

stormpath-js - npm Package Compare versions

Comparing version 0.2.0 to 0.4.0

.bower.json

2

bower.json
{
"name": "stormpath.js",
"description": "A browser-ready javascript library for Stormpath",
"version": "0.2.0",
"version": "0.4.0",
"license": "Apache 2.0",

@@ -6,0 +6,0 @@ "main": "dist/stormpath.js",

@@ -82,4 +82,5 @@ # Contributing

You will be prompted for the type of release (path, minor, major).
Please select the appropriate option and press enter.
After answering, the task will do the following:
The task will then do the following for you:

@@ -94,11 +95,16 @@ * Build the project and place the ouput in the `dist` folder

It will then ask if you would like to commit the files and push them to origin/master with a new tag.
While at this prompt you may use your git tool of choice to reivew the changes that have been made.
At this point you may answer yes to have the files committed and pushed, or answer no to end the task.
If you answer no, it is epexcted that you will manually commit, push and tag the changes.
Before answering "yes", you should use your git tool of choice to review the changes to make sure
that everything looks sane.
The task will not automatically publish this proejct to NPM, you must do that manually.
When you answer "yes", these changes will be committed and pushed to origin.
Bower is updated automatically by the presence of the new tag in the origin.
NPM will not be updated automatically, you must do that manually:
Bower is updated automatically by the tags that were pushed by the release task
````bash
npm publish
````
Finally, you should push the new version to the Stormpath CDN
If you answer no, it is epexcted that you will manually commit, push and tag the changes.
/*
Stormpath.js v0.2.0
(c) 2014 Stormpath, Inc. http://stormpath.com
Stormpath.js v0.4.0
(c) 2014-2015 Stormpath, Inc. http://stormpath.com
License: Apache 2.0
*/
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.Stormpath=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
var RequestExecutor = _dereq_('./request-executor');
var utils = _dereq_('./utils');
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Stormpath = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
'use strict';
var deferCallback = require('./defer-callback');
var IdSiteRequestExecutor = require('./idsite-request-executor');
var strings = require('./strings');
var utils = require('./utils');
var base64 = utils.base64;
function Client(options,readyCallback){
/**
* Creates a Stormpath.js Client
*
* A client is meant to encapsulate the communication
* with Stormpath's REST API.
*
* @constructor
* @param {object} options configuration options
* @param {function} readyCallback called when the client has
* initialized with its needed data from the REST API.
*/
function Client (options,readyCallback) {
var opts = typeof options === 'object' ? options : {};
var cb = typeof options === 'function' ? options : ( readyCallback || utils.noop);
var self = this;
var jwtSegments = null;
self.jwt = opts.token || self._getToken();
if(!self.jwt){
setTimeout(function(){cb(new Error('jwt not found as url query parameter'));},1);
return;
self.jwt = opts.token || self.getJwtFromUrl();
if (!self.jwt) {
return deferCallback(cb,[new Error(strings.errors.JWT_NOT_FOUND)]);
}
try{
self.jwtPayload = JSON.parse(base64.atob(self.jwt.split('.')[1]));
self.appHref = self.jwtPayload.app_href;
self.sptoken = self.jwtPayload.sp_token || null;
self.baseurl = self.appHref.match('^.+//([^\/]+)\/')[0];
}catch(e){
setTimeout(function(){cb(e);},1);
return;
jwtSegments = self.jwt.split('.');
if (jwtSegments.length < 2 || jwtSegments.length > 3) {
return deferCallback(cb,[new Error(strings.errors.NOT_A_JWT)]);
}
self.requestExecutor = opts.requestExecutor || new RequestExecutor(self.jwt);
try {
self.jwtPayload = JSON.parse(base64.atob(jwtSegments[1]));
} catch (e) {
return deferCallback(cb,[new Error(strings.errors.MALFORMED_JWT_CLAIMS)]);
}
self.appHref = self.jwtPayload.app_href;
self.sptoken = self.jwtPayload.sp_token || null;
self.baseurl = self.appHref.match('^.+//([^\/]+)\/')[0];
if (self.jwtPayload.onk) {
self.setCachedOrganizationNameKey(self.jwtPayload.onk);
}
var idSiteModelHref = self.appHref;
self.requestExecutor = opts.requestExecutor || new IdSiteRequestExecutor(self.jwt);
self.requestExecutor.execute(
'GET',self.appHref + '?expand=idSiteModel',
function(err,application){
cb(err, err? null:application.idSiteModel);
{
method: 'GET',
url: idSiteModelHref + '?expand=idSiteModel',
json: true
},
function (err,application) {
if (err) {
if (err.status === 401) {
return cb(new Error(strings.errors.INITIAL_JWT_REJECTED));
}
return cb(err);
}
/*
Assert that the response got a new auth token header. If it did not,
there is likely a proxy or firewall that is stripping it from the
response.
*/
if (!self.requestExecutor.authToken) {
return cb(new Error(strings.errors.NO_AUTH_TOKEN_HEADER));
}
cb(null,application.idSiteModel);
}

@@ -39,15 +89,64 @@ );

Client.prototype._getToken = function() {
return decodeURIComponent( (window.location.href.match(/jwt=(.+)/) || [])[1] || '' );
/**
* When storing an organization name key for future us, store it in this named
* cookie.
* @type {String}
*/
Client.prototype.organizationNameKeyCookieKey = 'sp.onk';
/**
* How long we should store the organization name key cookie for. Default:
* forever.
* @type {String}
*/
Client.prototype.organizationNameKeyCookieExpiration = 'expires=Fri, 31 Dec 9999 23:59:59 GMT';
/**
* Pull the cached organization name key from the organization name key cookie
* @return {string} The cached organization name.
*/
Client.prototype.getCachedOrganizationNameKey = function () {
return decodeURIComponent(
document.cookie.replace(
new RegExp('(?:(?:^|.*;)\\s*' + encodeURIComponent(this.organizationNameKeyCookieKey)
.replace(/[\-\.\+\*]/g, '\\$&') + '\\s*\\=\\s*([^;]*).*$)|^.*$'),
'$1'
)
) || null;
};
Client.prototype.login = function login(credentials,callback) {
/**
* Store the organization name key in the organization name key cookie
* @param {string} organization name key
*/
Client.prototype.setCachedOrganizationNameKey = function (nameKey) {
document.cookie = encodeURIComponent(this.organizationNameKeyCookieKey) +
'=' + encodeURIComponent(nameKey) + '; ' + this.organizationNameKeyCookieExpiration;
};
/**
* Attempts to fetch the JWT from the ?jwt=X location in the window URL.
* Returns an empty string if not found
* @return {string} JWT
*/
Client.prototype.getJwtFromUrl = function () {
return decodeURIComponent( (window.location.href.match(/jwt=([^&]+)/) || [])[1] || '' );
};
/**
* Make a login attempt against the REST API, given the credentials and
* application context.
*
* @param {object} credentials - Example: <pre>{ username: '', password: ''}</pre>
* @param {Function} callback
*/
Client.prototype.login = function login (credentials,callback) {
var self = this;
var data;
var creds = typeof credentials === 'object' ? credentials : null;
if(!creds){
if (!creds) {
throw new Error('must provide an object');
}else if(creds.providerData){
} else if (creds.providerData) {
data = creds;
}else if(creds.login){
} else if (creds.login) {
data = {

@@ -57,11 +156,14 @@ type: 'basic',

};
}else{
} else {
throw new Error('unsupported credentials object');
}
if (creds.accountStore) {
data.accountStore = creds.accountStore;
}
self.requestExecutor.execute(
'POST',self.appHref+'/loginAttempts',
{
body: data,
withCredentials: true
method: 'POST',
url: self.appHref+'/loginAttempts',
json: data
},

@@ -73,12 +175,37 @@ callback || utils.noop

Client.prototype.register = function register(data,callback) {
if(typeof data!=='object'){
/**
* Make an account creation attempt against the REST API, given the input data
* and application context. Social login should use this method.
*
* @param {object} data - Example:
* <pre>
* {
* username: '',
* password: '',
* givenName: '',
* surname: ''
* }
* </pre>
* Social Example:
* <pre>
* {
* providerData: {
* providerId: 'google',
* accessToken: ''
* }
* }
* </pre>
* @param {Function} callback - Called back with an error or ID Site Success
* Result
*/
Client.prototype.register = function register (data,callback) {
if (typeof data!=='object') {
throw new Error('client.register() must be called with a data object');
}
var self = this;
self.requestExecutor.execute(
'POST',self.appHref+'/accounts',
var client = this;
client.requestExecutor.execute(
{
body: data,
withCredentials: true
method: 'POST',
url: client.appHref+'/accounts',
json: data
},

@@ -89,10 +216,20 @@ callback || utils.noop

Client.prototype.verifyEmailToken = function verifyEmailToken(callback) {
if(typeof callback!=='function'){
/**
* Verify the email verification token that was embedded in the JWT that is in
* the URL.
*
* @param {Function} callback - If no error is given, the token is valid.
*/
Client.prototype.verifyEmailToken = function verifyEmailToken (callback) {
var client = this;
if (typeof callback!=='function') {
throw new Error('client.verifyEmailToken() takes a function as it\'s only argument');
}
var self = this;
self.requestExecutor.execute(
'POST',
self.baseurl + '/v1/accounts/emailVerificationTokens/' + self.sptoken,
client.requestExecutor.execute(
{
method: 'POST',
url: client.baseurl + '/v1/accounts/emailVerificationTokens/' + client.sptoken
},
callback

@@ -102,10 +239,21 @@ );

Client.prototype.verifyPasswordResetToken = function verifyPasswordResetToken(callback) {
if(typeof callback!=='function'){
/**
* Verify the password reset token that was embedded in the JWT that is in the
* URL.
*
* @param {Function} callback - If no error is given, the token is valid.
*/
Client.prototype.verifyPasswordResetToken = function verifyPasswordResetToken (callback) {
var client = this;
if (typeof callback!=='function') {
throw new Error('client.verifyPasswordResetToken() takes a function as it\'s only argument');
}
var self = this;
self.requestExecutor.execute(
'GET',
self.appHref + '/passwordResetTokens/' + self.sptoken,
client.requestExecutor.execute(
{
method: 'GET',
url: client.appHref + '/passwordResetTokens/' + client.sptoken,
json: true
},
callback

@@ -115,13 +263,33 @@ );

Client.prototype.setAccountPassword = function setAccountPassword(pwTokenVerification,newPassword,callback) {
if(!pwTokenVerification || !pwTokenVerification.href){
throw new Error('invalid pwTokenVerification');
/**
* Given the token resource, set the new password for the user.
*
* @param {object} passwordVerificationTokenResource -
* Example:
* <pre>
* {
* href: 'https://api.stormpath.com/v1/applications/1h72PFWoGxHKhysKjYIkir/passwordResetTokens/3Wog2qMsHyyjD76AWUnnlO'
* }
* </pre>
* @param {Function} callback - If no error is given, the password was reset
* successfully. If an error, the password strength validation error will be
* provided.
*/
Client.prototype.setAccountPassword = function setAccountPassword (passwordVerificationTokenResource,newPassword,callback) {
var client = this;
if (!passwordVerificationTokenResource || !passwordVerificationTokenResource.href) {
throw new Error('invalid passwordVerificationTokenResource');
}
if(!newPassword){
if (!newPassword) {
throw new Error('must supply new password as second argument to client.setAccountPassword()');
}
var self = this;
self.requestExecutor.execute('POST',pwTokenVerification.href,
client.requestExecutor.execute(
{
body: {
method: 'POST',
url: passwordVerificationTokenResource.href,
json: {
password: newPassword

@@ -134,12 +302,31 @@ }

Client.prototype.sendPasswordResetEmail = function sendPasswordResetEmail(emailOrUsername,callback) {
if(typeof emailOrUsername!=='string'){
throw new Error('sendPasswordResetEmail must be called with an email or username as the first argument');
/**
* Given the email, send that account an email with password reset link.
*
* @param {string} email
* @param {Function} callback - The error will indicate if the account could
* not be found. Otherwise, the email was sent.
*/
Client.prototype.sendPasswordResetEmail = function sendPasswordResetEmail (emailOrObject,callback) {
var client = this;
var body;
/*
emailOrObject is a backcompat option, in the future this should be a string-only option
*/
if (typeof emailOrObject==='string') {
body = { email: emailOrObject };
} else if (typeof emailOrObject === 'object') {
body = emailOrObject;
} else {
throw new Error('sendPasswordResetEmail must be called with an email/username as the first argument, or an options object');
}
var self = this;
self.requestExecutor.execute(
'POST',
self.appHref + '/passwordResetTokens',
client.requestExecutor.execute(
{
body: { email: emailOrUsername }
method: 'POST',
url: client.appHref + '/passwordResetTokens',
json: body
},

@@ -151,167 +338,515 @@ callback || utils.noop

module.exports = Client;
},{"./request-executor":3,"./utils":4}],2:[function(_dereq_,module,exports){
module.exports = {
Client: _dereq_('./client')
};
},{"./client":1}],3:[function(_dereq_,module,exports){
var utils = _dereq_('./utils');
},{"./defer-callback":2,"./idsite-request-executor":3,"./strings":5,"./utils":6}],2:[function(require,module,exports){
'use strict';
function Request(method,url,options,callback){
var self = this;
self.cb = callback;
self.options = options;
self.xhr = new XMLHttpRequest();
self.xhr.onreadystatechange = self.onLoad.bind(self);
self.xhr.onerror = self.onerror.bind(self);
self.xhr.open(method,url);
if(options.withCredentials){
self.xhr.withCredentials = options.withCredentials;
}
self.xhr.setRequestHeader('Authorization', 'Bearer '+self.options.authToken);
self.xhr.setRequestHeader('Content-Type','application/json');
self.xhr.send(JSON.stringify(options.body));
/**
* Defers the calling of the callback until the next run of
* the event loop. Do then when the callee is expecting
* the callback to be called after the current event loop
* is done processing (aka Angular's digest scheme)
*
* @function
* @param {function} cb - The callback to call at a later time
* @return {array} - args - The array of arguments to apply to the callback
*/
function deferCallback (cb,args) {
setTimeout(function () {
cb.apply(null,args);
},0);
}
self.done = false;
return self;
module.exports = deferCallback;
},{}],3:[function(require,module,exports){
'use strict';
var xhr = require('xhr');
var strings = require('./strings.json');
/**
* Request executor for ID Site, it must be initialized with the JWT that was
* recieved via the jwt parameter that is in the URL when you arrive on ID
* Site from the 302 redirect from the /sso endpoint
*
* @constructor
* @param {string} authToken - a JWT from the sso request
*/
function IdSiteRequestExecutor (authToken) {
this.authToken = authToken;
}
Request.prototype.onLoad = function onLoad() {
var self = this;
var XHR = XMLHttpRequest;
var s = self.xhr.readyState;
if(s === XHR.DONE && !self.done) {
try{
var headers = self.responseHeaders = self.getHeadersObject();
var body = (typeof self.xhr.responseText === 'string' && self.xhr.responseText !== '') ? JSON.parse(self.xhr.responseText) : {};
var status = self.xhr.status;
var newToken = ( (headers['Authorization'] || '').match(/Bearer (.*)$/i) || [])[1] || '';
self.cb(status < 400 ? null : body,
newToken,
self,
status < 400 ? body : null
);
self.done = true;
}catch(e){
self.cb(e);
/**
* Handles a response from the REST API, as executed by the`xhr` library.
*
* It will cache the new auth token for future use, or supply the service
* provider redirect URL (if that header exists) to the callback.
*
* @method
* @param {object} err - Provided by the xhr library callback
* @param {object} response - Provided by the xhr library callback
* @param {object} body - Provided by the xhr library callback
* @param {object} callback - the callback from the calling method in the client
* layer
*/
IdSiteRequestExecutor.prototype.handleResponse = function handleResponse (err,response,body,requestorCallback) {
var executor = this;
var newToken = response.headers.authorization;
var parsedToken = null;
var serviceProviderCallbackUrl = response.headers['stormpath-sso-redirect-location'];
if (newToken) {
parsedToken = newToken.split('Bearer');
if (parsedToken.length!==2) {
return requestorCallback(new Error(strings.errors.INVALID_AUTH_TOKEN_HEADER));
}
executor.authToken = parsedToken[1].trim();
} else {
executor.authToken = null;
}
/*
Note: The XHR library does not coerce HTTP error codes to err.
Only low-level errors (e.g CORS errors) are passed as err
*/
if (err) {
return requestorCallback(err);
}
if (response.statusCode>399) {
if (serviceProviderCallbackUrl) {
body.serviceProviderCallbackUrl = serviceProviderCallbackUrl;
}
return requestorCallback(body);
}
if (serviceProviderCallbackUrl) {
return requestorCallback(null, { serviceProviderCallbackUrl: serviceProviderCallbackUrl });
}
requestorCallback(null,body);
};
Request.prototype.onerror = function onerror() {
var self = this;
self.done = true;
self.cb(new Error('Unknown XHR Error'));
};
Request.prototype.getHeadersObject = function getHeadersObject() {
var self = this;
var all = self.xhr.getAllResponseHeaders().trim().split('\n');
return all.reduce(function(acc,str){
var x = str.split(': ');
acc[x[0]] = x[1].trim();
return acc;
},{});
};
function RequestExecutor(authToken){
this.authToken = authToken;
this.terminated = false;
}
/**
* Makes a request of the REST API, given the options for the xhr library.
* The cached auth token is used for authentication with the REST API.
*
* @param {object} xhrRequestOptions - Options for the call to `xhr(options)`
* @param {Function} callback - The callback to call with the result, as decorated
* by the `handleResponse` method in this class
*
*/
IdSiteRequestExecutor.prototype.execute = function (xhrRequestOptions,callback) {
RequestExecutor.prototype.execute = function(method,url,options,callback) {
var self = this;
if(self.terminated){
return callback(new Error('Request executor terminated, you must initiate a new flow from the service provider'));
var executor = this;
if (typeof xhrRequestOptions !== 'object') {
throw new Error('Must provide xhrRequestOptions as first parameter');
}
var opts = typeof options === 'object' ? options : {
body: null
};
opts.authToken = self.authToken;
var cb = typeof options === 'function' ? options : ( callback || utils.noop);
var req = new Request(method,url,opts,function onDone(err,newToken,request,body){
self.authToken = newToken;
if(!err && !self.authToken){
self.terminated = true;
}
if(err){
return cb(err);
}
var redirectUrl = request.responseHeaders['Stormpath-SSO-Redirect-Location'];
if(redirectUrl){
body.redirectUrl = redirectUrl;
}
cb(err,body);
if (typeof callback !== 'function') {
throw new Error('Must provide callback as second parameter');
}
if (!xhrRequestOptions.headers) {
xhrRequestOptions.headers = {};
}
if (!executor.authToken) {
return callback(new Error(strings.errors.NO_AUTH_TOKEN));
}
xhrRequestOptions.headers.Authorization = 'Bearer ' + executor.authToken;
return xhr(xhrRequestOptions, function xhrCallback (err,response,body) {
executor.handleResponse(err,response,body,callback);
});
return req;
};
module.exports = RequestExecutor;
},{"./utils":4}],4:[function(_dereq_,module,exports){
module.exports = IdSiteRequestExecutor;
},{"./strings.json":5,"xhr":7}],4:[function(require,module,exports){
module.exports = {
base64: _dereq_('base64'),
Client: require('./client')
};
},{"./client":1}],5:[function(require,module,exports){
module.exports={
"errors": {
"JWT_NOT_FOUND": "JWT not found as url query parameter.",
"NOT_A_JWT": "JWT does not appear to be a property formatted JWT.",
"MALFORMED_JWT_CLAIMS": "The JWT claims section is malfomed and could not be decoded as JSON.",
"NO_AUTH_TOKEN_HEADER": "HTTP response does not contain Authorization header.",
"INVALID_AUTH_TOKEN_HEADER": "HTTP response has an invalid Authorization header.",
"INITIAL_JWT_REJECTED": "The JWT used to initialized the client was rejected."
}
}
},{}],6:[function(require,module,exports){
'use strict';
/**
* @function
* From: https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding#Solution_.232_.E2.80.93_rewriting_atob()_and_btoa()_using_TypedArrays_and_UTF-8
*/
function b64EncodeUnicode(str) {
return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function(match, p1) {
return String.fromCharCode('0x' + p1);
}));
}
module.exports = {
base64: {
atob: function atob(str){
return decodeURIComponent(window.atob(str));
},
btoa: function btoa(str){
var v = b64EncodeUnicode(str);
return v;
}
},
noop: function(){}
};
},{"base64":5}],5:[function(_dereq_,module,exports){
;(function () {
},{}],7:[function(require,module,exports){
"use strict";
var window = require("global/window")
var once = require("once")
var parseHeaders = require("parse-headers")
var object = typeof exports != 'undefined' ? exports : this; // #8: web workers
var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
function InvalidCharacterError(message) {
this.message = message;
}
InvalidCharacterError.prototype = new Error;
InvalidCharacterError.prototype.name = 'InvalidCharacterError';
// encoder
// [https://gist.github.com/999166] by [https://github.com/nignag]
object.btoa || (
object.btoa = function (input) {
var str = String(input);
for (
// initialize result and counter
var block, charCode, idx = 0, map = chars, output = '';
// if the next str index does not exist:
// change the mapping table to "="
// check if d has no fractional digits
str.charAt(idx | 0) || (map = '=', idx % 1);
// "8 - idx % 1 * 8" generates the sequence 2, 4, 6, 8
output += map.charAt(63 & block >> 8 - idx % 1 * 8)
) {
charCode = str.charCodeAt(idx += 3/4);
if (charCode > 0xFF) {
throw new InvalidCharacterError("'btoa' failed: The string to be encoded contains characters outside of the Latin1 range.");
}
block = block << 8 | charCode;
module.exports = createXHR
createXHR.XMLHttpRequest = window.XMLHttpRequest || noop
createXHR.XDomainRequest = "withCredentials" in (new createXHR.XMLHttpRequest()) ? createXHR.XMLHttpRequest : window.XDomainRequest
function isEmpty(obj){
for(var i in obj){
if(obj.hasOwnProperty(i)) return false
}
return output;
});
return true
}
// decoder
// [https://gist.github.com/1020396] by [https://github.com/atk]
object.atob || (
object.atob = function (input) {
var str = String(input).replace(/=+$/, '');
if (str.length % 4 == 1) {
throw new InvalidCharacterError("'atob' failed: The string to be decoded is not correctly encoded.");
function createXHR(options, callback) {
function readystatechange() {
if (xhr.readyState === 4) {
loadFunc()
}
}
for (
// initialize result and counters
var bc = 0, bs, buffer, idx = 0, output = '';
// get next character
buffer = str.charAt(idx++);
// character found in table? initialize bit storage and add its ascii value;
~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer,
// and if not first of each 4 characters,
// convert the first 8 bits to one ascii character
bc++ % 4) ? output += String.fromCharCode(255 & bs >> (-2 * bc & 6)) : 0
function getBody() {
// Chrome with requestType=blob throws errors arround when even testing access to responseText
var body = undefined
if (xhr.response) {
body = xhr.response
} else if (xhr.responseType === "text" || !xhr.responseType) {
body = xhr.responseText || xhr.responseXML
}
if (isJson) {
try {
body = JSON.parse(body)
} catch (e) {}
}
return body
}
var failureResponse = {
body: undefined,
headers: {},
statusCode: 0,
method: method,
url: uri,
rawRequest: xhr
}
function errorFunc(evt) {
clearTimeout(timeoutTimer)
if(!(evt instanceof Error)){
evt = new Error("" + (evt || "Unknown XMLHttpRequest Error") )
}
evt.statusCode = 0
callback(evt, failureResponse)
}
// will load the data & process the response in a special response object
function loadFunc() {
if (aborted) return
var status
clearTimeout(timeoutTimer)
if(options.useXDR && xhr.status===undefined) {
//IE8 CORS GET successful response doesn't have a status field, but body is fine
status = 200
} else {
status = (xhr.status === 1223 ? 204 : xhr.status)
}
var response = failureResponse
var err = null
if (status !== 0){
response = {
body: getBody(),
statusCode: status,
method: method,
headers: {},
url: uri,
rawRequest: xhr
}
if(xhr.getAllResponseHeaders){ //remember xhr can in fact be XDR for CORS in IE
response.headers = parseHeaders(xhr.getAllResponseHeaders())
}
} else {
err = new Error("Internal XMLHttpRequest Error")
}
callback(err, response, response.body)
}
if (typeof options === "string") {
options = { uri: options }
}
options = options || {}
if(typeof callback === "undefined"){
throw new Error("callback argument missing")
}
callback = once(callback)
var xhr = options.xhr || null
if (!xhr) {
if (options.cors || options.useXDR) {
xhr = new createXHR.XDomainRequest()
}else{
xhr = new createXHR.XMLHttpRequest()
}
}
var key
var aborted
var uri = xhr.url = options.uri || options.url
var method = xhr.method = options.method || "GET"
var body = options.body || options.data
var headers = xhr.headers = options.headers || {}
var sync = !!options.sync
var isJson = false
var timeoutTimer
if ("json" in options) {
isJson = true
headers["accept"] || headers["Accept"] || (headers["Accept"] = "application/json") //Don't override existing accept header declared by user
if (method !== "GET" && method !== "HEAD") {
headers["content-type"] || headers["Content-Type"] || (headers["Content-Type"] = "application/json") //Don't override existing accept header declared by user
body = JSON.stringify(options.json)
}
}
xhr.onreadystatechange = readystatechange
xhr.onload = loadFunc
xhr.onerror = errorFunc
// IE9 must have onprogress be set to a unique function.
xhr.onprogress = function () {
// IE must die
}
xhr.ontimeout = errorFunc
xhr.open(method, uri, !sync, options.username, options.password)
//has to be after open
if(!sync) {
xhr.withCredentials = !!options.withCredentials
}
// Cannot set timeout with sync request
// not setting timeout on the xhr object, because of old webkits etc. not handling that correctly
// both npm's request and jquery 1.x use this kind of timeout, so this is being consistent
if (!sync && options.timeout > 0 ) {
timeoutTimer = setTimeout(function(){
aborted=true//IE9 may still call readystatechange
xhr.abort("timeout")
var e = new Error("XMLHttpRequest timeout")
e.code = "ETIMEDOUT"
errorFunc(e)
}, options.timeout )
}
if (xhr.setRequestHeader) {
for(key in headers){
if(headers.hasOwnProperty(key)){
xhr.setRequestHeader(key, headers[key])
}
}
} else if (options.headers && !isEmpty(options.headers)) {
throw new Error("Headers cannot be set on an XDomainRequest object")
}
if ("responseType" in options) {
xhr.responseType = options.responseType
}
if ("beforeSend" in options &&
typeof options.beforeSend === "function"
) {
// try to find character in table (0-63, not found => -1)
buffer = chars.indexOf(buffer);
options.beforeSend(xhr)
}
return output;
});
}());
xhr.send(body)
},{}]},{},[2])
(2)
return xhr
}
function noop() {}
},{"global/window":8,"once":9,"parse-headers":13}],8:[function(require,module,exports){
(function (global){
if (typeof window !== "undefined") {
module.exports = window;
} else if (typeof global !== "undefined") {
module.exports = global;
} else if (typeof self !== "undefined"){
module.exports = self;
} else {
module.exports = {};
}
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{}],9:[function(require,module,exports){
module.exports = once
once.proto = once(function () {
Object.defineProperty(Function.prototype, 'once', {
value: function () {
return once(this)
},
configurable: true
})
})
function once (fn) {
var called = false
return function () {
if (called) return
called = true
return fn.apply(this, arguments)
}
}
},{}],10:[function(require,module,exports){
var isFunction = require('is-function')
module.exports = forEach
var toString = Object.prototype.toString
var hasOwnProperty = Object.prototype.hasOwnProperty
function forEach(list, iterator, context) {
if (!isFunction(iterator)) {
throw new TypeError('iterator must be a function')
}
if (arguments.length < 3) {
context = this
}
if (toString.call(list) === '[object Array]')
forEachArray(list, iterator, context)
else if (typeof list === 'string')
forEachString(list, iterator, context)
else
forEachObject(list, iterator, context)
}
function forEachArray(array, iterator, context) {
for (var i = 0, len = array.length; i < len; i++) {
if (hasOwnProperty.call(array, i)) {
iterator.call(context, array[i], i, array)
}
}
}
function forEachString(string, iterator, context) {
for (var i = 0, len = string.length; i < len; i++) {
// no such thing as a sparse string.
iterator.call(context, string.charAt(i), i, string)
}
}
function forEachObject(object, iterator, context) {
for (var k in object) {
if (hasOwnProperty.call(object, k)) {
iterator.call(context, object[k], k, object)
}
}
}
},{"is-function":11}],11:[function(require,module,exports){
module.exports = isFunction
var toString = Object.prototype.toString
function isFunction (fn) {
var string = toString.call(fn)
return string === '[object Function]' ||
(typeof fn === 'function' && string !== '[object RegExp]') ||
(typeof window !== 'undefined' &&
// IE8 and below
(fn === window.setTimeout ||
fn === window.alert ||
fn === window.confirm ||
fn === window.prompt))
};
},{}],12:[function(require,module,exports){
exports = module.exports = trim;
function trim(str){
return str.replace(/^\s*|\s*$/g, '');
}
exports.left = function(str){
return str.replace(/^\s*/, '');
};
exports.right = function(str){
return str.replace(/\s*$/, '');
};
},{}],13:[function(require,module,exports){
var trim = require('trim')
, forEach = require('for-each')
, isArray = function(arg) {
return Object.prototype.toString.call(arg) === '[object Array]';
}
module.exports = function (headers) {
if (!headers)
return {}
var result = {}
forEach(
trim(headers).split('\n')
, function (row) {
var index = row.indexOf(':')
, key = trim(row.slice(0, index)).toLowerCase()
, value = trim(row.slice(index + 1))
if (typeof(result[key]) === 'undefined') {
result[key] = value
} else if (isArray(result[key])) {
result[key].push(value)
} else {
result[key] = [ result[key], value ]
}
}
)
return result
}
},{"for-each":10,"trim":12}]},{},[4])(4)
});
/*
Stormpath.js v0.2.0
(c) 2014 Stormpath, Inc. http://stormpath.com
Stormpath.js v0.4.0
(c) 2014-2015 Stormpath, Inc. http://stormpath.com
License: Apache 2.0
*/
!function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;"undefined"!=typeof window?b=window:"undefined"!=typeof global?b=global:"undefined"!=typeof self&&(b=self),b.Stormpath=a()}}(function(){return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);throw new Error("Cannot find module '"+g+"'")}var j=c[g]={exports:{}};b[g][0].call(j.exports,function(a){var c=b[g][1][a];return e(c?c:a)},j,j.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g<d.length;g++)e(d[g]);return e}({1:[function(a,b){function c(a,b){var c="object"==typeof a?a:{},g="function"==typeof a?a:b||e.noop,h=this;if(h.jwt=c.token||h._getToken(),!h.jwt)return void setTimeout(function(){g(new Error("jwt not found as url query parameter"))},1);try{h.jwtPayload=JSON.parse(f.atob(h.jwt.split(".")[1])),h.appHref=h.jwtPayload.app_href,h.sptoken=h.jwtPayload.sp_token||null,h.baseurl=h.appHref.match("^.+//([^/]+)/")[0]}catch(i){return void setTimeout(function(){g(i)},1)}h.requestExecutor=c.requestExecutor||new d(h.jwt),h.requestExecutor.execute("GET",h.appHref+"?expand=idSiteModel",function(a,b){g(a,a?null:b.idSiteModel)})}var d=a("./request-executor"),e=a("./utils"),f=e.base64;c.prototype._getToken=function(){return decodeURIComponent((window.location.href.match(/jwt=(.+)/)||[])[1]||"")},c.prototype.login=function(a,b){var c,d=this,f="object"==typeof a?a:null;if(!f)throw new Error("must provide an object");if(f.providerData)c=f;else{if(!f.login)throw new Error("unsupported credentials object");c={type:"basic",value:e.base64.btoa(f.login+":"+f.password)}}d.requestExecutor.execute("POST",d.appHref+"/loginAttempts",{body:c,withCredentials:!0},b||e.noop)},c.prototype.register=function(a,b){if("object"!=typeof a)throw new Error("client.register() must be called with a data object");var c=this;c.requestExecutor.execute("POST",c.appHref+"/accounts",{body:a,withCredentials:!0},b||e.noop)},c.prototype.verifyEmailToken=function(a){if("function"!=typeof a)throw new Error("client.verifyEmailToken() takes a function as it's only argument");var b=this;b.requestExecutor.execute("POST",b.baseurl+"/v1/accounts/emailVerificationTokens/"+b.sptoken,a)},c.prototype.verifyPasswordResetToken=function(a){if("function"!=typeof a)throw new Error("client.verifyPasswordResetToken() takes a function as it's only argument");var b=this;b.requestExecutor.execute("GET",b.appHref+"/passwordResetTokens/"+b.sptoken,a)},c.prototype.setAccountPassword=function(a,b,c){if(!a||!a.href)throw new Error("invalid pwTokenVerification");if(!b)throw new Error("must supply new password as second argument to client.setAccountPassword()");var d=this;d.requestExecutor.execute("POST",a.href,{body:{password:b}},c||e.noop)},c.prototype.sendPasswordResetEmail=function(a,b){if("string"!=typeof a)throw new Error("sendPasswordResetEmail must be called with an email or username as the first argument");var c=this;c.requestExecutor.execute("POST",c.appHref+"/passwordResetTokens",{body:{email:a}},b||e.noop)},b.exports=c},{"./request-executor":3,"./utils":4}],2:[function(a,b){b.exports={Client:a("./client")}},{"./client":1}],3:[function(a,b){function c(a,b,c,d){var e=this;return e.cb=d,e.options=c,e.xhr=new XMLHttpRequest,e.xhr.onreadystatechange=e.onLoad.bind(e),e.xhr.onerror=e.onerror.bind(e),e.xhr.open(a,b),c.withCredentials&&(e.xhr.withCredentials=c.withCredentials),e.xhr.setRequestHeader("Authorization","Bearer "+e.options.authToken),e.xhr.setRequestHeader("Content-Type","application/json"),e.xhr.send(JSON.stringify(c.body)),e.done=!1,e}function d(a){this.authToken=a,this.terminated=!1}var e=a("./utils");c.prototype.onLoad=function(){var a=this,b=XMLHttpRequest,c=a.xhr.readyState;if(c===b.DONE&&!a.done)try{var d=a.responseHeaders=a.getHeadersObject(),e="string"==typeof a.xhr.responseText&&""!==a.xhr.responseText?JSON.parse(a.xhr.responseText):{},f=a.xhr.status,g=((d.Authorization||"").match(/Bearer (.*)$/i)||[])[1]||"";a.cb(400>f?null:e,g,a,400>f?e:null),a.done=!0}catch(h){a.cb(h)}},c.prototype.onerror=function(){var a=this;a.done=!0,a.cb(new Error("Unknown XHR Error"))},c.prototype.getHeadersObject=function(){var a=this,b=a.xhr.getAllResponseHeaders().trim().split("\n");return b.reduce(function(a,b){var c=b.split(": ");return a[c[0]]=c[1].trim(),a},{})},d.prototype.execute=function(a,b,d,f){var g=this;if(g.terminated)return f(new Error("Request executor terminated, you must initiate a new flow from the service provider"));var h="object"==typeof d?d:{body:null};h.authToken=g.authToken;var i="function"==typeof d?d:f||e.noop,j=new c(a,b,h,function(a,b,c,d){if(g.authToken=b,a||g.authToken||(g.terminated=!0),a)return i(a);var e=c.responseHeaders["Stormpath-SSO-Redirect-Location"];e&&(d.redirectUrl=e),i(a,d)});return j},b.exports=d},{"./utils":4}],4:[function(a,b){b.exports={base64:a("base64"),noop:function(){}}},{base64:5}],5:[function(a,b,c){!function(){function a(a){this.message=a}var b="undefined"!=typeof c?c:this,d="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";a.prototype=new Error,a.prototype.name="InvalidCharacterError",b.btoa||(b.btoa=function(b){for(var c,e,f=String(b),g=0,h=d,i="";f.charAt(0|g)||(h="=",g%1);i+=h.charAt(63&c>>8-g%1*8)){if(e=f.charCodeAt(g+=.75),e>255)throw new a("'btoa' failed: The string to be encoded contains characters outside of the Latin1 range.");c=c<<8|e}return i}),b.atob||(b.atob=function(b){var c=String(b).replace(/=+$/,"");if(c.length%4==1)throw new a("'atob' failed: The string to be decoded is not correctly encoded.");for(var e,f,g=0,h=0,i="";f=c.charAt(h++);~f&&(e=g%4?64*e+f:f,g++%4)?i+=String.fromCharCode(255&e>>(-2*g&6)):0)f=d.indexOf(f);return i})}()},{}]},{},[2])(2)});
!function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;b="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,b.Stormpath=a()}}(function(){return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);var j=new Error("Cannot find module '"+g+"'");throw j.code="MODULE_NOT_FOUND",j}var k=c[g]={exports:{}};b[g][0].call(k.exports,function(a){var c=b[g][1][a];return e(c?c:a)},k,k.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g<d.length;g++)e(d[g]);return e}({1:[function(a,b,c){"use strict";function d(a,b){var c="object"==typeof a?a:{},d="function"==typeof a?a:b||h.noop,j=this,k=null;if(j.jwt=c.token||j.getJwtFromUrl(),!j.jwt)return e(d,[new Error(g.errors.JWT_NOT_FOUND)]);if(k=j.jwt.split("."),k.length<2||k.length>3)return e(d,[new Error(g.errors.NOT_A_JWT)]);try{j.jwtPayload=JSON.parse(i.atob(k[1]))}catch(l){return e(d,[new Error(g.errors.MALFORMED_JWT_CLAIMS)])}j.appHref=j.jwtPayload.app_href,j.sptoken=j.jwtPayload.sp_token||null,j.baseurl=j.appHref.match("^.+//([^/]+)/")[0],j.jwtPayload.onk&&j.setCachedOrganizationNameKey(j.jwtPayload.onk);var m=j.appHref;j.requestExecutor=c.requestExecutor||new f(j.jwt),j.requestExecutor.execute({method:"GET",url:m+"?expand=idSiteModel",json:!0},function(a,b){return a?d(401===a.status?new Error(g.errors.INITIAL_JWT_REJECTED):a):j.requestExecutor.authToken?void d(null,b.idSiteModel):d(new Error(g.errors.NO_AUTH_TOKEN_HEADER))})}var e=a("./defer-callback"),f=a("./idsite-request-executor"),g=a("./strings"),h=a("./utils"),i=h.base64;d.prototype.organizationNameKeyCookieKey="sp.onk",d.prototype.organizationNameKeyCookieExpiration="expires=Fri, 31 Dec 9999 23:59:59 GMT",d.prototype.getCachedOrganizationNameKey=function(){return decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*"+encodeURIComponent(this.organizationNameKeyCookieKey).replace(/[\-\.\+\*]/g,"\\$&")+"\\s*\\=\\s*([^;]*).*$)|^.*$"),"$1"))||null},d.prototype.setCachedOrganizationNameKey=function(a){document.cookie=encodeURIComponent(this.organizationNameKeyCookieKey)+"="+encodeURIComponent(a)+"; "+this.organizationNameKeyCookieExpiration},d.prototype.getJwtFromUrl=function(){return decodeURIComponent((window.location.href.match(/jwt=([^&]+)/)||[])[1]||"")},d.prototype.login=function(a,b){var c,d=this,e="object"==typeof a?a:null;if(!e)throw new Error("must provide an object");if(e.providerData)c=e;else{if(!e.login)throw new Error("unsupported credentials object");c={type:"basic",value:h.base64.btoa(e.login+":"+e.password)}}e.accountStore&&(c.accountStore=e.accountStore),d.requestExecutor.execute({method:"POST",url:d.appHref+"/loginAttempts",json:c},b||h.noop)},d.prototype.register=function(a,b){if("object"!=typeof a)throw new Error("client.register() must be called with a data object");var c=this;c.requestExecutor.execute({method:"POST",url:c.appHref+"/accounts",json:a},b||h.noop)},d.prototype.verifyEmailToken=function(a){var b=this;if("function"!=typeof a)throw new Error("client.verifyEmailToken() takes a function as it's only argument");b.requestExecutor.execute({method:"POST",url:b.baseurl+"/v1/accounts/emailVerificationTokens/"+b.sptoken},a)},d.prototype.verifyPasswordResetToken=function(a){var b=this;if("function"!=typeof a)throw new Error("client.verifyPasswordResetToken() takes a function as it's only argument");b.requestExecutor.execute({method:"GET",url:b.appHref+"/passwordResetTokens/"+b.sptoken,json:!0},a)},d.prototype.setAccountPassword=function(a,b,c){var d=this;if(!a||!a.href)throw new Error("invalid passwordVerificationTokenResource");if(!b)throw new Error("must supply new password as second argument to client.setAccountPassword()");d.requestExecutor.execute({method:"POST",url:a.href,json:{password:b}},c||h.noop)},d.prototype.sendPasswordResetEmail=function(a,b){var c,d=this;if("string"==typeof a)c={email:a};else{if("object"!=typeof a)throw new Error("sendPasswordResetEmail must be called with an email/username as the first argument, or an options object");c=a}d.requestExecutor.execute({method:"POST",url:d.appHref+"/passwordResetTokens",json:c},b||h.noop)},b.exports=d},{"./defer-callback":2,"./idsite-request-executor":3,"./strings":5,"./utils":6}],2:[function(a,b,c){"use strict";function d(a,b){setTimeout(function(){a.apply(null,b)},0)}b.exports=d},{}],3:[function(a,b,c){"use strict";function d(a){this.authToken=a}var e=a("xhr"),f=a("./strings.json");d.prototype.handleResponse=function(a,b,c,d){var e=this,g=b.headers.authorization,h=null,i=b.headers["stormpath-sso-redirect-location"];if(g){if(h=g.split("Bearer"),2!==h.length)return d(new Error(f.errors.INVALID_AUTH_TOKEN_HEADER));e.authToken=h[1].trim()}else e.authToken=null;return a?d(a):b.statusCode>399?(i&&(c.serviceProviderCallbackUrl=i),d(c)):i?d(null,{serviceProviderCallbackUrl:i}):void d(null,c)},d.prototype.execute=function(a,b){var c=this;if("object"!=typeof a)throw new Error("Must provide xhrRequestOptions as first parameter");if("function"!=typeof b)throw new Error("Must provide callback as second parameter");return a.headers||(a.headers={}),c.authToken?(a.headers.Authorization="Bearer "+c.authToken,e(a,function(a,d,e){c.handleResponse(a,d,e,b)})):b(new Error(f.errors.NO_AUTH_TOKEN))},b.exports=d},{"./strings.json":5,xhr:7}],4:[function(a,b,c){b.exports={Client:a("./client")}},{"./client":1}],5:[function(a,b,c){b.exports={errors:{JWT_NOT_FOUND:"JWT not found as url query parameter.",NOT_A_JWT:"JWT does not appear to be a property formatted JWT.",MALFORMED_JWT_CLAIMS:"The JWT claims section is malfomed and could not be decoded as JSON.",NO_AUTH_TOKEN_HEADER:"HTTP response does not contain Authorization header.",INVALID_AUTH_TOKEN_HEADER:"HTTP response has an invalid Authorization header.",INITIAL_JWT_REJECTED:"The JWT used to initialized the client was rejected."}}},{}],6:[function(a,b,c){"use strict";function d(a){return btoa(encodeURIComponent(a).replace(/%([0-9A-F]{2})/g,function(a,b){return String.fromCharCode("0x"+b)}))}b.exports={base64:{atob:function(a){return decodeURIComponent(window.atob(a))},btoa:function(a){var b=d(a);return b}},noop:function(){}}},{}],7:[function(a,b,c){"use strict";function d(a){for(var b in a)if(a.hasOwnProperty(b))return!1;return!0}function e(a,b){function c(){4===l.readyState&&j()}function f(){var a=void 0;if(l.response?a=l.response:"text"!==l.responseType&&l.responseType||(a=l.responseText||l.responseXML),u)try{a=JSON.parse(a)}catch(b){}return a}function g(a){clearTimeout(o),a instanceof Error||(a=new Error(""+(a||"Unknown XMLHttpRequest Error"))),a.statusCode=0,b(a,k)}function j(){if(!n){var c;clearTimeout(o),c=a.useXDR&&void 0===l.status?200:1223===l.status?204:l.status;var d=k,e=null;0!==c?(d={body:f(),statusCode:c,method:q,headers:{},url:p,rawRequest:l},l.getAllResponseHeaders&&(d.headers=i(l.getAllResponseHeaders()))):e=new Error("Internal XMLHttpRequest Error"),b(e,d,d.body)}}var k={body:void 0,headers:{},statusCode:0,method:q,url:p,rawRequest:l};if("string"==typeof a&&(a={uri:a}),a=a||{},"undefined"==typeof b)throw new Error("callback argument missing");b=h(b);var l=a.xhr||null;l||(l=a.cors||a.useXDR?new e.XDomainRequest:new e.XMLHttpRequest);var m,n,o,p=l.url=a.uri||a.url,q=l.method=a.method||"GET",r=a.body||a.data,s=l.headers=a.headers||{},t=!!a.sync,u=!1;if("json"in a&&(u=!0,s.accept||s.Accept||(s.Accept="application/json"),"GET"!==q&&"HEAD"!==q&&(s["content-type"]||s["Content-Type"]||(s["Content-Type"]="application/json"),r=JSON.stringify(a.json))),l.onreadystatechange=c,l.onload=j,l.onerror=g,l.onprogress=function(){},l.ontimeout=g,l.open(q,p,!t,a.username,a.password),t||(l.withCredentials=!!a.withCredentials),!t&&a.timeout>0&&(o=setTimeout(function(){n=!0,l.abort("timeout");var a=new Error("XMLHttpRequest timeout");a.code="ETIMEDOUT",g(a)},a.timeout)),l.setRequestHeader)for(m in s)s.hasOwnProperty(m)&&l.setRequestHeader(m,s[m]);else if(a.headers&&!d(a.headers))throw new Error("Headers cannot be set on an XDomainRequest object");return"responseType"in a&&(l.responseType=a.responseType),"beforeSend"in a&&"function"==typeof a.beforeSend&&a.beforeSend(l),l.send(r),l}function f(){}var g=a("global/window"),h=a("once"),i=a("parse-headers");b.exports=e,e.XMLHttpRequest=g.XMLHttpRequest||f,e.XDomainRequest="withCredentials"in new e.XMLHttpRequest?e.XMLHttpRequest:g.XDomainRequest},{"global/window":8,once:9,"parse-headers":13}],8:[function(a,b,c){(function(a){"undefined"!=typeof window?b.exports=window:"undefined"!=typeof a?b.exports=a:"undefined"!=typeof self?b.exports=self:b.exports={}}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],9:[function(a,b,c){function d(a){var b=!1;return function(){return b?void 0:(b=!0,a.apply(this,arguments))}}b.exports=d,d.proto=d(function(){Object.defineProperty(Function.prototype,"once",{value:function(){return d(this)},configurable:!0})})},{}],10:[function(a,b,c){function d(a,b,c){if(!h(b))throw new TypeError("iterator must be a function");arguments.length<3&&(c=this),"[object Array]"===i.call(a)?e(a,b,c):"string"==typeof a?f(a,b,c):g(a,b,c)}function e(a,b,c){for(var d=0,e=a.length;e>d;d++)j.call(a,d)&&b.call(c,a[d],d,a)}function f(a,b,c){for(var d=0,e=a.length;e>d;d++)b.call(c,a.charAt(d),d,a)}function g(a,b,c){for(var d in a)j.call(a,d)&&b.call(c,a[d],d,a)}var h=a("is-function");b.exports=d;var i=Object.prototype.toString,j=Object.prototype.hasOwnProperty},{"is-function":11}],11:[function(a,b,c){function d(a){var b=e.call(a);return"[object Function]"===b||"function"==typeof a&&"[object RegExp]"!==b||"undefined"!=typeof window&&(a===window.setTimeout||a===window.alert||a===window.confirm||a===window.prompt)}b.exports=d;var e=Object.prototype.toString},{}],12:[function(a,b,c){function d(a){return a.replace(/^\s*|\s*$/g,"")}c=b.exports=d,c.left=function(a){return a.replace(/^\s*/,"")},c.right=function(a){return a.replace(/\s*$/,"")}},{}],13:[function(a,b,c){var d=a("trim"),e=a("for-each"),f=function(a){return"[object Array]"===Object.prototype.toString.call(a)};b.exports=function(a){if(!a)return{};var b={};return e(d(a).split("\n"),function(a){var c=a.indexOf(":"),e=d(a.slice(0,c)).toLowerCase(),g=d(a.slice(c+1));"undefined"==typeof b[e]?b[e]=g:f(b[e])?b[e].push(g):b[e]=[b[e],g]}),b}},{"for-each":10,trim:12}]},{},[4])(4)});

@@ -9,2 +9,3 @@ 'use strict';

pkg: grunt.file.readJSON('package.json'),
year: new Date().getFullYear(),
bump: {

@@ -29,3 +30,3 @@ options:{

' Stormpath.js v<%= pkg.version %>\n' +
' (c) 2014 Stormpath, Inc. http://stormpath.com\n'+
' (c) 2014-<%= year %> Stormpath, Inc. http://stormpath.com\n'+
' License: Apache 2.0\n' +

@@ -55,4 +56,4 @@ '*/\n'

port: 8085
},
},
}
}
},

@@ -64,3 +65,3 @@ browserify: {

options: {
bundleOptions: {
browserifyOptions: {
standalone: 'Stormpath'

@@ -67,0 +68,0 @@ }

@@ -46,6 +46,6 @@ // Karma configuration

browserify: {
watch: true
watch: true,
debug: true
},
preprocessors: {

@@ -52,0 +52,0 @@ 'test/it/*.js': ['browserify'],

@@ -1,29 +0,79 @@

var RequestExecutor = require('./request-executor');
'use strict';
var deferCallback = require('./defer-callback');
var IdSiteRequestExecutor = require('./idsite-request-executor');
var strings = require('./strings');
var utils = require('./utils');
var base64 = utils.base64;
function Client(options,readyCallback){
/**
* Creates a Stormpath.js Client
*
* A client is meant to encapsulate the communication
* with Stormpath's REST API.
*
* @constructor
* @param {object} options configuration options
* @param {function} readyCallback called when the client has
* initialized with its needed data from the REST API.
*/
function Client (options,readyCallback) {
var opts = typeof options === 'object' ? options : {};
var cb = typeof options === 'function' ? options : ( readyCallback || utils.noop);
var self = this;
var jwtSegments = null;
self.jwt = opts.token || self._getToken();
if(!self.jwt){
setTimeout(function(){cb(new Error('jwt not found as url query parameter'));},1);
return;
self.jwt = opts.token || self.getJwtFromUrl();
if (!self.jwt) {
return deferCallback(cb,[new Error(strings.errors.JWT_NOT_FOUND)]);
}
try{
self.jwtPayload = JSON.parse(base64.atob(self.jwt.split('.')[1]));
self.appHref = self.jwtPayload.app_href;
self.sptoken = self.jwtPayload.sp_token || null;
self.baseurl = self.appHref.match('^.+//([^\/]+)\/')[0];
}catch(e){
setTimeout(function(){cb(e);},1);
return;
jwtSegments = self.jwt.split('.');
if (jwtSegments.length < 2 || jwtSegments.length > 3) {
return deferCallback(cb,[new Error(strings.errors.NOT_A_JWT)]);
}
self.requestExecutor = opts.requestExecutor || new RequestExecutor(self.jwt);
try {
self.jwtPayload = JSON.parse(base64.atob(jwtSegments[1]));
} catch (e) {
return deferCallback(cb,[new Error(strings.errors.MALFORMED_JWT_CLAIMS)]);
}
self.appHref = self.jwtPayload.app_href;
self.sptoken = self.jwtPayload.sp_token || null;
self.baseurl = self.appHref.match('^.+//([^\/]+)\/')[0];
if (self.jwtPayload.onk) {
self.setCachedOrganizationNameKey(self.jwtPayload.onk);
}
var idSiteModelHref = self.appHref;
self.requestExecutor = opts.requestExecutor || new IdSiteRequestExecutor(self.jwt);
self.requestExecutor.execute(
'GET',self.appHref + '?expand=idSiteModel',
function(err,application){
cb(err, err? null:application.idSiteModel);
{
method: 'GET',
url: idSiteModelHref + '?expand=idSiteModel',
json: true
},
function (err,application) {
if (err) {
if (err.status === 401) {
return cb(new Error(strings.errors.INITIAL_JWT_REJECTED));
}
return cb(err);
}
/*
Assert that the response got a new auth token header. If it did not,
there is likely a proxy or firewall that is stripping it from the
response.
*/
if (!self.requestExecutor.authToken) {
return cb(new Error(strings.errors.NO_AUTH_TOKEN_HEADER));
}
cb(null,application.idSiteModel);
}

@@ -33,15 +83,64 @@ );

Client.prototype._getToken = function() {
return decodeURIComponent( (window.location.href.match(/jwt=(.+)/) || [])[1] || '' );
/**
* When storing an organization name key for future us, store it in this named
* cookie.
* @type {String}
*/
Client.prototype.organizationNameKeyCookieKey = 'sp.onk';
/**
* How long we should store the organization name key cookie for. Default:
* forever.
* @type {String}
*/
Client.prototype.organizationNameKeyCookieExpiration = 'expires=Fri, 31 Dec 9999 23:59:59 GMT';
/**
* Pull the cached organization name key from the organization name key cookie
* @return {string} The cached organization name.
*/
Client.prototype.getCachedOrganizationNameKey = function () {
return decodeURIComponent(
document.cookie.replace(
new RegExp('(?:(?:^|.*;)\\s*' + encodeURIComponent(this.organizationNameKeyCookieKey)
.replace(/[\-\.\+\*]/g, '\\$&') + '\\s*\\=\\s*([^;]*).*$)|^.*$'),
'$1'
)
) || null;
};
Client.prototype.login = function login(credentials,callback) {
/**
* Store the organization name key in the organization name key cookie
* @param {string} organization name key
*/
Client.prototype.setCachedOrganizationNameKey = function (nameKey) {
document.cookie = encodeURIComponent(this.organizationNameKeyCookieKey) +
'=' + encodeURIComponent(nameKey) + '; ' + this.organizationNameKeyCookieExpiration;
};
/**
* Attempts to fetch the JWT from the ?jwt=X location in the window URL.
* Returns an empty string if not found
* @return {string} JWT
*/
Client.prototype.getJwtFromUrl = function () {
return decodeURIComponent( (window.location.href.match(/jwt=([^&]+)/) || [])[1] || '' );
};
/**
* Make a login attempt against the REST API, given the credentials and
* application context.
*
* @param {object} credentials - Example: <pre>{ username: '', password: ''}</pre>
* @param {Function} callback
*/
Client.prototype.login = function login (credentials,callback) {
var self = this;
var data;
var creds = typeof credentials === 'object' ? credentials : null;
if(!creds){
if (!creds) {
throw new Error('must provide an object');
}else if(creds.providerData){
} else if (creds.providerData) {
data = creds;
}else if(creds.login){
} else if (creds.login) {
data = {

@@ -51,11 +150,14 @@ type: 'basic',

};
}else{
} else {
throw new Error('unsupported credentials object');
}
if (creds.accountStore) {
data.accountStore = creds.accountStore;
}
self.requestExecutor.execute(
'POST',self.appHref+'/loginAttempts',
{
body: data,
withCredentials: true
method: 'POST',
url: self.appHref+'/loginAttempts',
json: data
},

@@ -67,12 +169,37 @@ callback || utils.noop

Client.prototype.register = function register(data,callback) {
if(typeof data!=='object'){
/**
* Make an account creation attempt against the REST API, given the input data
* and application context. Social login should use this method.
*
* @param {object} data - Example:
* <pre>
* {
* username: '',
* password: '',
* givenName: '',
* surname: ''
* }
* </pre>
* Social Example:
* <pre>
* {
* providerData: {
* providerId: 'google',
* accessToken: ''
* }
* }
* </pre>
* @param {Function} callback - Called back with an error or ID Site Success
* Result
*/
Client.prototype.register = function register (data,callback) {
if (typeof data!=='object') {
throw new Error('client.register() must be called with a data object');
}
var self = this;
self.requestExecutor.execute(
'POST',self.appHref+'/accounts',
var client = this;
client.requestExecutor.execute(
{
body: data,
withCredentials: true
method: 'POST',
url: client.appHref+'/accounts',
json: data
},

@@ -83,10 +210,20 @@ callback || utils.noop

Client.prototype.verifyEmailToken = function verifyEmailToken(callback) {
if(typeof callback!=='function'){
/**
* Verify the email verification token that was embedded in the JWT that is in
* the URL.
*
* @param {Function} callback - If no error is given, the token is valid.
*/
Client.prototype.verifyEmailToken = function verifyEmailToken (callback) {
var client = this;
if (typeof callback!=='function') {
throw new Error('client.verifyEmailToken() takes a function as it\'s only argument');
}
var self = this;
self.requestExecutor.execute(
'POST',
self.baseurl + '/v1/accounts/emailVerificationTokens/' + self.sptoken,
client.requestExecutor.execute(
{
method: 'POST',
url: client.baseurl + '/v1/accounts/emailVerificationTokens/' + client.sptoken
},
callback

@@ -96,10 +233,21 @@ );

Client.prototype.verifyPasswordResetToken = function verifyPasswordResetToken(callback) {
if(typeof callback!=='function'){
/**
* Verify the password reset token that was embedded in the JWT that is in the
* URL.
*
* @param {Function} callback - If no error is given, the token is valid.
*/
Client.prototype.verifyPasswordResetToken = function verifyPasswordResetToken (callback) {
var client = this;
if (typeof callback!=='function') {
throw new Error('client.verifyPasswordResetToken() takes a function as it\'s only argument');
}
var self = this;
self.requestExecutor.execute(
'GET',
self.appHref + '/passwordResetTokens/' + self.sptoken,
client.requestExecutor.execute(
{
method: 'GET',
url: client.appHref + '/passwordResetTokens/' + client.sptoken,
json: true
},
callback

@@ -109,13 +257,33 @@ );

Client.prototype.setAccountPassword = function setAccountPassword(pwTokenVerification,newPassword,callback) {
if(!pwTokenVerification || !pwTokenVerification.href){
throw new Error('invalid pwTokenVerification');
/**
* Given the token resource, set the new password for the user.
*
* @param {object} passwordVerificationTokenResource -
* Example:
* <pre>
* {
* href: 'https://api.stormpath.com/v1/applications/1h72PFWoGxHKhysKjYIkir/passwordResetTokens/3Wog2qMsHyyjD76AWUnnlO'
* }
* </pre>
* @param {Function} callback - If no error is given, the password was reset
* successfully. If an error, the password strength validation error will be
* provided.
*/
Client.prototype.setAccountPassword = function setAccountPassword (passwordVerificationTokenResource,newPassword,callback) {
var client = this;
if (!passwordVerificationTokenResource || !passwordVerificationTokenResource.href) {
throw new Error('invalid passwordVerificationTokenResource');
}
if(!newPassword){
if (!newPassword) {
throw new Error('must supply new password as second argument to client.setAccountPassword()');
}
var self = this;
self.requestExecutor.execute('POST',pwTokenVerification.href,
client.requestExecutor.execute(
{
body: {
method: 'POST',
url: passwordVerificationTokenResource.href,
json: {
password: newPassword

@@ -128,12 +296,31 @@ }

Client.prototype.sendPasswordResetEmail = function sendPasswordResetEmail(emailOrUsername,callback) {
if(typeof emailOrUsername!=='string'){
throw new Error('sendPasswordResetEmail must be called with an email or username as the first argument');
/**
* Given the email, send that account an email with password reset link.
*
* @param {string} email
* @param {Function} callback - The error will indicate if the account could
* not be found. Otherwise, the email was sent.
*/
Client.prototype.sendPasswordResetEmail = function sendPasswordResetEmail (emailOrObject,callback) {
var client = this;
var body;
/*
emailOrObject is a backcompat option, in the future this should be a string-only option
*/
if (typeof emailOrObject==='string') {
body = { email: emailOrObject };
} else if (typeof emailOrObject === 'object') {
body = emailOrObject;
} else {
throw new Error('sendPasswordResetEmail must be called with an email/username as the first argument, or an options object');
}
var self = this;
self.requestExecutor.execute(
'POST',
self.appHref + '/passwordResetTokens',
client.requestExecutor.execute(
{
body: { email: emailOrUsername }
method: 'POST',
url: client.appHref + '/passwordResetTokens',
json: body
},

@@ -140,0 +327,0 @@ callback || utils.noop

@@ -0,4 +1,25 @@

'use strict';
/**
* @function
* From: https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding#Solution_.232_.E2.80.93_rewriting_atob()_and_btoa()_using_TypedArrays_and_UTF-8
*/
function b64EncodeUnicode(str) {
return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function(match, p1) {
return String.fromCharCode('0x' + p1);
}));
}
module.exports = {
base64: require('base64'),
base64: {
atob: function atob(str){
return decodeURIComponent(window.atob(str));
},
btoa: function btoa(str){
var v = b64EncodeUnicode(str);
return v;
}
},
noop: function(){}
};
{
"name": "stormpath-js",
"version": "0.2.0",
"version": "0.4.0",
"description": "A browser-ready javascript library for Stormpath. Use this library if you are building your own ID Site from scratch. Additional features may be added in the future.",

@@ -20,29 +20,31 @@ "main": "lib/index.js",

"license": "Apache-2.0",
"keywords": ["stormpath"],
"keywords": [
"stormpath"
],
"devDependencies": {
"browserify": "^4.2.0",
"browserify": "^11.2.0",
"chai": "^1.9.1",
"grunt": "^0.4.5",
"grunt-browserify": "^2.1.2",
"grunt-browserify": "^4.0.1",
"grunt-bump": "0.0.14",
"grunt-contrib-clean": "^0.5.0",
"grunt-contrib-concat": "^0.4.0",
"grunt-contrib-connect": "^0.8.0",
"grunt-contrib-uglify": "^0.5.0",
"karma": "^0.12.16",
"grunt-karma": "^0.8.3",
"grunt-contrib-watch": "^0.6.1",
"grunt-istanbul": "^0.6.1",
"grunt-karma": "^0.12.1",
"grunt-prompt": "^1.1.0",
"karma": "^0.13.11",
"karma-browserify": "^4.4.0",
"karma-chai": "^0.1.0",
"karma-chrome-launcher": "^0.2.1",
"karma-coverage": "^0.5.3",
"karma-mocha": "^0.2.0",
"load-grunt-tasks": "^0.6.0",
"mocha": "^1.20.1",
"karma-mocha": "^0.1.4",
"karma-chrome-launcher": "^0.1.4",
"karma-browserify": "^0.2.1",
"chai": "^1.9.1",
"karma-chai": "^0.1.0",
"karma-coverage": "^0.2.4",
"grunt-istanbul": "^0.3.0",
"grunt-contrib-clean": "^0.5.0",
"grunt-contrib-connect": "^0.8.0",
"grunt-contrib-concat": "^0.4.0",
"grunt-bump": "0.0.14",
"grunt-prompt": "^1.1.0"
"mocha": "^2.3.3"
},
"dependencies": {
"Base64": "^0.3.0"
"xhr": "^2.1.0"
}
}

@@ -1,5 +0,6 @@

# Stormpath.js - BETA
# Stormpath.js
A browser-ready javascript library for use with Stormpath features. Use this library if you are building your own ID Site from scratch.
Additional features may be added in the future.
A browser-ready javascript library for use with Stormpath features. Use this
library if you are building your own ID Site from scratch. Additional features
may be added in the future.

@@ -9,5 +10,5 @@

In order to use Stormpath.js, your application must be part of a Service-Provider initiated flow.
The client assumes this is true and searches the browser's URL for the secure token
which is needed to initialize the client.
In order to use Stormpath.js, your application must be part of a Service-
Provider initiated flow. The client assumes this is true and searches the
browser's URL for the secure token which is needed to initialize the client.

@@ -18,4 +19,5 @@ For more information please read [Using Stormpath's ID Site to Host your User Management UI](http://docs.stormpath.com/guides/using-id-site)

You may clone this repo and use the `stormpath.min.js` or `stormpath.js` files from the `dist/` folder
by including them in your application with a script tag:
You may clone this repo and use the `stormpath.min.js` or `stormpath.js` files
from the `dist/` folder by including them in your application with a script
tag:

@@ -32,3 +34,3 @@ ````html

You may also install this module via NPM and require it in your [Browerified](http://browserify.org) application:
You may also install this module via NPM and require it in your [Browserify](http://browserify.org) application:

@@ -39,8 +41,6 @@ ````bash

In the near future we will provide this library through our CDN.
### Initialization
To initialize a Stormpath Client which will be used for all API communication, simply create a new instance and pass a callback function:
To initialize a Stormpath Client which will be used for all API communication,
simply create a new instance and pass a callback function:

@@ -64,5 +64,10 @@ ````javascript

* `passwordPolicy`, an object, which provides the password strength policies for the account store which new accounts will be created in.
If null, new accounts are not permitted for the target account store or the store is a social provider store.
* `providers`, which provides your social provider configuration as an array of objects, ordered by account store prioritization.
* `passwordPolicy`, an object, which provides the password strength policies for
the account store which new accounts will be created in. If null, new accounts
are not permitted for the target account store or the store is a social
provider store.
* `providers`, which provides your social provider configuration as an array of
objects, ordered by account store prioritization.
* `logoUrl`, the URL to the logo image

@@ -109,3 +114,6 @@

login: usernameOrEmail,
password: submittedPassword
password: submittedPassword,
accountStore: { // optional
href: 'optional account store href for login attempt'
}
},

@@ -116,4 +124,4 @@ function loginCallback(err,result){

}else{
// login was successful, send the user to the redirectUrl
window.location.replace(result.redirectUrl);
// login was successful, send the user to the serviceProviderCallbackUrl
window.location.replace(result.serviceProviderCallbackUrl);
}

@@ -124,3 +132,3 @@ }

### Login/register a user (Google or Facebook)
### Social Login (Google or Facebook)

@@ -142,4 +150,4 @@ Use the Facebook or Google Javascript Library to prompt the user for login, then pass

}else{
// login was successful, send the user to the redirectUrl
window.location.replace(result.redirectUrl);
// login was successful, send the user to the serviceProviderCallbackUrl
window.location.replace(result.serviceProviderCallbackUrl);
}

@@ -164,7 +172,7 @@ }

function registerCallback(err,result){
if(result.redirectUrl){
// You will be given the redirectUrl if the email verification workflow is
if(result.serviceProviderCallbackUrl){
// You will be given the serviceProviderCallbackUrl if the email verification workflow is
// NOT enabled for this account store, in which case the user can now
// continue to the redirectUrl
window.location.replace(result.redirectUrl);
// continue to the serviceProviderCallbackUrl
window.location.replace(result.serviceProviderCallbackUrl);
}else{

@@ -201,3 +209,9 @@ // tell the user to check their email for a verification link

````javascript
client.sendPasswordResetEmail(email,function(err){
var options = {
email: 'email or username',
accountStore: { // optional
href: 'optional account store href for login attempt'
}
}
client.sendPasswordResetEmail(options,function(err){
if(err){

@@ -253,2 +267,22 @@ // email is invalid, show err.message to user

### 0.4.1
**Not Yet Released**
### 0.4.0
**Released on October 23rd, 2015**
* Refactoring the internal request executor to supply contextual error messages
* Fixing https://github.com/stormpath/idsite-src/issues/2 by not sending cookies
on requests to the API
### 0.3.1
Fixing the base64 encoding strategy, unicode characters are now supported.
### 0.3.0
Adding support for Organizations
### 0.2.0

@@ -255,0 +289,0 @@

@@ -19,3 +19,3 @@ 'use strict';

});
it('should call the callback an idSiteModel',function(){
it('should call the callback with an idSiteModel',function(){
assert.equal(result[1].href,validToken.decoded.app_href+'/idSiteModel');

@@ -28,3 +28,3 @@ });

before(function(done){
client.login({login:'bad',password:'bad'},function(err,value){
new stormpathJs.Client({token:validToken.encoded}).login({login:'bad',password:'bad'},function(err,value){
result = [err,value];

@@ -42,3 +42,3 @@ done();

before(function(done){
client.login({login:'good',password:'good'},function(err,value){
new stormpathJs.Client({token:validToken.encoded}).login({login:'good',password:'good'},function(err,value){
result = [err,value];

@@ -49,3 +49,3 @@ done();

it('should give a redirect url',function(){
assert.equal(result[1].redirectUrl,'the-place-to-go');
assert.equal(result[1].serviceProviderCallbackUrl,'the-place-to-go');
});

@@ -81,3 +81,3 @@ });

it('should give a redirect url',function(){
assert.equal(result[1].redirectUrl,'the-place-to-go');
assert.equal(result[1].serviceProviderCallbackUrl,'the-place-to-go');
});

@@ -84,0 +84,0 @@ });

'use strict';
var stormpathJs = require('../common').stormpath;
var stormpathJs = require('../../lib');

@@ -58,3 +58,3 @@ describe('Request Executor', function () {

it('should not have a new token',function(){
assert.equal(client.requestExecutor.authToken,'');
assert.equal(client.requestExecutor.authToken,null);
});

@@ -61,0 +61,0 @@ });

'use strict';
var stormpathJs = require('../common').stormpath;
var strings = require('../../lib/strings');

@@ -18,7 +19,7 @@ describe('Client', function () {

it('should err',function(){
assert.instanceOf(result[0],Error);
assert.equal(result[0].message,strings.errors.JWT_NOT_FOUND);
});
});
describe('with an invalid JWT', function () {
describe('with a invalid JWT', function () {
var result;

@@ -32,7 +33,7 @@ before(function(done){

it('should err',function(){
assert.instanceOf(result[0],Error);
assert.equal(result[0].message,strings.errors.NOT_A_JWT);
});
});
describe('with an valid JWT', function () {
describe('with a valid JWT', function () {
var requestedAppHref, result;

@@ -47,4 +48,4 @@ var token = require('../data/valid-jwt.json');

requestExecutor: {
execute: function(m,u,cb){
requestedAppHref = u;
execute: function(xhrRequestOptions,cb){
requestedAppHref = xhrRequestOptions.url;
cb(null,{idSiteModel:'abcd1234'});

@@ -63,5 +64,2 @@ done();

});
it('should call the callback with the idSiteModel value',function(){
assert.equal(result[1],'abcd1234');
});

@@ -81,4 +79,4 @@ });

requestExecutor: {
execute: function(m,u,o,cb){
if(u.match(/idSiteModel/)){
execute: function(xhrRequestOptions,cb){
if(xhrRequestOptions.url.match(/idSiteModel/)){
// the first call for the site model

@@ -88,3 +86,3 @@ done();

// the calls to login attempts
calledWith.push(o);
calledWith.push(xhrRequestOptions);
cb();

@@ -122,3 +120,3 @@ }

it('should post that data to the api',function(){
assert.deepEqual(calledWith[0].body,input);
assert.deepEqual(calledWith[0].json,input);
});

@@ -140,5 +138,44 @@ });

it('should post base64 encode the data and post it to the api',function(){
assert.deepEqual(calledWith[1].body,{type:'basic',value:data.encoded});
assert.deepEqual(calledWith[1].json,{type:'basic',value:data.encoded});
});
});
describe('if called with unicode characters', function(){
var result;
var data = require('../data/unicode-password.json');
var input = {
login: data.login,
password: data.password
};
before(function(done){
client.login(input,function(err){
result = [err];
done();
});
});
it('should post the correct base64 encoded string to the API',function(){
assert.deepEqual(calledWith[2].json,{type:'basic',value:data.encoded});
});
});
describe('if called with an account store',function(){
var result;
var data = require('../data/basic-login.json');
var input = {
login: data.login,
password: data.password,
accountStore:{
href: 'abc'
}
};
before(function(done){
client.login(input,function(err){
result = [err];
done();
});
});
it('should pass the account store to the api',function(){
assert.equal(calledWith[3].json.accountStore.href,input.accountStore.href);
});
});
});

@@ -155,4 +192,4 @@

requestExecutor: {
execute: function(m,u,o,cb){
if(u.match(/idSiteModel/)){
execute: function(xhrRequestOptions,cb){
if(xhrRequestOptions.url.match(/idSiteModel/)){
// the first call for the site model

@@ -162,3 +199,3 @@ done();

// the calls to register
calledWith.push([m,u,o]);
calledWith.push([xhrRequestOptions]);
cb();

@@ -186,5 +223,6 @@ }

it('should post that data to the api',function(){
assert.deepEqual(calledWith[0][0],'POST');
expect(calledWith[0][1]).to.have.string('/accounts');
assert.deepEqual(calledWith[0][2].body,data);
var xhrInvocation = calledWith[0][0];
assert.deepEqual(xhrInvocation.method,'POST');
expect(xhrInvocation.url).to.have.string('/accounts');
assert.deepEqual(xhrInvocation.json,data);
});

@@ -205,4 +243,4 @@ });

requestExecutor: {
execute: function(m,u,cb){
if(u.match(/idSiteModel/)){
execute: function(xhrRequestOptions,cb){
if(xhrRequestOptions.url.match(/idSiteModel/)){
// the first call for the site model

@@ -212,3 +250,3 @@ done();

// the calls to verifyEmailToken
calledWith.push([m,u]);
calledWith.push([xhrRequestOptions]);
cb();

@@ -235,5 +273,6 @@ }

it('should post that data to the api',function(){
assert.deepEqual(calledWith[0][0],'POST');
expect(calledWith[0][1]).to.have.string('/v1/accounts/emailVerificationTokens/' + token.decoded.sp_token);
assert.equal(calledWith[0][2],null);
var xhrInvocation = calledWith[0][0];
assert.deepEqual(xhrInvocation.method,'POST');
expect(xhrInvocation.url).to.have.string('/v1/accounts/emailVerificationTokens/' + token.decoded.sp_token);
assert.equal(xhrInvocation.json,null);
});

@@ -254,4 +293,4 @@ });

requestExecutor: {
execute: function(m,u,cb){
if(u.match(/idSiteModel/)){
execute: function(xhrRequestOptions,cb){
if(xhrRequestOptions.url.match(/idSiteModel/)){
// the first call for the site model

@@ -261,3 +300,3 @@ done();

// the calls to verifyPasswordResetToken
calledWith.push([m,u]);
calledWith.push([xhrRequestOptions]);
cb();

@@ -284,5 +323,6 @@ }

it('should post that data to the api',function(){
assert.deepEqual(calledWith[0][0],'GET');
expect(calledWith[0][1]).to.have.string('passwordResetTokens/' + token.decoded.sp_token);
assert.equal(calledWith[0][2],null);
var xhrInvocation = calledWith[0][0];
assert.deepEqual(xhrInvocation.method,'GET');
expect(xhrInvocation.url).to.have.string('passwordResetTokens/' + token.decoded.sp_token);
assert.equal(xhrInvocation.json,true);
});

@@ -304,4 +344,4 @@ });

requestExecutor: {
execute: function(m,u,o,cb){
if(u.match(/idSiteModel/)){
execute: function(xhrRequestOptions,cb){
if(xhrRequestOptions.url.match(/idSiteModel/)){
// the first call for the site model

@@ -311,3 +351,3 @@ done();

// the calls to setAccountPassword
calledWith.push([m,u,o]);
calledWith.push([xhrRequestOptions]);
cb();

@@ -352,5 +392,6 @@ }

it('should post that data to the api',function(){
assert.deepEqual(calledWith[0][0],'POST');
assert.equal(calledWith[0][1],pwTokenVerification.href);
assert.deepEqual(calledWith[0][2],{body:{password:newPassword}});
var xhrInvocation = calledWith[0][0];
assert.deepEqual(xhrInvocation.method,'POST');
assert.equal(xhrInvocation.url,pwTokenVerification.href);
assert.deepEqual(xhrInvocation.json,{password:newPassword});
});

@@ -372,4 +413,4 @@ });

requestExecutor: {
execute: function(m,u,o,cb){
if(u.match(/idSiteModel/)){
execute: function(xhrRequestOptions,cb){
if(xhrRequestOptions.url.match(/idSiteModel/)){
// the first call for the site model

@@ -379,3 +420,3 @@ done();

// the calls to sendPasswordResetEmail
calledWith.push([m,u,o]);
calledWith.push([xhrRequestOptions]);
cb();

@@ -395,3 +436,3 @@ }

describe('if called with correct arugments',function(){
describe('if called with an email',function(){
var emailOrUsername = 'reset@met.com';

@@ -403,11 +444,32 @@ before(function(done){

});
it('should post that data to the api',function(){
assert.deepEqual(calledWith[0][0],'POST');
assert.equal(calledWith[0][1],token.decoded.app_href + '/passwordResetTokens');
assert.deepEqual(calledWith[0][2],{body:{email:emailOrUsername}});
it('should post that email',function(){
var xhrInvocation = calledWith[0][0];
assert.deepEqual(xhrInvocation.method,'POST');
assert.equal(xhrInvocation.url,token.decoded.app_href + '/passwordResetTokens');
assert.deepEqual(xhrInvocation.json,{ email:emailOrUsername });
});
});
describe('if called with an object',function(){
var data = {
email: 'reset@met.com',
accountStore: {
href: 'anHref' + Math.random()
}
};
before(function(done){
client.sendPasswordResetEmail(data,function(){
done();
});
});
it('should post that object',function(){
var xhrInvocation = calledWith[1][0];
assert.deepEqual(xhrInvocation.method,'POST');
assert.equal(xhrInvocation.url,token.decoded.app_href + '/passwordResetTokens');
assert.deepEqual(xhrInvocation.json,data);
});
});
});
});
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc