Skip to content

Commit

Permalink
feat: dbUrlUsername and dbUrlPassword options
Browse files Browse the repository at this point in the history
  • Loading branch information
Manosmer authored and gr2m committed Mar 15, 2017
1 parent 8c8e131 commit b848323
Show file tree
Hide file tree
Showing 8 changed files with 335 additions and 11 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,11 @@ option | default | description
------------------------- | -------------------- | -------------
`--address` | `'127.0.0.1'` | Address to which Hoodie binds
`--data` | `'.hoodie'` | Data path
`--dbUrl` | – | If provided, uses external CouchDB. URL has to contain credentials
`--dbUrl` | - | If provided, uses external CouchDB listening at the given URL. (Can contain auth credentials)
`--dbUrlUsername` | - | Username to authenticate with the external CouchDB (requires --dbUrl and --dbUrlPassword to be set).
`--dbUrlPassword` | - | Password to authenticate with the external CouchDB (requires --dbUrl and/or --dbUrlUsername to be set).
`--dbAdapter` | `pouchdb-adapter-fs` | Default [PouchDB adapter](https://pouchdb.com/adapters.html). Ignored if `dbUrl` or `inMemory` set
`--adminPassword` | | Password to login to Admin Dashboard. Login is not possible if `adminPassword` option is not set
`--adminPassword` | - | Password to login to Admin Dashboard. Login is not possible if `adminPassword` option is not set
`--loglevel` | `'warn'` | One of: silent, error, warn, http, info, verbose, silly
`-m`, `--inMemory` | `false` | Whether to start the PouchDB Server in memory
`--port` | `8080` | Port-number to run the Hoodie App on
Expand Down
2 changes: 2 additions & 0 deletions cli/hoodie-defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ function getHoodieDefaults () {
data: '.hoodie',
public: 'public',
dbUrl: undefined,
dbUrlPassword: undefined,
dbUrlUsername: undefined,
dbAdapter: 'pouchdb-adapter-fs',
inMemory: false,
loglevel: 'warn',
Expand Down
12 changes: 11 additions & 1 deletion cli/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,17 @@ function getCliOptions (projectPath) {
dbUrl: {
type: 'string',
default: defaults.dbUrl,
describe: 'If provided, uses external CouchDB. URL has to contain credentials.'
describe: 'If provided, uses external CouchDB. (Can contain auth credentials)'
},
dbUrlPassword: {
type: 'string',
default: defaults.dbUrlPassword,
describe: 'Provides the password for auth with the db at dbUrl (requires dbUrl and/or dbUrlUsername)'
},
dbUrlUsername: {
type: 'string',
default: defaults.dbUrlUsername,
describe: 'Provides the username for auth with the db at dbUrl (requires dbUrl and dbUrlPassword)'
},
dbAdapter: {
type: 'string',
Expand Down
11 changes: 6 additions & 5 deletions cli/parse-options.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ module.exports = parseOptions

var log = require('npmlog')
var path = require('path')

var PouchDB = require('pouchdb-core')
var urlParse = require('url').parse

var createAuthDbUrl = require('./utils/create-auth-dbUrl')

/**
* Parse options into internal config structure.
Expand All @@ -20,6 +22,7 @@ var urlParse = require('url').parse
* PouchDB is being used. A shortcut to set PouchDB’s adapter to memdown is to
* passe set the `inMemory: true` option. If it’s not set, leveldown is used
* with the prefix set to `options.data` + 'data' (`.hoodie/data` by default).
*
*/

function parseOptions (options) {
Expand All @@ -46,11 +49,9 @@ function parseOptions (options) {

PouchDB.plugin(require('pouchdb-mapreduce'))

if (options.dbUrl) {
if (!urlParse(options.dbUrl).auth) {
throw new Error('Authentication details missing from database URL: ' + options.db.url)
}
options.dbUrl = createAuthDbUrl(options.dbUrlUsername, options.dbUrlPassword, options.dbUrl)

if (options.dbUrl) {
PouchDB.plugin(require('pouchdb-adapter-http'))
dbOptions.prefix = options.dbUrl
log.info('config', 'Storing all data in ' + options.dbUrl)
Expand Down
82 changes: 82 additions & 0 deletions cli/utils/create-auth-dbUrl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
module.exports = createAuthDbUrl

var log = require('npmlog')
log.level = 'warn'

/**
* Parse username, password and url for external db, via options object and returns the modified dbUrl
* with username and password encoded in URL encoding
*
* @param dbUsername used for parsing options.dbUrlUsername
* @param dbPassword used for parsing options.dbUrlPassword
* @param dbUrl used for parsing options.dbUrl
*
* @var dbUrlParts contains different parts of dbUrl, helping in modifing username and password
*
* @returns dbUrl based on the parameters
* @throws Error if dbUrl is unparsable or authDetails are missing
*
*/

function createAuthDbUrl (dbUsername, dbPassword, dbUrl) {
var dbUrlParts = {
prefix: '',
authDetails: '',
url: ''
}

if (dbUrl) {
dbUrlParts.prefix = dbUrl.startsWith('https://') ? (
dbUrl = dbUrl.replace('https://', ''),
'https://'
) : (
dbUrl = dbUrl.replace('http://', ''),
'http://'
)

if (dbUrl.includes('@')) {
dbUrlParts.authDetails = dbUrl.split('@').slice(0, -1).join('@')
dbUrlParts.url = dbUrl.replace(dbUrlParts.authDetails + '@', '')

if (!dbUrlParts.authDetails) throw new Error('dbUrl: ' + '"' + dbUrlParts.prefix + dbUrl + '"' + ' does not include authentication details')

if (dbUrlParts.authDetails.includes(':')) {
if (dbUrlParts.authDetails.match(/:/gi).length >= 2) throw new Error('Could not find username & password in dbUrl. Please try setting --dbUrlUsername and --dbUrlPassword if either contains special characters like : or @')

if (!dbUrlParts.authDetails.split(':')[1]) {
throw new Error('Password is missing from --dbUrl after symbol ":"')
}

if (!dbUrlParts.authDetails.split(':')[0]) {
throw new Error('Username is missing from --dbUrl after symbol ":"')
}

if (dbUsername || dbPassword) {
log.warn('DB config', '--dbUsername and --dbPassword are replacing authentication details of --dbUrl')

return dbUrlParts.prefix + (dbUsername ? encodeURIComponent(dbUsername) : encodeURIComponent(dbUrlParts.authDetails.split(':')[0])) + ':' + (dbPassword ? encodeURIComponent(dbPassword) : encodeURIComponent(dbUrlParts.authDetails.split(':')[1])) + '@' + dbUrlParts.url
}

return dbUrlParts.prefix + (dbUrlParts.authDetails.split(':').map(n => encodeURIComponent(n)).join(':')) + '@' + dbUrlParts.url
}

if (dbPassword) {
return dbUrlParts.prefix + encodeURIComponent(dbUrlParts.authDetails) + ':' + encodeURIComponent(dbPassword) + '@' + dbUrlParts.url
} else {
throw new Error('Password has not been specified for dbUrl: ' + dbUrlParts.prefix + dbUrl + '. ' +
'Use --dbUrlPassword or provide it within --dbUrl.')
}
} else {
if (!(dbUsername && dbPassword)) {
throw new Error('Authentication credentials (username AND password) are missing from dbUrl. Provide them either by --dbUrl directly or by setting --dbUrlUsername and --dbUrlPassword arguments.')
}
return dbUrlParts.prefix + encodeURIComponent(dbUsername) + ':' + encodeURIComponent(dbPassword) + '@' + dbUrl
}
} else {
if (dbUsername || dbPassword) {
log.warn('DB url config', 'No dbAddress is provided in order to authenticate with credentials(username:password): ' + dbUsername + ':' + dbPassword)
log.warn('DB config', 'Setting db automatically depending on --inMemory. To see more, use --loglevel=info')
}
return undefined
}
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
"semantic-release": "semantic-release pre && npm publish && semantic-release post",
"start": "./bin/start.js",
"pretest": "standard",
"test": "nyc tap --no-cov './test/{unit,integration}/**/*-test.js'",
"test": "nyc tap --no-cov ./test/{unit,integration}/**/*-test.js",
"postinstall": "node ./bin/setup.js",
"textlint": "textlint docs/**/*.md README.md"
}
Expand Down
2 changes: 2 additions & 0 deletions test/unit/cli/hoodie-default-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ test('hoodie defaults test', function (group) {
data: '.hoodie',
dbAdapter: 'pouchdb-adapter-fs',
dbUrl: undefined,
dbUrlPassword: undefined,
dbUrlUsername: undefined,
inMemory: false,
loglevel: 'warn',
port: 8080,
Expand Down
Loading

0 comments on commit b848323

Please sign in to comment.