Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Switched to request library for couch interaction, authorization now …

…works, tidied up CSS etc.
  • Loading branch information...
commit c3b93a892145e6965f3d117fd3792658afcac99e 1 parent 4fc9393
@cliftonc authored
View
5 README
@@ -4,7 +4,7 @@ Initial application skeleton for the NPM registry user reset node app (as per co
* DONE - Look up that user account.
* DONE Mint a token good for 24 hours, and put it in a db (or something) along with the account name
* DONE - Email the token to the email address.
-* TODO - When presented with a valid token, delete the user account out of the db, and tell them to run npm adduser to re-create it.
+* DONE - When presented with a valid token, delete the user account out of the db, and tell them to run npm adduser to re-create it.
Delete account:
@@ -16,8 +16,7 @@ How to use
* 'npm link' to get all the dependencies (you do need nodejs and npm!)
* Set the environment variables:
- COUCH_HOST=localhost
- COUCH_PORT=5984
+ COUCH=localhost:5984
USERDB=_users
ADMIN=adminuser:adminpass
View
91 lib/couch.facade.js
@@ -1,81 +1,60 @@
/**
+ *
* Facade for CouchDB rest calls for user, only implement what is requried
*
* Configuration from ENV
- * COUCH_HOST=localhost
- * COUCH_PORT=5984
+ * COUCH=localhost:5984
* USERDB=_users
* ADMIN=adminuser:adminpass
*/
-var base64 = require('./base64'), http = require('http');
+var base64 = require('./base64'),
+ request = require('request'),
+ sys = require('sys'),
+ headers = {accept:'application/json', 'content-type':'application/json'};
-exports.validateUser = function(username,callback) {
+exports.validateUser = function(username,email,callback) {
/*
* Construct a simple http get based on the env params, assume 'normal' CouchDB Setup?
*/
- var options = http.request({ host: process.env.COUCH_HOST,
- port: process.env.COUCH_PORT,
- path: "/" + process.env.USERDB + "/org.couchdb.user:" + username,
- method: "GET"
- });
-
- var req = http.request(options, function(res) {
- res.on('data', function (chunk) {
- var data = JSON.parse(chunk);
- if(res.statusCode == 200) {
- if(data.error) {
- // We got an error for some reason
- callback(false);
- } else {
- callback(true,data._rev);
- }
- } else {
- callback(false);
- }
-
- });
+ var url = 'http://' + process.env.COUCH + "/" + process.env.USERDB + "/org.couchdb.user:" + username
+
+ request({uri:url, method:'GET', headers:headers}, function (err, response, body) {
+ if (err) callback(false);
+ if (response.statusCode == 200) {
+ // Also check that it is the same email address if it exists in the table
+ var user = JSON.parse(body);
+ if(user.email) {
+ if(user.email != email) {
+ callback(false,user._rev);
+ }
+ } else {
+ callback(true,user._rev);
+ }
+ } else {
+ callback(false);
+ }
});
+
- req.end();
-
};
exports.deleteUser = function(token,callback) {
-
+
/*
* Construct a simple http get based on the env params, assume 'normal' CouchDB Setup?
*/
- var options = http.request({
- host: process.env.COUCH_HOST,
- port: process.env.COUCH_PORT,
- path: "/" + process.env.USERDB + "/org.couchdb.user:" + token.username + '?rev=' + token.revision,
- headers: {'authorization':'Basic ' + base64.encode(process.env.ADMIN)},
- method: "DELETE"
- });
+ var url = 'http://' + process.env.COUCH + "/" + process.env.USERDB + "/org.couchdb.user:" + token.username + '?rev=' + token.revision;
+ headers.authorization = 'Basic ' + base64.encode(process.env.ADMIN);
- console.log(options);
-
- /**
- * Make the request
- */
- var req = http.request(options, function(res) {
- res.on('data', function (chunk) {
-
- console.log("Data: " + chunk);
- if(chunk) {
- if(JSON.parse(chunk).error) {
- callback(false);
- } else {
- callback(res.statusCode == 200 ? true : false);
- }
- } else {
- callback(res.statusCode == 200 ? true : false);
- }
- });
+ request({uri:url, method:'DELETE', headers:headers}, function (err, response, body) {
+ if (err) callback(false);
+ if (response.statusCode == 200) {
+ callback(true);
+ } else {
+ callback(false);
+ }
});
- req.end();
-
};
View
4 lib/emailer.js
@@ -13,8 +13,8 @@ exports.Mailer = {
port: 465,
ssl: true,
use_authentication: true,
- user: "<EMAIL>@gmail.com",
- pass: "<PASSWORD>"
+ user: "clifton.cunningham@gmail.com",
+ pass: "s@ltyAnn"
}
email.send_mail({
View
1  package.json
@@ -16,6 +16,7 @@
"validator" : ">=0.1.7",
"nodemailer" : ">=0.1.8",
"expresso" : ">=0.7.3",
+ "request" : ">=1.9.0",
"should" : ">=0.0.4"
}
}
View
187 public/css/style.css
@@ -16,7 +16,7 @@ body {
#container {
position: relative;
- padding: 10px 20%;
+ padding: 50px 20%;
}
/*--- Basics ---*/
@@ -37,23 +37,10 @@ strong { font-weight: bold; }
em { font-style: italic; }
a { text-decoration: none; color: #333; }
a, h1 a, h2 a { text-decoration: none; }
-a:hover { color: #232323; }
+a:hover { color: #4343A3; }
a:visited:hover { color: #232323; }
a img { border: none; }
-/*--- Lists ---*/
-li ul, li ol { margin: 0; }
-ul, ol { margin: 0 0 1em 2.75em; }
-dt, dd {
- font-style: italic;
- margin: .5em 0;
-}
-dt {
- font-weight: bold;
-}
-dd {
- margin-left: 1em;
-}
/*--- Header ---*/
#header h1 {
margin: .1em 0;
@@ -67,49 +54,6 @@ dd {
line-height: 22px;
}
-/*--- Tables ---*/
-table {
- clear: both;
- width: 100%;
- border-collapse: collapse;
- border-spacing: 0;
- border: 1px solid #e6e6e6;
- background: #eaeafa;
- margin: 12px 0;
-}
-td, th {
- padding: .25em 1em;
- border: 1px solid #a6a6c6;
- vertical-align: middle;
- text-align: left;
- font-weight: normal;
- color: #333;
- font-size: 0.85em;
-}
-
-table tr {
- background: #fff;
-}
-
-table.tabular tr:nth-child(even) {
- background: #eaeafa;
-}
-
-tfoot td {
- background: #d3d3f3;
- color: #333;
- text-align: left;
- padding: 1em 0.5em;
- font-size: 0.7em;
-}
-
-th {
- background: #d3d3f3;
- color: #333;
- text-align: left;
- font-weight: bold;
- padding: .5em .75em;
-}
/*--- Forms ---*/
form {
display: block;
@@ -118,18 +62,6 @@ form {
padding: 1em 2em 2em 2em;
border: 1px solid #a6a6c6;
}
-fieldset {
- padding: 2em;
- margin: 0 0 1em 0;
- border: 1px solid #a6a6c6;
- background: #f3f3f3;
-}
-legend {
- padding: .5em 1em;
- border: 1px solid #a6a6c6;
- background: #fff;
- font-size: 22px;
-}
label {
padding: 0 1em 0 0;
color: #454545;
@@ -154,127 +86,40 @@ input[type=text], input[type=password], textarea {
margin: .5em 0 1em 0;
padding:.5em;
}
-select {
- clear: both;
- display: block;
- margin: .5em 0 1em 0;
-}
-div.checkbox {
- clear: both;
- padding: 1em 0;
-}
-.checkbox label {
- display: inline;
-}
-
input[type=text]:focus, input[type=password]:focus, textarea:focus, select:focus {
border-color: #00a8e6;
outline: none;
}
-
-/*--- Misc ---*/
-hr {
- border: none;
- height: 0;
- border-bottom: 1px solid #e6e6e6;
- margin:1em 0;
-}
-sup, sub {
- color: #666;
- font-size: .65em;
-}
-acronym {
- font-weight: bold;
- font-style: italic;
- color: #333;
-}
-abbr {
- color: #333;
-}
-
-blockquote {
- padding: 0.15em .5em;
- margin: 0.5em 0;
- font-size: 2em;
- color: #666;
- display: block;
- font-style: italic;
-}
-
-blockquote:before, blockquote:after {
- display: inline;
- color: #e5e5e5;
- font-size: 3em;
- position: relative;
- top: 0.25em;
- left: -0.1em;
-}
-
-blockquote:before {
- content: '\D \201C';
-}
-
-
-span.pager-page {
- font-family: Helvetica, Arial, sans-serif;
- padding: 3px 3px;
- margin: 3px 3px 3px 3px;
- color: #454545;
- line-height: 1.25em;
-}
-
-input.pager-page {
- display: inline !important;
- width: 30px;
- font-family: Helvetica, Arial, sans-serif;
- padding: 2px 2px;
- margin: 3px 3px 3px 3px;
- color: #454545;
- line-height: 1.25em;
- clear: none;
-}
-
-a.pager-page {
- font-family: Helvetica, Arial, sans-serif;
- padding: 3px 3px;
- margin: 3px 3px 3px 3px;
+div.messages {
+ padding: 10px;
+ border: solid 1px #efefef;
+ background: #eaeafa;
+ margin-top: 10px;
+ margin-bottom: 20px;
border: 1px solid #a6a6c6;
- color: #454545;
- line-height: 1.25em;
- background-color: #efefef;
-}
-
-blockquote:after {
- content: '\201D';
}
-
pre.code {
padding: 10px;
- color: white;
- background-color: #883434;
+ color: red;
+ background-color: white;
margin-top: 10px;
+ margin-bottom: 20px;
+ border: 1px solid #a6a6c6;
}
/*--- Shadows ---*/
-pre.code {
- -moz-box-shadow: 0 0 3px rgba(0,0,0,.1);
- -webkit-box-shadow: 0 0 3px rgba(0,0,0,.1);
- box-shadow: 0 0 3px rgba(0,0,0,.1);
-}
-table, form {
+
+form {
margin-top: 0px;
margin-bottom: 12px;
}
-table, form, pre > code, .shadow {
+form, pre > code, .shadow, div.messages {
-moz-box-shadow: 2px 2px 12px rgba(0,0,0,.15);
-webkit-box-shadow: 2px 2px 12px rgba(0,0,0,0.15);
box-shadow: 2px 2px 12px rgba(0,0,0,.15);
}
-img.shadow {
- border: 1px solid rgba(255,255,255,.15);
-}
-input[type=text],input[type=password], textarea {
+input[type=text],input[type=password], textarea, pre.code {
-moz-box-shadow: inset 0 0 5px rgba(0,0,0,.2);
-webkit-box-shadow: inset 0 0 5px rgba(0,0,0,.2);
box-shadow: inset 0 0 5px rgba(0,0,0,.2);
View
28 server.js
@@ -1,9 +1,10 @@
/**
* Very lightweight server, use Express to enable a small amount of flex
- * Basic requirements for password reset
+ * Basic requirements for password reset via a token
*
- * TODO: Link to couch to actually delete the user!
+ * Author: clifton.cunningham@gmail.com
*
+ *
*/
var express = require('express'),
tokenRegistry = require('./lib/token.registry').TokenRegistry,
@@ -17,8 +18,7 @@ var express = require('express'),
* Initial configuration of the Express server
*
* Configuration from ENV
- * COUCH_HOST=localhost
- * COUCH_PORT=5984
+ * COUCH=localhost:5984
* USERDB=_users
* ADMIN=adminuser:adminpass
*
@@ -51,10 +51,9 @@ app.set('view engine', 'html');
* Development configuration, enables a '/list' route that shows all tokens
*/
app.configure('development', function() {
-
+
app.use(express.logger());
- app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
-
+ app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
app.set('baseUrl','localhost:3000');
app.set('helpEmail','clifton.cunningham@gmail.com');
@@ -68,7 +67,7 @@ app.configure('development', function() {
/**
* Production configuration, no '/list' route that shows all tokens
*/
-app.configure('production', function() {
+app.configure('production', function() {
app.set('baseUrl','localhost:3000');
app.set('helpEmail','clifton.cunningham@gmail.com');
app.use(express.errorHandler({ dumpExceptions: false, showStack: false }));
@@ -89,10 +88,10 @@ app.post('/reset', function(req,res,next) {
// Mixin params for validator
req.mixinParams();
- var errors = [];
+ var errors = "";
req.onValidationError(function (msg) {
- errors.push(msg);
+ errors += msg + "<br/>";
});
//Validate user input
@@ -114,12 +113,10 @@ app.post('/reset', function(req,res,next) {
* TODO: WE SHOULD MAKE SURE THE USER IS IN NPM AT THIS POINT
* account details are in token.username / token.email
*/
- couch.validateUser(req.params.username,function(isValid,revision) {
+ couch.validateUser(req.params.username,req.params.email,function(isValid,revision) {
if(isValid) {
- console.log("Revision: " + revision);
-
// We need to store the revision to delete it
tokenRegistry.setRevision(tokenId,revision);
@@ -153,7 +150,7 @@ app.post('/reset', function(req,res,next) {
} else {
- responseData = {message:'There were errors in the information you entered: <br><pre class="code">' + JSON.stringify(errors) + '</pre>'};
+ responseData = {message:'There were errors in the information you entered: <br><pre class="code">' + errors + '</pre>'};
res.render("reset",{locals:responseData});
}
@@ -167,8 +164,7 @@ app.get('/confirm/:tokenId', function(req,res,next) {
tokenRegistry.getToken(req.params.tokenId,function(err,token) {
- if(!err) {
-
+ if(!err) {
/**
* TODO: IF YOU GET TO THIS POINT YOU CAN NOW RESET THE ACCOUNT
* account details are in token.username / token.email
View
4 views/confirm.html
@@ -2,7 +2,7 @@
<% if(err != null) { %>
<%= err.message %>
<% } else { %>
- Your account will now been reset, you will receive an email when it is completed. Do not refresh this page as your one time token has now been deleted.
+ Your account has now been deleted, and can be recreated via 'npm adduser'.
<% }%>
</div>
-<a href="/">Return</a>
+<a href="/"><< Return to Reset Form</a>
View
8 views/home.html
@@ -1,9 +1,9 @@
<p>Please use the form below to request that your account be reset:</p>
<form method="post" action="/reset">
- <p><label for="username">NPM Username:</label><input type="text" name="username" /></p>
- <p><label for="email">NPM Email:</label><input type="text" name="email" /></p>
+ <p><label for="username">Username:</label><input type="text" name="username" /></p>
+ <p><label for="email">Email:</label><input type="text" name="email" /></p>
<p>
- <button class="button-submit" type="submit" value="Update">Submit</button>
+ <button class="button-submit" type="submit" value="Update">Reset</button>
</p>
</form>
-<p>If you have forgotten your details, please re-type 'npm adduser' it will tell you your current configured settings (assuming this is the account that you would like reset).</p>
+<p style='font-size: 0.9em; color: grey;'><i>If you have forgotten your details, please re-type 'npm adduser' it will tell you your current configured settings (assuming this is the account that you would like reset).</i></p>
View
4 views/layout.html
@@ -1,12 +1,12 @@
<html>
<head>
- <title>NPM User Reset</title>
+ <title>CouchDB _User Reset</title>
<link rel="stylesheet" href="/css/style.css" />
</head>
<body>
<div id="container">
<div id="header">
- <h1>NPM User Reset</h1>
+ <h1>User Reset</h1>
</div>
<div id="content">
<%- body %>
View
2  views/reset.html
@@ -1,5 +1,5 @@
<div class='messages'>
<%- message %>
</div>
-<a href="/">Return</a>
+<a href="/"><< Return to Reset Form</a>
<!-- kind of pointless page but here just in case we want more info -->
Please sign in to comment.
Something went wrong with that request. Please try again.