├── .gitignore ├── _security-docs ├── _security-couchdb.json └── _security-cloudant.json ├── Cakefile ├── package.json ├── src └── index.coffee ├── index.js.map ├── README.md └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | *.sublime-workspace 3 | *.sublime-project 4 | -------------------------------------------------------------------------------- /_security-docs/_security-couchdb.json: -------------------------------------------------------------------------------- 1 | { 2 | "couchdb_auth_only": true, 3 | "members": { 4 | "names": [], 5 | "roles": [] 6 | }, 7 | "admins": {} 8 | } 9 | -------------------------------------------------------------------------------- /_security-docs/_security-cloudant.json: -------------------------------------------------------------------------------- 1 | { 2 | "cloudant": { 3 | "nobody": [] 4 | }, 5 | "readers": { 6 | "names":[], 7 | "roles":[] 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Cakefile: -------------------------------------------------------------------------------- 1 | {print} = require 'util' 2 | {spawn} = require 'child_process' 3 | 4 | task 'build', 'Build lib/ from src/', -> 5 | coffee = spawn 'iced', ['--bare', '--runtime', 'node', '-c', '-o', './', 'src'] 6 | coffee.stderr.on 'data', (data) -> 7 | process.stderr.write data.toString() 8 | coffee.stdout.on 'data', (data) -> 9 | print data.toString() 10 | coffee.on 'exit', (code) -> 11 | callback?() if code is 0 12 | 13 | 14 | task 'watch', 'Watch src/ for changes', -> 15 | coffee = spawn 'iced', ['-w', '--bare', '--runtime', 'node', '-c', '-o', './', 'src'] 16 | coffee.stderr.on 'data', (data) -> 17 | process.stderr.write data.toString() 18 | coffee.stdout.on 'data', (data) -> 19 | print data.toString() -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cloudant-user", 3 | "version": "2.0.0", 4 | "description": "Helper module to use standard CouchDB _users db on a Cloudant db", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "build": "./node_modules/.bin/iced --bare --map --runtime node -o ./ -c src/" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git://github.com/doublerebel/cloudant-user" 13 | }, 14 | "keywords": [ 15 | "cloudant", 16 | "couchdb", 17 | "couch", 18 | "user", 19 | "npm", 20 | "registry" 21 | ], 22 | "author": "Charles Phillips ", 23 | "license": "MIT", 24 | "bugs": { 25 | "url": "https://github.com/doublerebel/cloudant-user/issues" 26 | }, 27 | "homepage": "https://github.com/doublerebel/cloudant-user", 28 | "dependencies": { 29 | "cradle": "~0.7.1", 30 | "iced-runtime": "~1.0.3" 31 | }, 32 | "devDependencies": { 33 | "iced-coffee-script": "^108.0.9" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/index.coffee: -------------------------------------------------------------------------------- 1 | cradle = require "cradle" 2 | crypto = require "crypto" 3 | extend = (require "util")._extend 4 | 5 | 6 | class CloudantUser 7 | defaultRoles: [ 8 | "_default" 9 | "_reader" 10 | "_creator" 11 | "_writer" 12 | ] 13 | 14 | constructor: (@server) -> 15 | unless @server?.host then throw new Error "server.host required" 16 | unless @server.auth.username then throw new Error "server.auth.username required" 17 | @server.secure ?= /https/.exec @server.host 18 | @server.port or= if @server.secure then 443 else 80 19 | @server.cache = false 20 | @server.timeout = 5000 21 | 22 | @connect() 23 | 24 | couchUser: (name) -> "org.couchdb.user:#{name}" 25 | 26 | connect: -> 27 | @conn = new (cradle.Connection) @server 28 | @db = @conn.database "_users" 29 | 30 | create: (name, password, roles..., cb) -> 31 | @createWithMeta name, password, roles..., null, cb 32 | 33 | createWithMeta: (name, password, roles..., metadata = {}, cb) -> 34 | await @exists name, defer err, doc 35 | return (cb err or error: "user_exists") unless doc is false 36 | 37 | roles = @defaultRoles unless roles.length 38 | hashAndSalt = @generatePasswordHash password 39 | 40 | user = 41 | name: name 42 | password_sha: hashAndSalt[0] 43 | salt: hashAndSalt[1] 44 | password_scheme: "simple" 45 | type: "user" 46 | roles: roles 47 | 48 | extend user, metadata 49 | @db.save (@couchUser name), user, cb 50 | 51 | npmCreate: (name, password, email, roles..., cb) -> 52 | @createWithMeta name, password, roles..., {email}, cb 53 | 54 | get: (name, callback) -> @db.get (@couchUser name), callback 55 | 56 | exists: (name, cb) -> 57 | await @db.get (@couchUser name), defer err, doc 58 | if err?.error is "not_found" 59 | cb err, false 60 | else if doc 61 | cb null, doc 62 | else 63 | cb err 64 | 65 | update: (name, props, cb) -> 66 | cb error: "properties for user required" unless props 67 | 68 | {password} = props 69 | if password 70 | delete props.password 71 | hashAndSalt = @generatePasswordHash password 72 | props.password_sha = hashAndSalt[0] 73 | props.salt = hashAndSalt[1] 74 | props.password_scheme = "simple" 75 | 76 | @db.merge (@couchUser name), props, cb 77 | 78 | remove: (name, callback) -> @db.remove name, callback 79 | 80 | generatePasswordHash: (password) -> 81 | salt = (crypto.randomBytes 16).toString "hex" 82 | hash = crypto.createHash "sha1" 83 | hash.update password + salt 84 | [ 85 | hash.digest "hex" 86 | salt 87 | ] 88 | 89 | 90 | module.exports = CloudantUser 91 | -------------------------------------------------------------------------------- /index.js.map: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "file": "index.js", 4 | "sourceRoot": "", 5 | "sources": [ 6 | "src/index.coffee" 7 | ], 8 | "names": [], 9 | "mappings": "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" 10 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cloudant-user 2 | 3 | Helper module to use standard CouchDB _users db on a Cloudant db. 4 | 5 | * [Purpose](#purpose) 6 | * [Installation](#installation) 7 | * [Usage](#usage) 8 | - [Enable standard CouchDB auth on a Cloudant DB](#enable-standard-couchdb-auth-on-a-cloudant-db) 9 | + [Example: Set your Cloudant user as CouchDB admin](#example-set-your-cloudant-user-as-couchdb-admin) 10 | - [Revert to Cloudant auth on a Cloudant DB](#revert-to-cloudant-auth-on-a-cloudant-db) 11 | - [Create a user with any set of roles](#create-a-user-with-any-set-of-roles) 12 | + [CoffeeScript](#coffeescript) 13 | + [JavaScript](#javascript) 14 | * [Contributors](#contributors) 15 | * [License](#license) 16 | 17 | ## Purpose 18 | When _users db is enabled, Cloudant uses an old version of CouchDB auth which requires the salt and sha1-hashed password to be included with user creation. 19 | 20 | https://cloudant.com/for-developers/faq/auth/ 21 | 22 | So, if you'd like to run your own npm registry with the solid hosting of Cloudant, this module is a huge help. I use it to create user accounts for our private npm. 23 | 24 | ## Installation 25 | ```sh 26 | git clone https://github.com/doublerebel/cloudant-user.git 27 | ``` 28 | 29 | ## Usage: 30 | 31 | ### Enable standard CouchDB auth on a Cloudant DB 32 | PUT `_security-docs/_security-couchdb.json` to youruser.cloudant.com/yourdbname/_security to enable standard CouchDB auth for that database. 33 | 34 | ```sh 35 | curl -X PUT -d @_security-docs/_security-couchdb.json https://youruser.cloudant.com/yourdbname/_security 36 | ``` 37 | 38 | #### Example: Set your Cloudant user as CouchDB admin 39 | When switching to CouchDB auth, it's useful to define the admin role as your existing Cloudant user. The admin user will be able to create/read/update/delete all other users in this database. 40 | 41 | We can also limit this database to users which have a role "npm". 42 | 43 | `_security-docs/_security-cloudant.json` 44 | ```json 45 | { 46 | "couchdb_auth_only": true, 47 | "admins": { 48 | "names": ["your-cloudant-username"], 49 | "roles": ["_admin"] 50 | }, 51 | "members": { 52 | "names": [], 53 | "roles": ["npm"] 54 | } 55 | } 56 | ``` 57 | 58 | ### Revert to Cloudant auth on a Cloudant DB 59 | PUT `_security-docs/_security-cloudant.json` to youruser.cloudant.com/yourdbname/_security to reset auth to Cloudant management for that database. 60 | 61 | ```sh 62 | curl -X PUT -d @_security-docs/_security-cloudant.json https://youruser.cloudant.com/yourdbname/_security 63 | ``` 64 | 65 | ### Create a user with any set of roles 66 | Example scripts to add a user to Cloudant. Create one of these scripts and run with `coffee scriptname.coffee` or `node scriptname.js`. 67 | 68 | Server options are passed directly to [cradle](https://github.com/flatiron/cradle). 69 | 70 | #### CoffeeScript 71 | ```coffee 72 | CloudantUser = require "cloudant-user" 73 | 74 | server = 75 | host: your-cloudant-user.cloudant.com 76 | port: 443 77 | secure: true 78 | auth: 79 | username: "your-admin-username" 80 | password: "your-admin-password" 81 | 82 | newuser = 83 | name: "your-newuser-name" 84 | password: "your-newuser-pass" 85 | roles: ["_reader","_writer"] 86 | 87 | callback = (err, res) -> 88 | console.log err if err 89 | console.log res if res 90 | 91 | cloudantUser = new CloudantUser server 92 | cloudantUser.create newuser.name, newuser.password, newuser.roles..., callback 93 | ``` 94 | 95 | #### JavaScript 96 | ```js 97 | var CloudantUser = require("cloudant-user"); 98 | 99 | var server = { 100 | host: your-cloudant-user.cloudant.com, 101 | port: 443, 102 | secure: true, 103 | auth: { 104 | username: "your-admin-username", 105 | password: "your-admin-password" 106 | } 107 | }; 108 | 109 | var newuser = { 110 | name: "your-newuser-name", 111 | password: "your-newuser-pass", 112 | roles: ["_reader", "_writer"] 113 | }; 114 | 115 | var callback = function(err, res) { 116 | if (err) console.log(err); 117 | if (res) return console.log(res); 118 | }; 119 | 120 | var cloudantUser = new CloudantUser(server); 121 | cloudantUser.create(newuser.name, 122 | newuser.password, 123 | newuser.roles[0], 124 | newuser.roles[1], 125 | callback); 126 | ``` 127 | 128 | ### cloudantUser.npmCreate() 129 | Create a user with email (required by npm) 130 | ```coffee 131 | npmCreate(username, password, email, roles..., callback) 132 | ``` 133 | 134 | ### cloudantUser.createWithMeta() 135 | Create a user with arbitrary metadata 136 | ```coffee 137 | metadata = 138 | shrike: true 139 | timewarp: false 140 | 141 | createWithMeta(username, password, email, roles..., metadata, callback) 142 | ``` 143 | 144 | ## Extra help 145 | 146 | ### Users need to change their own password 147 | On Cloudant, a user without both roles "_reader" and "_writer" will be unable to change their password. Therefore, all normal users should be created with these roles. 148 | 149 | ### Futon on Cloudant 150 | Futon is available for any Cloudant database at https://cloudant.com/futon . Login there with your Cloudant account username and password. 151 | 152 | ## Contributors 153 | 154 | This module is originally based off of [a gist](https://gist.github.com/weilu/10445007) by [weilu](https://github.com/weilu). 155 | 156 | ## License 157 | Copyright 2014-2016 doublerebel. MIT licensed. 158 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | // Generated by IcedCoffeeScript 108.0.9 2 | var CloudantUser, cradle, crypto, extend, iced, __iced_k, __iced_k_noop, 3 | __slice = [].slice; 4 | 5 | iced = require('iced-runtime'); 6 | __iced_k = __iced_k_noop = function() {}; 7 | 8 | cradle = require("cradle"); 9 | 10 | crypto = require("crypto"); 11 | 12 | extend = (require("util"))._extend; 13 | 14 | CloudantUser = (function() { 15 | CloudantUser.prototype.defaultRoles = ["_default", "_reader", "_creator", "_writer"]; 16 | 17 | function CloudantUser(server) { 18 | var _base, _base1, _ref; 19 | this.server = server; 20 | if (!((_ref = this.server) != null ? _ref.host : void 0)) { 21 | throw new Error("server.host required"); 22 | } 23 | if (!this.server.auth.username) { 24 | throw new Error("server.auth.username required"); 25 | } 26 | if ((_base = this.server).secure == null) { 27 | _base.secure = /https/.exec(this.server.host); 28 | } 29 | (_base1 = this.server).port || (_base1.port = this.server.secure ? 443 : 80); 30 | this.server.cache = false; 31 | this.server.timeout = 5000; 32 | this.connect(); 33 | } 34 | 35 | CloudantUser.prototype.couchUser = function(name) { 36 | return "org.couchdb.user:" + name; 37 | }; 38 | 39 | CloudantUser.prototype.connect = function() { 40 | this.conn = new cradle.Connection(this.server); 41 | return this.db = this.conn.database("_users"); 42 | }; 43 | 44 | CloudantUser.prototype.create = function() { 45 | var cb, name, password, roles, _i; 46 | name = arguments[0], password = arguments[1], roles = 4 <= arguments.length ? __slice.call(arguments, 2, _i = arguments.length - 1) : (_i = 2, []), cb = arguments[_i++]; 47 | return this.createWithMeta.apply(this, [name, password].concat(__slice.call(roles), [null], [cb])); 48 | }; 49 | 50 | CloudantUser.prototype.createWithMeta = function() { 51 | var cb, doc, err, hashAndSalt, metadata, name, password, roles, user, ___iced_passed_deferral, __iced_deferrals, __iced_k, _i; 52 | __iced_k = __iced_k_noop; 53 | ___iced_passed_deferral = iced.findDeferral(arguments); 54 | name = arguments[0], password = arguments[1], roles = 5 <= arguments.length ? __slice.call(arguments, 2, _i = arguments.length - 2) : (_i = 2, []), metadata = arguments[_i++], cb = arguments[_i++]; 55 | if (metadata == null) { 56 | metadata = {}; 57 | } 58 | (function(_this) { 59 | return (function(__iced_k) { 60 | __iced_deferrals = new iced.Deferrals(__iced_k, { 61 | parent: ___iced_passed_deferral, 62 | filename: "/home/charles/source/cloudant-user/src/index.coffee", 63 | funcname: "CloudantUser.createWithMeta" 64 | }); 65 | _this.exists(name, __iced_deferrals.defer({ 66 | assign_fn: (function() { 67 | return function() { 68 | err = arguments[0]; 69 | return doc = arguments[1]; 70 | }; 71 | })(), 72 | lineno: 33 73 | })); 74 | __iced_deferrals._fulfill(); 75 | }); 76 | })(this)((function(_this) { 77 | return function() { 78 | if (doc !== false) { 79 | return cb(err || { 80 | error: "user_exists" 81 | }); 82 | } 83 | if (!roles.length) { 84 | roles = _this.defaultRoles; 85 | } 86 | hashAndSalt = _this.generatePasswordHash(password); 87 | user = { 88 | name: name, 89 | password_sha: hashAndSalt[0], 90 | salt: hashAndSalt[1], 91 | password_scheme: "simple", 92 | type: "user", 93 | roles: roles 94 | }; 95 | extend(user, metadata); 96 | return _this.db.save(_this.couchUser(name), user, cb); 97 | }; 98 | })(this)); 99 | }; 100 | 101 | CloudantUser.prototype.npmCreate = function() { 102 | var cb, email, name, password, roles, _i; 103 | name = arguments[0], password = arguments[1], email = arguments[2], roles = 5 <= arguments.length ? __slice.call(arguments, 3, _i = arguments.length - 1) : (_i = 3, []), cb = arguments[_i++]; 104 | return this.createWithMeta.apply(this, [name, password].concat(__slice.call(roles), [{ 105 | email: email 106 | }], [cb])); 107 | }; 108 | 109 | CloudantUser.prototype.get = function(name, callback) { 110 | return this.db.get(this.couchUser(name), callback); 111 | }; 112 | 113 | CloudantUser.prototype.exists = function(name, cb) { 114 | var doc, err, ___iced_passed_deferral, __iced_deferrals, __iced_k; 115 | __iced_k = __iced_k_noop; 116 | ___iced_passed_deferral = iced.findDeferral(arguments); 117 | (function(_this) { 118 | return (function(__iced_k) { 119 | __iced_deferrals = new iced.Deferrals(__iced_k, { 120 | parent: ___iced_passed_deferral, 121 | filename: "/home/charles/source/cloudant-user/src/index.coffee", 122 | funcname: "CloudantUser.exists" 123 | }); 124 | _this.db.get(_this.couchUser(name), __iced_deferrals.defer({ 125 | assign_fn: (function() { 126 | return function() { 127 | err = arguments[0]; 128 | return doc = arguments[1]; 129 | }; 130 | })(), 131 | lineno: 56 132 | })); 133 | __iced_deferrals._fulfill(); 134 | }); 135 | })(this)((function(_this) { 136 | return function() { 137 | if ((typeof err !== "undefined" && err !== null ? err.error : void 0) === "not_found") { 138 | return cb(err, false); 139 | } else if (doc) { 140 | return cb(null, doc); 141 | } else { 142 | return cb(err); 143 | } 144 | }; 145 | })(this)); 146 | }; 147 | 148 | CloudantUser.prototype.update = function(name, props, cb) { 149 | var hashAndSalt, password; 150 | if (!props) { 151 | cb({ 152 | error: "properties for user required" 153 | }); 154 | } 155 | password = props.password; 156 | if (password) { 157 | delete props.password; 158 | hashAndSalt = this.generatePasswordHash(password); 159 | props.password_sha = hashAndSalt[0]; 160 | props.salt = hashAndSalt[1]; 161 | props.password_scheme = "simple"; 162 | } 163 | return this.db.merge(this.couchUser(name), props, cb); 164 | }; 165 | 166 | CloudantUser.prototype.remove = function(name, callback) { 167 | return this.db.remove(name, callback); 168 | }; 169 | 170 | CloudantUser.prototype.generatePasswordHash = function(password) { 171 | var hash, salt; 172 | salt = (crypto.randomBytes(16)).toString("hex"); 173 | hash = crypto.createHash("sha1"); 174 | hash.update(password + salt); 175 | return [hash.digest("hex"), salt]; 176 | }; 177 | 178 | return CloudantUser; 179 | 180 | })(); 181 | 182 | module.exports = CloudantUser; 183 | 184 | //# sourceMappingURL=index.js.map 185 | --------------------------------------------------------------------------------