From 305dca51657478ba5ff245d1ad42c0b2be16adb7 Mon Sep 17 00:00:00 2001 From: Gevorg Harutyunyan Date: Sat, 11 Jun 2016 01:52:08 +0400 Subject: [PATCH] Moving to babel and mocha. --- .babelrc | 3 + .npmignore | 2 + README.md | 7 +- bin/htdigest | 3 +- .../test-processor-integration.coffee | 0 {tests => bin}/test-utils.coffee | 0 package.json | 22 ++-- src/htdigest.coffee | 7 -- src/htdigest.js | 30 ++++++ src/processor.coffee | 77 ------------- src/processor.js | 101 ++++++++++++++++++ src/program.coffee | 23 ---- src/utils.coffee | 20 ---- src/utils.js | 26 +++++ test/processor.js | 90 ++++++++++++++++ test/utils.js | 37 +++++++ tests/test-processor.coffee | 20 ---- 17 files changed, 310 insertions(+), 158 deletions(-) create mode 100644 .babelrc rename {tests => bin}/test-processor-integration.coffee (100%) rename {tests => bin}/test-utils.coffee (100%) delete mode 100644 src/htdigest.coffee create mode 100644 src/htdigest.js delete mode 100644 src/processor.coffee create mode 100644 src/processor.js delete mode 100644 src/program.coffee delete mode 100644 src/utils.coffee create mode 100644 src/utils.js create mode 100644 test/processor.js create mode 100644 test/utils.js delete mode 100644 tests/test-processor.coffee diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..c13c5f6 --- /dev/null +++ b/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["es2015"] +} diff --git a/.npmignore b/.npmignore index 2215570..8b37476 100644 --- a/.npmignore +++ b/.npmignore @@ -4,3 +4,5 @@ node_modules .idea htdigest.iml .settings +src +test \ No newline at end of file diff --git a/README.md b/README.md index 33d053a..e6e1261 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ $ htdigest [-c] passwordfile realm username ## Running tests -It uses [nodeunit](https://github.com/caolan/nodeunit/), so just run following command in package directory: +It uses [mocha](https://mochajs.org/), so just run following command in package directory: ```bash $ npm test @@ -50,8 +50,9 @@ You can find list of issues using **[this link](http://github.com/http-auth/htdi ## Development dependencies - - **[coffee-script](http://coffeescript.org/)** - CoffeeScript is a little language that compiles into JavaScript. - - **[nodeunit](https://github.com/caolan/nodeunit/)** - Easy unit testing in node.js and the browser, based on the assert module. + - **[babel](https://babeljs.io/)** - compiler for writing next generation JavaScript.. + - **[mocha](https://mochajs.org/)** - simple, flexible, fun javascript test framework for node.js & the browser. + - **[chai](http://chaijs.com/)** - BDD / TDD assertion framework for node.js and the browser that can be paired with any testing framework. ## License diff --git a/bin/htdigest b/bin/htdigest index c830429..a40c8e5 100644 --- a/bin/htdigest +++ b/bin/htdigest @@ -1,3 +1,4 @@ #!/usr/bin/env node -require("../gensrc/htdigest"); \ No newline at end of file +var settings = require('../package.json'); +require("../gensrc/htdigest").default(settings.version, process.argv); \ No newline at end of file diff --git a/tests/test-processor-integration.coffee b/bin/test-processor-integration.coffee similarity index 100% rename from tests/test-processor-integration.coffee rename to bin/test-processor-integration.coffee diff --git a/tests/test-utils.coffee b/bin/test-utils.coffee similarity index 100% rename from tests/test-utils.coffee rename to bin/test-utils.coffee diff --git a/package.json b/package.json index 4a01bf7..5481558 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "htdigest", "description": "Node.js package for HTTP Digest Authentication password file utility.", - "version": "2.1.1", + "version": "2.1.2", "author": "Gevorg Harutyunyan (http://github.com/gevorg)", "maintainers": [ { @@ -33,16 +33,24 @@ "prompt": "^1.0.0" }, "devDependencies": { - "coffee-script": "^1.10.0", - "nodeunit": "^0.9.1" + "babel-cli": "^6.9.0", + "babel-preset-es2015": "^6.9.0", + "mocha": "^2.5.3", + "chai": "^3.5.0" }, "engines": { "node": ">=0.4.1" }, "scripts": { - "test": "node ./node_modules/nodeunit/bin/nodeunit tests", - "prepublish": "rm -rf gensrc && node ./node_modules/coffee-script/bin/coffee --compile -o gensrc src", - "pretest": "npm run prepublish" + "test": "mocha --compilers js:babel-core/register", + "compile": "babel src -d gensrc", + "prepublish": "npm run compile", + "pretest": "npm run compile" }, - "keywords": ["htdigest", "http", "digest", "authentication"] + "keywords": [ + "htdigest", + "http", + "digest", + "authentication" + ] } diff --git a/src/htdigest.coffee b/src/htdigest.coffee deleted file mode 100644 index 65e0d24..0000000 --- a/src/htdigest.coffee +++ /dev/null @@ -1,7 +0,0 @@ -# Importing local modules. -program = require './program' -processor = require './processor' - -# Parses and processes command line arguments. -program.parse process.argv -processor.process program \ No newline at end of file diff --git a/src/htdigest.js b/src/htdigest.js new file mode 100644 index 0000000..ed8f1c6 --- /dev/null +++ b/src/htdigest.js @@ -0,0 +1,30 @@ +'use strict'; + +// Importing local modules. +import program from 'commander' +import * as processor from './processor' + +// Parses and processes command line arguments. +export default function(version, args) { + // Setup. + program + .version(version) + .usage("[options] passwordfile realm username") + .option('-c, --create', "Create a new file."); + + // Help option. + program.on('--help', function () { + console.log(` + Examples: + + htdigest [-c] passwordfile realm username + + `); + }); + + // Parse options. + program.parse(args); + + // Process program output. + processor.exec(program); +} \ No newline at end of file diff --git a/src/processor.coffee b/src/processor.coffee deleted file mode 100644 index 830fa33..0000000 --- a/src/processor.coffee +++ /dev/null @@ -1,77 +0,0 @@ -# Need utility module. -utils = require './utils' - -# FS module. -fs = require 'fs' - -# Prompt module. -prompt = require 'prompt' - -## Module for processing command. -module.exports = - - # Read password. - readPassword: (program) -> - # Prepare prompt. - prompt.message = "" - prompt.delimiter = "" - - # Prepare options. - options = [ - {name: 'password', description: 'New password:', hidden: true}, - {name: 'rePassword', description: 'Re-type new password:', hidden: true} - ] - - # Try to read password. - prompt.get options, (err, result) -> - if not err and result.password is result.rePassword - program.args.push result.password - module.exports.finalize program - else - console.error "\nPassword verification error." - - # Processing command. - process: (program) -> - if program.args.length is 3 - module.exports.readPassword program - else - program.help() - - # Finalizes processing by printing output or changing password file. - finalize: (program) -> - try - module.exports.syncFile program - catch error - console.error error.message - - # Sync file with new data. - syncFile: (program) -> - passwordFile = program.args[0] - realm = program.args[1] - username = program.args[2] - writeData = utils.encode program - - found = false - newLines = [] - - if not program.create - if not fs.existsSync passwordFile - console.error "Cannot modify file #{passwordFile}; use '-c' to create it." - return - - lines = (fs.readFileSync passwordFile, 'UTF-8').split "\n" - - for line, i in lines - if (line.indexOf "#{username}:#{realm}:") is 0 - found = true - newLines.push writeData - console.log "Changing password for user #{username} in realm #{realm}." - else if line # Remove empty lines. - newLines.push line - - if not found # Adding user to existing file. - newLines.push writeData - console.log "Adding password for user #{username} in realm #{realm}." - - # Write data. - fs.writeFileSync passwordFile, (newLines.join "\n") + "\n", 'UTF-8' \ No newline at end of file diff --git a/src/processor.js b/src/processor.js new file mode 100644 index 0000000..a6d70fb --- /dev/null +++ b/src/processor.js @@ -0,0 +1,101 @@ +"use strict"; + +// Utils. +import * as utils from './utils' + +// FS. +import fs from 'fs' + +// Prompt module. +import prompt from 'prompt' + +// Sync file function. +export function syncFile(program) { + // Read params. + let passwordFile = program.args[0]; + let realm = program.args[1]; + let username = program.args[2]; + + // Encode file data. + let writeData = utils.encode(program); + + // Collectors. + let found = false; + let newLines = []; + + // Not creating file. + if (!program.create) { + // Check if file exists. + if (!fs.existsSync(passwordFile)) { + console.error(`Cannot modify file ${passwordFile}; use '-c' to create it.`); + return + } + + // Read lines. + let lines = fs.readFileSync(passwordFile, 'UTF-8').split("\n"); + + // Loop lines. + lines.forEach(line => { + if (line.indexOf(`${username}:${realm}:`) === 0) { + found = true; + newLines.push(writeData); + console.log(`Changing password for user ${username} in realm ${realm}.`); + } else { + newLines.push(line); + } + }); + } + + // Adding user to existing file. + if (!found) { + newLines.push(writeData); + console.log(`Adding password for user ${username} in realm ${realm}.`); + } + + // Write data. + fs.writeFileSync(passwordFile, newLines.join("\n") + "\n", 'UTF-8'); +} + +// Read password. +export function readPassword(program) { + prompt.message = ""; + prompt.delimiter = ""; + + let passportOption = [{name: 'password', description: 'New password:', hidden: true}]; + let rePassportOption = [{name: 'rePassword', description: 'Re-type new password:', hidden: true}]; + + // Try to read password. + setTimeout(function () { + prompt.get(passportOption, function (err, result) { + if (!err) { + let password = result.password; + setTimeout(function () { + prompt.get(rePassportOption, function (err, result) { + if (!err && password == result.rePassword) { + program.args.push(password); + + try { + syncFile(program); + } catch (err) { + console.error(err.message); + } + } else { + console.error("\nPassword verification error."); + } + }); + }, 50); + } else { + console.error("\nPassword verification error."); + } + }); + }, 50); +} + +// Process command. +export function exec(program) { + if (program.args.length === 3) { + readPassword(program); + } else { + program.help(); + } +} \ No newline at end of file diff --git a/src/program.coffee b/src/program.coffee deleted file mode 100644 index cfa6f81..0000000 --- a/src/program.coffee +++ /dev/null @@ -1,23 +0,0 @@ -# Importing package.json for version info. -settings = require '../package.json' - -# Importing commander module. -program = require 'commander' - -# Setting up program. -program - .version(settings.version) - .usage("[options] passwordfile realm username") - .option('-c, --create', "Create a new file.") - -# Custom help. -program.on '--help', () -> - console.log """ - Examples: - - htdigest [-c] passwordfile realm username - - """ - -# Exporting program. -module.exports = program \ No newline at end of file diff --git a/src/utils.coffee b/src/utils.coffee deleted file mode 100644 index 5212afb..0000000 --- a/src/utils.coffee +++ /dev/null @@ -1,20 +0,0 @@ -# Importing crypto module. -crypto = require 'crypto' - -# Module for utility functionalities. -module.exports = - - # MD5 hash. - md5: (str) -> - hash = crypto.createHash 'MD5' - hash.update str - hash.digest 'hex' - - # Encoding program digest. - encode: (program) -> - passwordFile = program.args[0] - realm = program.args[1] - username = program.args[2] - password = program.args[3] - - "#{username}:#{realm}:" + @md5 "#{username}:#{realm}:#{password}" diff --git a/src/utils.js b/src/utils.js new file mode 100644 index 0000000..23af09a --- /dev/null +++ b/src/utils.js @@ -0,0 +1,26 @@ +"use strict"; + +// Importing crypto module. +import crypto from 'crypto' + +// md5 function. +export function md5(str) { + let hash = crypto.createHash('MD5'); + hash.update(str); + + return hash.digest('hex'); +} + +// encode function. +export function encode(program) { + // Prepare arguments. + let realm = program.args[1]; + let username = program.args[2]; + let password = program.args[3]; + + // Generate hash. + let hash = md5(`${username}:${realm}:${password}`); + + // Final result. + return `${username}:${realm}:${hash}`; +} \ No newline at end of file diff --git a/test/processor.js b/test/processor.js new file mode 100644 index 0000000..27051f2 --- /dev/null +++ b/test/processor.js @@ -0,0 +1,90 @@ +"use strict"; + +// FS. +import fs from 'fs' + +// Expect module. +import {expect} from 'chai'; + +// Source. +import * as processor from '../gensrc/processor' + +// Processor. +describe('processor', function () { + // Tests for syncFile. + describe('#syncFile', function () { + afterEach(function() { + if (fs.existsSync("password.txt")) { + fs.unlinkSync("password.txt"); + } + }); + + it('file create', function () { + // Input. + let program = { + 'create': true, + 'args': ["password.txt", "sho", "gevorg", "loser"] + }; + + // Source. + processor.syncFile(program); + + // Expectation. + let fileData = fs.readFileSync("password.txt", 'UTF-8'); + expect(fileData).to.equal("gevorg:sho:c188621dd651b5d3da4d3a1d3553ebcb\n"); + }); + + it('file update', function () { + // Prepare file. + fs.writeFileSync("password.txt", "gevorg:sho:c188621dd651b5d3da4d3a1d3553ebcb", 'UTF-8'); + + // Input. + let program = { + 'args': ["password.txt", "sho", "gevorg", "winner"] + }; + + // Source. + processor.syncFile(program); + + // Expectation. + let fileData = fs.readFileSync("password.txt", 'UTF-8'); + expect(fileData).to.equal("gevorg:sho:8acff7c997e8afb4831290c93db09c95\n"); + }); + + it('file add', function () { + // Prepare file. + let initData = "gevorg:sho:8acff7c997e8afb4831290c93db09c95"; + fs.writeFileSync("password.txt", initData, 'UTF-8'); + + // Input. + let program = { + 'args': ["password.txt", "thegreat", "tigran", "sea"] + }; + + // Source. + processor.syncFile(program); + + // Expectation. + let fileData = fs.readFileSync("password.txt", 'UTF-8'); + expect(fileData).to.equal(`${initData}\ntigran:thegreat:07e9e983c2c8d2c20826350dae5e72fc\n`); + }); + + it('file add, not existing', function () { + // Input. + let program = { + 'args': ["password.txt", "losers", "serob", "dragon"] + }; + + let preservedLog = console.log; + console.error = function () { + console.error = preservedLog; + console.error.apply(console, arguments); + + expect(arguments[0]).to.equal("Cannot modify file password.txt; use '-c' to create it."); + }; + + // Source. + processor.syncFile(program); + }); + }); +}); \ No newline at end of file diff --git a/test/utils.js b/test/utils.js new file mode 100644 index 0000000..d067680 --- /dev/null +++ b/test/utils.js @@ -0,0 +1,37 @@ +"use strict"; + +// Expect module. +import {expect} from 'chai'; + +// Source. +import * as utils from '../gensrc/utils' + +// Utils +describe('utils', function () { + // Tests for md5 + describe('#md5', function () { + it('hash should be correct', function () { + // Source. + let hash = utils.md5("devochka"); + + // Expectation. + expect(hash).to.equal("490db6b7628ee087f416f954682d0b08"); + }); + }); + + // Tests for encode + describe('#encode', function () { + it('encoded result should be correct', function () { + // Prepare input. + var input = { + 'args': ["password.txt", "superRealm", "superUser"] + }; + + // Source. + let encoded = utils.encode(input); + + // Expectation. + expect(encoded).to.equal("superUser:superRealm:d60f8a9654592b85bfc0474dfa604906"); + }); + }); +}); diff --git a/tests/test-processor.coffee b/tests/test-processor.coffee deleted file mode 100644 index ef15465..0000000 --- a/tests/test-processor.coffee +++ /dev/null @@ -1,20 +0,0 @@ -# Importing module. -processor = require '../gensrc/processor' - -module.exports = - - # Test for process password function. - testProcessPassword: (test) -> - program = {'args': ["someText.txt", "someRealm", "someUser"]} - processor.readPassword = () -> - test.done() - - processor.process program - - # Test for process help function. - testProcessHelp: (test) -> - program = {'args': ["jeff", "buckley"]} - program.help = () -> - test.done() - - processor.process program \ No newline at end of file