diff --git a/env.sample b/env.sample index 1594571..80e9951 100644 --- a/env.sample +++ b/env.sample @@ -16,11 +16,6 @@ export MONGO_URL='mongodb://localhost/makeapi' # Host and port for your Elastic search cluster export ELASTIC_SEARCH_URL='http://localhost:9200' -# A List of allowed users for write operations to the database -# List in this format: "user:pass,user2:pass" -# You shouldn't use this username/password combo yourself -export ALLOWED_USERS='testuser:password' - # Persona export AUDIENCE="http://localhost:7777" diff --git a/lib/middleware.js b/lib/middleware.js index c651d2f..f4ae5d9 100644 --- a/lib/middleware.js +++ b/lib/middleware.js @@ -10,11 +10,10 @@ var http = require( "http" ), hawkModule = require( "./hawk" )(), tags = require( "./tags" )(); - -module.exports = function( makeModel, apiUserModel ) { +module.exports = function( makeModel, apiAppModel ) { var Make = makeModel, hawkOptions = {}, - credentialsLookupStrategy = require( "./strategy" )( apiUserModel, env.get( "USE_DEV_KEY_LOOKUP" ) ), + credentialsLookupStrategy = require( "./strategy" )( apiAppModel, env.get( "USE_DEV_KEY_LOOKUP" ) ), LOGIN_API = env.get( "LOGIN_SERVER_URL_WITH_AUTH" ); // API Key write permissions feature flag diff --git a/lib/models/apiUser.js b/lib/models/apiApp.js similarity index 85% rename from lib/models/apiUser.js rename to lib/models/apiApp.js index 0aef2b4..2128040 100644 --- a/lib/models/apiUser.js +++ b/lib/models/apiApp.js @@ -16,6 +16,10 @@ required: true, unique: true }, + domain: { + type: String, + required: true, + }, revoked: { type: Boolean, required: true, @@ -33,8 +37,8 @@ } }); - var ApiUser = mongoose.model( "ApiUser" , schema ); + var ApiApp = mongoose.model( "ApiApp" , schema ); - return ApiUser; + return ApiApp; }; diff --git a/lib/models/make.js b/lib/models/make.js index 6b4e88e..1cd4a0d 100644 --- a/lib/models/make.js +++ b/lib/models/make.js @@ -163,7 +163,7 @@ module.exports = function( mongoInstance ) { Make.createMapping(function( err, mapping ) { if ( err ) { - console.log( "failed to create mapping", err.toString() ); + console.log( "Failed to create mapping. Is ElasticSearch Running?\n", err.toString() ); } }); diff --git a/lib/strategy.js b/lib/strategy.js index 574d584..eb03573 100644 --- a/lib/strategy.js +++ b/lib/strategy.js @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ -module.exports = function( ApiUser, devMode ) { +module.exports = function( ApiApp, devMode ) { var DEVKEY = "00000000-0000-0000-000000000000", uuid = require( "uuid" ); @@ -26,7 +26,7 @@ module.exports = function( ApiUser, devMode ) { algorithm: "sha256", user: publickey }; - ApiUser.findOne({ publickey: publickey }, function( err, doc ) { + ApiApp.findOne({ publickey: publickey }, function( err, doc ) { if ( err || !doc ) { return callback( err ); } diff --git a/migrations/20140206-apiApp.js b/migrations/20140206-apiApp.js new file mode 100644 index 0000000..2b372f6 --- /dev/null +++ b/migrations/20140206-apiApp.js @@ -0,0 +1,101 @@ +/* This script will migrate all ApiUser records into ApiApp records + * + * run this script from the root of the project like so: + * node migrations/20140206-apiApp :: :: ... + */ + +var habitat = require( "habitat" ), + async = require( "async" ), + validate = require( "mongoose-validator" ).validate, + slicedArgs = process.argv.slice( 2 ), + mongoStreamEnded = false, + env, + mongoose; + +var domainMap = {}; + +slicedArgs.forEach(function( arg ) { + arg = arg.split( '::' ); + domainMap[ arg[0] ] = arg[1]; +}); + +function getApiUser( mongoose ) { + return mongoose.model( "ApiUser" , new mongoose.Schema({ + privatekey: { + type: String, + required: true, + unique: true + }, + publickey: { + type: String, + required: true, + unique: true + }, + revoked: { + type: Boolean, + required: true, + "default": false + }, + contact: { + type: String, + required: true, + validate: validate( "isEmail" ) + }, + admin: { + type: Boolean, + required: true, + "default": false + } + })); +} + +habitat.load(); +env = new habitat(); + +dbh = require( "../lib/mongoose" )( env, function( err ) { + if ( err ) { + console.log( err ); + process.exit( 1 ); + } + + var ApiApp = require( "../lib/models/apiApp" )( env, dbh.mongoInstance() ), + ApiUser = getApiUser( dbh.mongoInstance() ), + stream = ApiUser.find().stream(), + queue = async.queue(function( doc, done ) { + + var app = new ApiApp({ + contact: doc.contact, + privatekey: doc.privatekey, + publickey: doc.publickey, + domain: domainMap[ doc.contact ], + revoked: doc.revoked, + admin: doc.admin + }); + + app.save(function( err ) { + if ( err ) { + console.log( "Failure saving document:" ); + console.log( app ); + console.log( err ); + process.exit( 1 ); + } + done(); + }); + }, 4 );// concurrency of 4 + + queue.drain = function() { + if ( mongoStreamEnded ) { + console.log( "completed!" ); + process.exit( 0 ); + } + }; + + stream.on( "data", function onData( doc ) { + queue.push( doc ); + }).on( "error", function( err ) { + console.log( err ); + process.exit( 1 ); + }).on( "end", function() { + mongoStreamEnded = true; + }); +}); diff --git a/public/js/admin.js b/public/js/admin.js index f779d39..eebdf19 100644 --- a/public/js/admin.js +++ b/public/js/admin.js @@ -517,13 +517,14 @@ document.addEventListener( "DOMContentLoaded", function() { pager.goToPage( 1 ); var contactEmail = document.querySelector( "#app-contact"), - createUser = document.querySelector( "#add-user" ), - createResult = document.querySelector( "#user-result" ); + domain = document.querySelector( "#app-domain" ), + createApp = document.querySelector( "#add-app" ), + createResult = document.querySelector( "#app-result" ); function generateKeys() { var request = new XMLHttpRequest(); - request.open( "POST", "/admin/api/user", true ); + request.open( "POST", "/admin/api/app", true ); request.setRequestHeader( "X-CSRF-Token", csrfToken ); // express.js uses a non-standard name for csrf-token request.setRequestHeader( "Content-Type", "application/json; charset=utf-8" ); request.onreadystatechange = function() { @@ -545,13 +546,14 @@ document.addEventListener( "DOMContentLoaded", function() { } }; request.send(JSON.stringify({ - contact: contactEmail.value + contact: contactEmail.value, + domain: domain.value })); } if ( isAdmin ) { - createUser.addEventListener( "keypress", function( e ) { + createApp.addEventListener( "keypress", function( e ) { if ( e.which === 13 ) { e.preventDefault(); e.stopPropagation(); @@ -559,7 +561,7 @@ document.addEventListener( "DOMContentLoaded", function() { } }, false ); - createUser.addEventListener( "click", generateKeys, false ); + createApp.addEventListener( "click", generateKeys, false ); } // Remix Counter diff --git a/routes/admin.js b/routes/admin.js index 67220b5..8b60d31 100644 --- a/routes/admin.js +++ b/routes/admin.js @@ -8,9 +8,9 @@ var env = require( "../lib/environment" ); -module.exports = function( apiUserModel ) { +module.exports = function( apiAppModel ) { var uuid = require( "uuid" ), - ApiUser = apiUserModel, + App = apiAppModel, audience = env.get( "AUDIENCE" ), login = env.get( "LOGIN_SERVER" ), personaHostname = env.get( "PERSONA_HOSTNAME", "https://login.persona.org" ); @@ -35,25 +35,25 @@ module.exports = function( apiUserModel ) { personaHostname: personaHostname }); }, - addUser: function( req, res ) { - var newUser = req.body; + addApp: function( req, res ) { + var newApp = req.body; - if ( !newUser.contact ) { + if ( !newApp.contact || !newApp.domain ) { return res.json( 400, { error: "Missing data" } ); } - newUser.privatekey = uuid.v4(); - newUser.publickey = uuid.v4(); - newUser.revoked = false; - newUser.admin = false; + newApp.privatekey = uuid.v4(); + newApp.publickey = uuid.v4(); + newApp.revoked = false; + newApp.admin = false; - var user = new ApiUser( newUser ); + var app = new App( newApp ); - user.save(function( err, user ) { + app.save(function( err, app ) { if ( err ) { res.json( 500, { error: err } ); } else { - res.json( { user: user } ); + res.json( { app: app } ); } }); } diff --git a/routes/index.js b/routes/index.js index 6a4e434..dfcbd93 100755 --- a/routes/index.js +++ b/routes/index.js @@ -4,9 +4,9 @@ var env = require( "../lib/environment" ); -module.exports = function routesCtor( makeModel, apiUserModel ) { +module.exports = function routesCtor( makeModel, apiAppModel ) { var makeRoutes = require( "./make" )( makeModel ), - adminRoutes = require( "./admin" )( apiUserModel ); + adminRoutes = require( "./admin" )( apiAppModel ); return { index: function( req, res ) { @@ -22,6 +22,6 @@ module.exports = function routesCtor( makeModel, apiUserModel ) { healthcheck: makeRoutes.healthcheck, admin: adminRoutes.admin, login: adminRoutes.login, - addUser: adminRoutes.addUser + addApp: adminRoutes.addApp }; }; diff --git a/scripts/generateKeys.js b/scripts/generateKeys.js index bb6434e..43df962 100644 --- a/scripts/generateKeys.js +++ b/scripts/generateKeys.js @@ -28,27 +28,27 @@ dbh = require( "../lib/mongoose" )( env, function( err ) { process.exit( 1 ); } - var ApiUser = require( "../lib/models/apiUser" )( env, dbh.mongoInstance() ), - users = []; + var ApiApp = require( "../lib/models/apiApp" )( env, dbh.mongoInstance() ), + apps = []; for ( var i = 0; i < numPairs; i++ ) { - users.push( new ApiUser({ + apps.push( new ApiApp({ contact: contactEmail, privatekey: uuid.v4(), publickey: uuid.v4(), revoked: false, - admin: !!isAdmin + admin: !!isAdmin // This means "Internal Webmaker" })); } - async.eachSeries( users, function( user, cb ) { - user.save(function( err, user ){ + async.eachSeries( apps, function( app, cb ) { + app.save(function( err, app ){ if ( err ) { return cb( err ); } console.log( "Keys generated for %s\nPRIVATEKEY: %s\nPUBLICKEY: %s\nadmin: %s", - contactEmail, user.privatekey, user.publickey, isAdmin ); + contactEmail, app.privatekey, app.publickey, isAdmin ); cb(); }); }, function done( err ) { diff --git a/server.js b/server.js index 5e21b63..840bb2d 100755 --- a/server.js +++ b/server.js @@ -19,7 +19,7 @@ var app = express(), env = require( "./lib/environment" ), Mongo = require( "./lib/mongoose" )(), Make = require( "./lib/models/make" )( Mongo.mongoInstance() ), - ApiUser = require( "./lib/models/apiUser" )( Mongo.mongoInstance() ), + apiApp = require( "./lib/models/apiApp" )( Mongo.mongoInstance() ), nunjucksEnv = new nunjucks.Environment( new nunjucks.FileSystemLoader( path.join( __dirname + "/views" ) ), { autoescape: true } ), csrfMiddleware = express.csrf(), webmakerAuth = new WebmakerAuth({ @@ -81,8 +81,8 @@ app.use(express.static(tmpDir)); app.use( app.router ); -var routes = require( "./routes" )( Make, ApiUser ), - middleware = require( "./lib/middleware" )( Make, ApiUser ); +var routes = require( "./routes" )( Make, apiApp ), + middleware = require( "./lib/middleware" )( Make, apiApp ); app.use( middleware.errorHandler ); app.use( middleware.fourOhFourHandler ); @@ -127,7 +127,7 @@ app.get( "/login", csrfMiddleware, routes.login ); app.get( "/admin", csrfMiddleware, middleware.collabAuth, routes.admin ); // Admin tool path for generating Hawk Keys -app.post( "/admin/api/user", csrfMiddleware, middleware.adminAuth, Mongo.isDbOnline, routes.addUser ); +app.post( "/admin/api/app", csrfMiddleware, middleware.adminAuth, Mongo.isDbOnline, routes.addApp ); // Serve makeapi-client.js over http app.get( "/js/make-api.js", function( req, res ) { diff --git a/views/admin.html b/views/admin.html index 708f6ee..010d271 100644 --- a/views/admin.html +++ b/views/admin.html @@ -145,14 +145,20 @@

Remix Count

- +
- +
- - + +
+ +
+
+
+ +