basic auth structure with helper functions and skeleton modules

This commit is contained in:
Chris Raynor
2013-12-26 17:31:20 -08:00
parent 6b18b57a02
commit dce6967a6f
5 changed files with 276 additions and 15 deletions

View File

@@ -1,9 +1,10 @@
#!/usr/bin/env node
var optimist = require('optimist'),
argv = optimist.usage('Usage: firebase (auth|app)').argv,
app = require('../lib/app')
auth = require('../lib/auth');
argv = optimist.usage('Usage: firebase').argv,
Auth = require('../lib/auth'),
auth = new Auth(argv),
App = require('../lib/app');
if (argv._.length === 0) {
@@ -11,15 +12,24 @@ if (argv._.length === 0) {
optimist.showHelp();
} else {
// Router
// Top-level router
switch (argv._[0]) {
case 'app':
app(argv);
case 'refreshtoken':
auth.login(
function(email, token) {
console.log('New token saved for ' + email + ': ' + token);
},
function() {
console.log("Sorry, we couldn't refresh the token");
},
this
);
break;
case 'auth':
auth(argv);
case 'app':
new App(auth, argv);
break;
default:
// No route found
optimist.showHelp();
}
}

48
lib/api.js Normal file
View File

@@ -0,0 +1,48 @@
var https = require('https'),
querystring = require('querystring')
/**
* Static API methods.
*/
var Api = {
request: function(method, resource, data, callback, scope) {
if (typeof(scope) === 'undefined') {
var scope = this;
}
// TODO: Add support for other request types
if (method !== 'GET') {
method = 'GET';
}
if (method === 'GET') {
var separator = resource.match(/\?/) ? '&' : '?';
resource += separator + querystring.stringify(data);
}
var options = {
host: 'admin.firebase.com',
path: resource,
port: 443,
method: method
};
var req = https.request(options, function(res) {
var responseString = '';
res.setEncoding('utf8');
res.on('data', function (chunk) {
responseString += chunk;
});
res.on('end', function() {
var response = JSON.parse(responseString);
callback.call(scope, res.statusCode, response);
});
})
req.end();
}
}
module.exports = Api;

View File

@@ -1,5 +1,21 @@
module.exports = app;
var optimist = require('optimist');
function app(argv) {
console.log('app', argv);
function App(auth, argv) {
// TODO: Ensure valid route
var validRoute = true;
if (validRoute) {
auth.requireLogin(function() {
// TODO: App-specific router
console.log('app', argv);
},
function() {
console.log("Sorry, we couldn't log you in");
},
this
);
} else {
optimist.showHelp();
}
}
module.exports = App;

View File

@@ -1,5 +1,191 @@
module.exports = auth;
var prompt = require('prompt'),
fs = require('fs'),
configFile = process.env['HOME'] + '/.firebaserc',
Api = require('./api');
function auth(argv) {
console.log('auth', argv);
/**
* Auth-related methods.
* Stores the current user's credentials and syncs them to disc.
*/
function Auth(argv) {
try {
var data = fs.readFileSync(configFile),
config;
config = JSON.parse(data);
if (typeof(config.authToken) === 'string') {
this.authToken = config.authToken;
} else {
this.authToken = '';
}
if (typeof(config.email) === 'string') {
this.email = config.email;
} else {
this.email = '';
}
} catch (err) {
this.authToken = '';
this.email = '';
}
this.argv = argv;
}
Auth.prototype.validate = function(successCallback, errorCallback, scope) {
if (typeof(scope) === 'undefined') {
var scope = this;
}
Api.request('GET',
'/token/validate',
{
token: this.authToken
},
function(statusCode, response) {
if (response.success) {
if (typeof(successCallback) === 'function') {
successCallback.call(scope);
}
} else {
if (typeof(errorCallback) === 'function') {
errorCallback.call(scope);
}
}
}
);
}
Auth.prototype.loginRequest = function(successCallback, errorCallback, scope) {
if (typeof(scope) === 'undefined') {
var scope = this;
}
var that = this,
schema = {
properties: {
email: {
description: 'Email',
pattern: /@/,
message: 'Must be a valid email address',
required: true
},
password: {
description: 'Password',
hidden: true,
required: true
}
}
};
if (this.email.length > 0) {
schema.properties.email.default = this.email;
}
prompt.override = this.argv;
prompt.message = '';
prompt.delimiter = '';
prompt.get(schema, function(err, result) {
if (err) {
if (typeof(errorCallback) === 'function') {
errorCallback.call(scope);
}
return;
}
that.email = result.email;
that.authenticate(
result.email,
result.password,
successCallback,
errorCallback,
scope
);
});
};
var maxRetries = 3;
Auth.prototype.requireLogin = function(successCallback, errorCallback, scope) {
if (typeof(scope) === 'undefined') {
var scope = this;
}
var that = this;
this.validate(
successCallback,
that.attemptLogin(maxRetries, successCallback, errorCallback, scope),
scope
);
};
Auth.prototype.attemptLogin = function(tries, successCallback, errorCallback, scope) {
var that = this;
return function() {
if (tries > 0) {
if (tries == maxRetries) {
console.log('You need to be logged in to perform this action');
} else {
console.log('Email or password incorrect, please try again');
}
that.loginRequest(
successCallback,
that.attemptLogin(tries - 1, successCallback, errorCallback, scope),
scope
);
} else {
if (typeof(errorCallback) === 'function') {
errorCallback.call(scope);
}
}
}
};
Auth.prototype.login = function(successCallback, errorCallback, scope) {
this.attemptLogin(maxRetries, successCallback, errorCallback, scope)();
};
Auth.prototype.authenticate = function(email, password, successCallback, errorCallback, scope) {
var data = {
email: email,
password: password,
rememberMe: true
};
Api.request(
'GET',
'/account/login',
data,
this.handleLogin(successCallback, errorCallback, scope),
this
);
};
Auth.prototype.handleLogin = function(successCallback, errorCallback, scope) {
return function(statusCode, response) {
var token = response.adminToken;
if (!token) {
if (typeof(errorCallback) === 'function') {
errorCallback.call(scope);
}
return;
}
this.storeToken(token, successCallback, errorCallback, scope);
}
};
Auth.prototype.storeToken = function(token, successCallback, errorCallback, scope) {
this.authToken = token;
var data = {
email: this.email,
authToken: this.authToken
};
var dataString = JSON.stringify(data, null, 2) + "\n";
fs.writeFile(configFile, dataString, function (err) {
if (err) {
if (typeof(errorCallback) === 'function') {
errorCallback.call(scope);
}
return;
}
if (typeof(successCallback) === 'function') {
successCallback.call(scope, data.email, data.authToken);
}
});
};
module.exports = Auth;

View File

@@ -14,7 +14,8 @@
"repository": "https://github.com/firebase/firebase-cli.git",
"homepage": "https://github.com/firebase/firebase-cli",
"dependencies": {
"optimist": "0.6.x"
"optimist": "0.6.x",
"prompt": "0.2.x"
},
"bin": {
"firebase": "./bin/firebase"