summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoan Touzet <wohali@users.noreply.github.com>2018-08-06 12:31:45 -0400
committerGitHub <noreply@github.com>2018-08-06 12:31:45 -0400
commit8c306105f3da6391fdb116767e378a567a43cf2e (patch)
tree04e5355dd2930a84bf442cf4623b63884fdaa8e1
parentcb87b479443123e94a571e98b68a70176a33b935 (diff)
parent99e801eca88a4521157d4369847f61cf2a88d1ba (diff)
downloadcouchdb-1278-add-clustered-db-info.tar.gz
Merge branch 'master' into 1278-add-clustered-db-info1278-add-clustered-db-info
-rw-r--r--.gitignore1
-rw-r--r--.travis.yml2
-rw-r--r--INSTALL.Unix.md3
-rw-r--r--LICENSE117
-rw-r--r--Makefile49
-rw-r--r--Makefile.win45
-rw-r--r--NOTICE7
-rwxr-xr-xbuild-aux/couchdb-build-release.sh6
-rwxr-xr-xconfigure9
-rw-r--r--rebar.config.script13
-rw-r--r--rel/overlay/etc/default.ini24
-rw-r--r--rel/overlay/etc/local.ini2
-rw-r--r--rel/reltool.config2
-rw-r--r--src/chttpd/src/chttpd.erl2
-rw-r--r--src/chttpd/src/chttpd_auth_request.erl5
-rw-r--r--src/chttpd/src/chttpd_misc.erl1
-rw-r--r--src/chttpd/test/chttpd_welcome_test.erl2
-rw-r--r--src/couch/rebar.config.script17
-rw-r--r--src/couch/src/couch.app.src1
-rw-r--r--src/couch/src/couch.erl1
-rw-r--r--src/couch/src/couch_auth_cache.erl7
-rw-r--r--src/couch/src/couch_bt_engine.erl2
-rw-r--r--src/couch/src/couch_db.erl2
-rw-r--r--src/couch/src/couch_file.erl8
-rw-r--r--src/couch/src/couch_hash.erl45
-rw-r--r--src/couch/src/couch_httpd.erl2
-rw-r--r--src/couch/src/couch_httpd_auth.erl12
-rw-r--r--src/couch/src/couch_native_process.erl4
-rw-r--r--src/couch/src/couch_passwords.erl19
-rw-r--r--src/couch/src/couch_query_servers.erl54
-rw-r--r--src/couch/src/couch_server.erl3
-rw-r--r--src/couch/src/couch_stream.erl18
-rw-r--r--src/couch/src/couch_users_db.erl10
-rw-r--r--src/couch/src/test_engine_util.erl8
-rw-r--r--src/couch/src/test_request.erl6
-rw-r--r--src/couch/src/test_util.erl3
-rw-r--r--src/couch/test/couch_passwords_tests.erl42
-rw-r--r--src/couch/test/couchdb_attachments_tests.erl6
-rw-r--r--src/couch_epi/src/couch_epi_data.erl2
-rw-r--r--src/couch_epi/src/couch_epi_util.erl2
-rw-r--r--src/couch_event/src/couch_event_os_sup.erl82
-rw-r--r--src/couch_event/src/couch_event_sup2.erl7
-rw-r--r--src/couch_index/test/couch_index_ddoc_updated_tests.erl2
-rw-r--r--src/couch_mrview/src/couch_mrview.erl2
-rw-r--r--src/couch_mrview/src/couch_mrview_util.erl8
-rw-r--r--src/couch_replicator/src/couch_replicator_auth.erl2
-rw-r--r--src/couch_replicator/src/couch_replicator_ids.erl2
-rw-r--r--src/couch_replicator/test/couch_replicator_many_leaves_tests.erl2
-rw-r--r--src/couch_replicator/test/couch_replicator_test_helper.erl12
-rw-r--r--src/fabric/src/fabric.erl9
-rw-r--r--src/mem3/src/mem3_rep.erl6
-rw-r--r--src/setup/src/setup.erl43
-rw-r--r--test/javascript/tests/design_docs.js8
-rw-r--r--test/javascript/tests/users_db_security.js167
54 files changed, 351 insertions, 565 deletions
diff --git a/.gitignore b/.gitignore
index a1cba1e0b..088303039 100644
--- a/.gitignore
+++ b/.gitignore
@@ -28,7 +28,6 @@ share/server/main.js
share/www
src/b64url/
src/bear/
-src/bcrypt/
src/config/
src/couch/priv/couch_js/config.h
src/couch/priv/couchjs
diff --git a/.travis.yml b/.travis.yml
index b2e7ff0ed..acb0b5102 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,7 +3,7 @@ sudo: false
os: linux
otp_release:
- - 20.1
+ - 20.3
- 19.3
- 18.3
- 17.5
diff --git a/INSTALL.Unix.md b/INSTALL.Unix.md
index bfd9c89a2..f0baf58c9 100644
--- a/INSTALL.Unix.md
+++ b/INSTALL.Unix.md
@@ -74,6 +74,9 @@ You can install the documentation dependencies by running:
sudo apt-get --no-install-recommends -y install \
python-sphinx
+
+ sudo pip install --upgrade sphinx_rtd_theme nose requests hypothesis
+
Be sure to update the version numbers to match your system's available
packages.
diff --git a/LICENSE b/LICENSE
index 6034c717e..83a1aa7df 100644
--- a/LICENSE
+++ b/LICENSE
@@ -2158,123 +2158,6 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-The Erlang code is subject to this license:
-
-%% Copyright (c) 2011 Hunter Morris <hunter.morris@smarkets.com>
-
-%% Permission to use, copy, modify, and distribute this software for any
-%% purpose with or without fee is hereby granted, provided that the above
-%% copyright notice and this permission notice appear in all copies.
-
-%% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-%% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-%% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-%% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-%% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-The underlying blowfish code is derived from OpenBSD libc and is
-subject to the following license:
-
-/*
- * Blowfish block cipher for OpenBSD
- * Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de>
- * All rights reserved.
- *
- * Implementation advice by David Mazieres <dm@lcs.mit.edu>.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Niels Provos.
- * 4. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-The underlying bcrypt (hashing) code is derived from OpenBSD libc and is
-subject to the following license:
-
-/*
- * Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Niels Provos.
- * 4. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-The asynchronous queue code (c_src/async_queue.c and
-c_src/async_queue.h) is from the esnappy project, copyright 2011
-Konstantin V. Sorokin. It is subject to the following license:
-
-Copyright (c) 2011 Konstantin V. Sorokin
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-
-1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-3. Neither the name of the copyright holder nor the names of contributors
- may be used to endorse or promote products derived from this software
- without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
-
For the src/hyper component:
The MIT License (MIT)
diff --git a/Makefile b/Makefile
index 27d9531a7..0ab7b4eed 100644
--- a/Makefile
+++ b/Makefile
@@ -13,20 +13,49 @@
include version.mk
REBAR?=$(shell echo `pwd`/bin/rebar)
+
+# Handle the following scenarios:
+# 1. When building from a tarball, use version.mk.
+# 2. When building from a clean release tag (#.#.#), use that tag.
+# 3. When building from a clean RC tag (#.#.#-RC#), use JUST the version
+# number inside the tarball, but use the full name for the name of the
+# tarball itself.
+# 4. When not on a clean tag, use version.mk + git sha + dirty status.
+
+COUCHDB_GIT_SHA=$(git_sha)
+
IN_RELEASE = $(shell if [ ! -d .git ]; then echo true; fi)
ifeq ($(IN_RELEASE), true)
+
+# 1. Building from tarball, use version.mk.
COUCHDB_VERSION = $(vsn_major).$(vsn_minor).$(vsn_patch)
+
else
-# IN_RC generates a tarball that has the -RCx suffix in the name if needed
+
+# Gather some additional information.
+# We do it this way so we don't bake shell-isms into Makefile
+# to make it easier to port to Windows. I know, I know. -jst
+# IN_RC contains the -RCx suffix in the name if present
IN_RC = $(shell git describe --tags --always --first-parent \
- | grep -Eo -- '-RC[0-9]+' 2>/dev/null)
-RELTAG = $(shell git describe --dirty --abbrev=0 --tags --always --first-parent \
- | grep -Eo '^[0-9]+\.[0-9]\.[0-9]+')
-ifeq ($(RELTAG),)
-COUCHDB_VERSION_SUFFIX = $(shell git rev-parse --short --verify HEAD)
+ | grep -Eo -- '-RC[0-9]+' 2>/dev/null)
+# ON_TAG matches *ONLY* if we are on a release or RC tag
+ON_TAG = $(shell git describe --tags --always --first-parent \
+ | grep -Eo -- '^[0-9]+\.[0-9]\.[0-9]+(-RC[0-9]+)?$$' 2>/dev/null)
+# RELTAG contains the #.#.# from git describe, which might be used
+RELTAG = $(shell git describe --tags --always --first-parent \
+ | grep -Eo -- '^[0-9]+\.[0-9]\.[0-9]+' 2>/dev/null)
+# DIRTY identifies if we're not on a commit
+DIRTY = $(shell git describe --dirty | grep -Eo -- '-dirty' 2>/dev/null)
+# COUCHDB_GIT_SHA is our current git hash.
+COUCHDB_GIT_SHA=$(shell git rev-parse --short --verify HEAD)
+
+ifeq ($(ON_TAG),)
+# 4. Not on a tag.
+COUCHDB_VERSION_SUFFIX = $(COUCHDB_GIT_SHA)$(DIRTY)
COUCHDB_VERSION = $(vsn_major).$(vsn_minor).$(vsn_patch)-$(COUCHDB_VERSION_SUFFIX)
else
-COUCHDB_VERSION = $(RELTAG)
+# 2 and 3. On a tag.
+COUCHDB_VERSION = $(RELTAG)$(DIRTY)
endif
endif
@@ -82,7 +111,7 @@ help:
.PHONY: couch
# target: couch - Build CouchDB core, use ERL_OPTS to provide custom compiler's options
couch: config.erl
- @COUCHDB_VERSION=$(COUCHDB_VERSION) $(REBAR) compile $(COMPILE_OPTS)
+ @COUCHDB_VERSION=$(COUCHDB_VERSION) COUCHDB_GIT_SHA=$(COUCHDB_GIT_SHA) $(REBAR) compile $(COMPILE_OPTS)
@cp src/couch/priv/couchjs bin/
@@ -225,7 +254,7 @@ list-eunit-apps:
.PHONY: list-eunit-suites
# target: list-eunit-suites - List EUnit target test suites
list-eunit-suites:
- @find ./src/ -type f -name *_test.erl -o -name *_tests.erl -printf "%f\n" \
+ @find ./src/ -type f -name *_test.erl -o -name *_tests.erl -exec basename {} \; \
| cut -d '.' -f -1 \
| sort
@@ -233,7 +262,7 @@ list-eunit-suites:
.PHONY: list-js-suites
# target: list-js-suites - List JavaScript test suites
list-js-suites:
- @find ./test/javascript/tests/ -type f -name *.js -printf "%f\n" \
+ @find ./test/javascript/tests/ -type f -name *.js -exec basename {} \; \
| cut -d '.' -f -1 \
| sort
diff --git a/Makefile.win b/Makefile.win
index 5a2a73ab1..67c15fc69 100644
--- a/Makefile.win
+++ b/Makefile.win
@@ -14,13 +14,50 @@ include version.mk
SHELL=cmd.exe
REBAR?=$(shell where rebar.cmd)
+
+# Handle the following scenarios:
+# 1. When building from a tarball, use version.mk.
+# 2. When building from a clean release tag (#.#.#), use that tag.
+# 3. When building from a clean RC tag (#.#.#-RC#), use JUST the version
+# number inside the tarball, but use the full name for the name of the
+# tarball itself.
+# 4. When not on a clean tag, use version.mk + git sha + dirty status.
+
+COUCHDB_GIT_SHA=$(git_sha)
IN_RELEASE = $(shell if not exist .git echo true)
+
ifeq ($(IN_RELEASE), true)
-COUCHDB_VERSION_SUFFIX=
+
+# 1. Building from tarball, use version.mk.
COUCHDB_VERSION = $(vsn_major).$(vsn_minor).$(vsn_patch)
+
+else
+
+# Gather some additional information.
+# We do it this way so we don't bake shell-isms into Makefile
+# to make it easier to port to Windows. I know, I know. -jst
+# COUCHDB_GIT_SHA is our current git hash.
+COUCHDB_GIT_SHA=$(shell git rev-parse --short --verify HEAD)
+# IN_RC contains the -RCx suffix in the name if present
+IN_RC = $(shell git describe --tags --always --first-parent \
+ | grep -Eo -- '-RC[0-9]+' 2>/dev/null)
+# ON_TAG matches *ONLY* if we are on a release or RC tag
+ON_TAG = $(shell git describe --tags --always --first-parent \
+ | grep -Eo -- '^[0-9]+\.[0-9]\.[0-9]+(-RC[0-9]+)?$$' 2>/dev/null)
+# RELTAG contains the #.#.# from git describe, which might be used
+RELTAG = $(shell git describe --tags --always --first-parent \
+ | grep -Eo -- '^[0-9]+\.[0-9]\.[0-9]+' 2>/dev/null)
+# DIRTY identifies if we're not on a commit
+DIRTY = $(shell git describe --dirty | grep -Eo -- '-dirty' 2>/dev/null)
+
+ifeq ($(ON_TAG),)
+# 4. Not on a tag.
+COUCHDB_VERSION_SUFFIX = $(COUCHDB_GIT_SHA)$(DIRTY)
+COUCHDB_VERSION = $(vsn_major).$(vsn_minor).$(vsn_patch)-$(COUCHDB_VERSION_SUFFIX)
else
-COUCHDB_VERSION_SUFFIX = -$(shell git rev-parse --short --verify HEAD)
-COUCHDB_VERSION = $(vsn_major).$(vsn_minor).$(vsn_patch)$(COUCHDB_VERSION_SUFFIX)
+# 2 and 3. On a tag.
+COUCHDB_VERSION = $(RELTAG)$(DIRTY)
+endif
endif
DESTDIR=
@@ -53,7 +90,7 @@ all: couch fauxton docs
.PHONY: couch
# target: couch - Build CouchDB core
couch: config.erl
- @set COUCHDB_VERSION=$(COUCHDB_VERSION) && $(REBAR) compile
+ @set COUCHDB_VERSION=$(COUCHDB_VERSION) && set COUCHDB_GIT_SHA=$(COUCHDB_GIT_SHA) && $(REBAR) compile
@copy src\couch\priv\couchjs.exe bin
diff --git a/NOTICE b/NOTICE
index 481e75513..f703af216 100644
--- a/NOTICE
+++ b/NOTICE
@@ -178,13 +178,6 @@ This product also includes the following third-party components:
Copyright (c) 2015 Twitter, Inc.
-* erlang-bcrypt
- - Erlang code: Copyright (c) 2011 Hunter Morris <hunter.morris@smarkets.com>
- - Blowfish block cipher & bcrypt (hashing) code for OpenBSD, Copyright
- 1997 Niels Provos <provos@physnet.uni-hamburg.de>
- - The asynchronous queue code (c_src/async_queue.c and c_src/async_queue.h)
- is from the esnappy project, copyright 2011 Konstantin V. Sorokin.
-
* hyper
Copyright (c) 2014 Game Analytics ApS
diff --git a/build-aux/couchdb-build-release.sh b/build-aux/couchdb-build-release.sh
index 4482b713c..2d219e5e4 100755
--- a/build-aux/couchdb-build-release.sh
+++ b/build-aux/couchdb-build-release.sh
@@ -35,8 +35,12 @@ done
cd ..
-# create CONTRIBUTORS file
+
if test -e .git; then
+ # save git sha in version.mk
+ git_sha=`git rev-parse --short HEAD`
+ echo "git_sha=$git_sha" >> $RELDIR/version.mk
+ # create CONTRIBUTORS file
OS=`uname -s`
case "$OS" in
Linux|CYGWIN*) # GNU sed
diff --git a/configure b/configure
index fa0dfed6a..370c964ae 100755
--- a/configure
+++ b/configure
@@ -25,6 +25,7 @@ PACKAGE_AUTHOR_NAME="The Apache Software Foundation"
WITH_CURL="false"
WITH_FAUXTON=1
WITH_DOCS=1
+ERLANG_MD5="false"
SKIP_DEPS=0
COUCHDB_USER="$(whoami 2>/dev/null || echo couchdb)"
@@ -46,6 +47,7 @@ Options:
-c | --with-curl request that couchjs is linked to cURL (default false)
--disable-fauxton do not build Fauxton
--disable-docs do not build any documentation or manpages
+ --erlang-md5 use erlang for md5 hash operations
--dev alias for --with-curl --disable-docs --disable-fauxton
--skip-deps do not update erlang dependencies
--rebar=PATH use rebar by specified path (version >=2.6.0 && <3.0 required)
@@ -78,6 +80,12 @@ parse_opts() {
continue
;;
+ --erlang-md5)
+ ERLANG_MD5="true"
+ shift
+ continue
+ ;;
+
--dev)
WITH_DOCS=0
WITH_FAUXTON=0
@@ -195,6 +203,7 @@ EOF
cat > $rootdir/config.erl << EOF
{with_curl, $WITH_CURL}.
+{erlang_md5, $ERLANG_MD5}.
EOF
install_local_rebar() {
diff --git a/rebar.config.script b/rebar.config.script
index 14117527c..cd469553c 100644
--- a/rebar.config.script
+++ b/rebar.config.script
@@ -56,19 +56,16 @@ DepDescs = [
%% Non-Erlang deps
{docs, {url, "https://github.com/apache/couchdb-documentation"},
- {tag, "2.1.2"}, [raw]},
+ {tag, "2.2.0"}, [raw]},
{fauxton, {url, "https://github.com/apache/couchdb-fauxton"},
- {tag, "v1.1.15"}, [raw]},
+ {tag, "v1.1.17"}, [raw]},
%% Third party deps
{folsom, "folsom", {tag, "CouchDB-0.8.2"}},
-{hyper, "hyper", {tag, "CouchDB-2.2.0-3"}},
+{hyper, "hyper", {tag, "CouchDB-2.2.0-4"}},
{ibrowse, "ibrowse", {tag, "CouchDB-4.0.1"}},
{jiffy, "jiffy", {tag, "CouchDB-0.14.11-2"}},
{mochiweb, "mochiweb", {tag, "v2.17.0"}},
-{meck, "meck", {tag, "0.8.8"}},
-{bcrypt, {url, "https://github.com/apache/couchdb-erlang-bcrypt"},
- {tag, "1.0.2"}},
-{triq, "triq", {tag, "v1.2.0"}}
+{meck, "meck", {tag, "0.8.8"}}
],
@@ -105,7 +102,7 @@ AddConfig = [
{plt_location, local},
{plt_location, COUCHDB_ROOT},
{plt_extra_apps, [
- asn1, bcrypt, compiler, crypto, inets, kernel, os_mon, runtime_tools,
+ asn1, compiler, crypto, inets, kernel, os_mon, runtime_tools,
sasl, setup, ssl, stdlib, syntax_tools, xmerl]},
{warnings, [unmatched_returns, error_handling, race_conditions]}]},
{post_hooks, [{compile, "escript support/build_js.escript"}]}
diff --git a/rel/overlay/etc/default.ini b/rel/overlay/etc/default.ini
index 0f0d54793..45025e780 100644
--- a/rel/overlay/etc/default.ini
+++ b/rel/overlay/etc/default.ini
@@ -83,7 +83,8 @@ port = {{cluster_port}}
bind_address = 127.0.0.1
backlog = 512
docroot = {{fauxton_root}}
-socket_options = [{recbuf, 262144}, {sndbuf, 262144}, {nodelay, true}]
+socket_options = [{sndbuf, 262144}, {nodelay, true}]
+server_options = [{recbuf, undefined}]
require_valid_user = false
; List of headers that will be kept when the header Prefer: return=minimal is included in a request.
; If Server header is left out, Mochiweb will add its own one in.
@@ -98,6 +99,9 @@ max_db_number_for_dbs_info_req = 100
; uncomment the next line to enable proxy authentication
; authentication_handlers = {chttpd_auth, proxy_authentication_handler}, {chttpd_auth, cookie_authentication_handler}, {chttpd_auth, default_authentication_handler}
+; prevent non-admins from accessing /_all_dbs
+;admin_only_all_dbs = false
+
[database_compaction]
; larger buffer sizes can originate smaller files
doc_buffer_size = 524288 ; value in bytes
@@ -135,8 +139,8 @@ allow_jsonp = false
; Options for the MochiWeb HTTP server.
;server_options = [{backlog, 128}, {acceptor_pool_size, 16}]
; For more socket options, consult Erlang's module 'inet' man page.
-;socket_options = [{recbuf, 262144}, {sndbuf, 262144}, {nodelay, true}]
-socket_options = [{recbuf, 262144}, {sndbuf, 262144}]
+;socket_options = [{recbuf, undefined}, {sndbuf, 262144}, {nodelay, true}]
+socket_options = [{sndbuf, 262144}]
enable_cors = false
enable_xframe_options = false
; CouchDB can optionally enforce a maximum uri length;
@@ -149,7 +153,7 @@ enable_xframe_options = false
; x_forwarded_proto = X-Forwarded-Proto
; x_forwarded_ssl = X-Forwarded-Ssl
; Maximum allowed http request size. Applies to both clustered and local port.
-max_http_request_size = 67108864 ; 64 MB
+max_http_request_size = 4294967296 ; 4GB
; [httpd_design_handlers]
; _view =
@@ -203,8 +207,7 @@ require_valid_user = false
timeout = 600 ; number of seconds before automatic logout
auth_cache_size = 50 ; size is number of cache entries
allow_persistent_cookies = false ; set to true to allow persistent cookies
-iterations = 10 ; iterations for PBKDF2 password hashing
-log_rounds = 10 ; 2^log_rounds iterations for Bcrypt password hashing
+iterations = 10 ; iterations for password hashing
; min_iterations = 1
; max_iterations = 1000000000
; password_scheme = pbkdf2
@@ -431,13 +434,12 @@ ssl_certificate_max_depth = 3
; There are currently two plugins available:
; couch_replicator_auth_session - use _session cookie authentication
; couch_replicator_auth_noop - use basic authentication (previous default)
-; Currently previous default behavior is still the default. To start using
-; session auth, use this as the list of plugins:
-; `couch_replicator_auth_session,couch_replicator_auth_noop`.
-; In a future release the session plugin might be used by default.
+; Currently, the new _session cookie authentication is tried first, before
+; falling back to the old basic authenticaion default:
+;auth_plugins = couch_replicator_auth_session,couch_replicator_auth_noop
+; To restore the old behaviour, use the following value:
;auth_plugins = couch_replicator_auth_noop
-
[compaction_daemon]
; The delay, in seconds, between each check for which database and view indexes
; need to be compacted.
diff --git a/rel/overlay/etc/local.ini b/rel/overlay/etc/local.ini
index e3b7b1502..ea5467c9a 100644
--- a/rel/overlay/etc/local.ini
+++ b/rel/overlay/etc/local.ini
@@ -27,7 +27,7 @@
; Options for the MochiWeb HTTP server.
;server_options = [{backlog, 128}, {acceptor_pool_size, 16}]
; For more socket options, consult Erlang's module 'inet' man page.
-;socket_options = [{recbuf, 262144}, {sndbuf, 262144}, {nodelay, true}]
+;socket_options = [{sndbuf, 262144}, {nodelay, true}]
[httpd]
; NOTE that this only configures the "backend" node-local port, not the
diff --git a/rel/reltool.config b/rel/reltool.config
index 5e86d9643..2c55d0900 100644
--- a/rel/reltool.config
+++ b/rel/reltool.config
@@ -15,7 +15,6 @@
{rel, "couchdb", "2.2.0", [
%% stdlib
asn1,
- bcrypt,
compiler,
crypto,
inets,
@@ -68,7 +67,6 @@
%% stdlib
{app, asn1, [{incl_cond, include}]},
- {app, bcrypt, [{incl_cond, include}]},
{app, compiler, [{incl_cond, include}]},
{app, crypto, [{incl_cond, include}]},
{app, inets, [{incl_cond, include}]},
diff --git a/src/chttpd/src/chttpd.erl b/src/chttpd/src/chttpd.erl
index c0179babc..a5628396b 100644
--- a/src/chttpd/src/chttpd.erl
+++ b/src/chttpd/src/chttpd.erl
@@ -681,7 +681,7 @@ doc_etag(#doc{id=Id, body=Body, revs={Start, [DiskRev|_]}}) ->
couch_httpd:doc_etag(Id, Body, {Start, DiskRev}).
make_etag(Term) ->
- <<SigInt:128/integer>> = crypto:hash(md5, term_to_binary(Term)),
+ <<SigInt:128/integer>> = couch_hash:md5_hash(term_to_binary(Term)),
list_to_binary(io_lib:format("\"~.36B\"",[SigInt])).
etag_match(Req, CurrentEtag) when is_binary(CurrentEtag) ->
diff --git a/src/chttpd/src/chttpd_auth_request.erl b/src/chttpd/src/chttpd_auth_request.erl
index 05c5e8e35..9110ed6bc 100644
--- a/src/chttpd/src/chttpd_auth_request.erl
+++ b/src/chttpd/src/chttpd_auth_request.erl
@@ -34,7 +34,10 @@ authorize_request_int(#httpd{path_parts=[]}=Req) ->
authorize_request_int(#httpd{path_parts=[<<"favicon.ico">>|_]}=Req) ->
Req;
authorize_request_int(#httpd{path_parts=[<<"_all_dbs">>|_]}=Req) ->
- Req;
+ case config:get_boolean("chttpd", "admin_only_all_dbs", false) of
+ true -> require_admin(Req);
+ false -> Req
+ end;
authorize_request_int(#httpd{path_parts=[<<"_dbs_info">>|_]}=Req) ->
Req;
authorize_request_int(#httpd{path_parts=[<<"_replicator">>], method='PUT'}=Req) ->
diff --git a/src/chttpd/src/chttpd_misc.erl b/src/chttpd/src/chttpd_misc.erl
index 95345d42b..596e0142b 100644
--- a/src/chttpd/src/chttpd_misc.erl
+++ b/src/chttpd/src/chttpd_misc.erl
@@ -49,6 +49,7 @@ handle_welcome_req(#httpd{method='GET'}=Req, WelcomeMessage) ->
send_json(Req, {[
{couchdb, WelcomeMessage},
{version, list_to_binary(couch_server:get_version())},
+ {git_sha, list_to_binary(couch_server:get_git_sha())},
{features, config:features()}
] ++ case config:get("vendor") of
[] ->
diff --git a/src/chttpd/test/chttpd_welcome_test.erl b/src/chttpd/test/chttpd_welcome_test.erl
index af9732f57..b737abd7a 100644
--- a/src/chttpd/test/chttpd_welcome_test.erl
+++ b/src/chttpd/test/chttpd_welcome_test.erl
@@ -60,6 +60,8 @@ should_have_version(Url) ->
Version = couch_util:get_value(<<"version">>, Json, undefined),
CouchDB = couch_util:get_value(<<"couchdb">>, Json, undefined),
Features = couch_util:get_value(<<"features">>, Json, undefined),
+ Sha = couch_util:get_value(<<"git_sha">>, Json, undefined),
+ ?assertNotEqual(Sha, undefined),
?assertEqual(<<"Welcome">>, CouchDB),
RealVersion = list_to_binary(couch_server:get_version()),
?assertEqual(RealVersion, Version),
diff --git a/src/couch/rebar.config.script b/src/couch/rebar.config.script
index 498ce3a82..5321cff66 100644
--- a/src/couch/rebar.config.script
+++ b/src/couch/rebar.config.script
@@ -39,6 +39,13 @@ Version = case os:getenv("COUCHDB_VERSION") of
string:strip(Version0, right)
end,
+GitSha = case os:getenv("COUCHDB_GIT_SHA") of
+ false ->
+ ""; % release builds won’t get a fallback
+ GitSha0 ->
+ string:strip(GitSha0, right)
+end,
+
CouchConfig = case filelib:is_file(os:getenv("COUCHDB_CONFIG")) of
true ->
{ok, Result} = file:consult(os:getenv("COUCHDB_CONFIG")),
@@ -64,6 +71,13 @@ ConfigSrc = [["#define ", K, " ", V, $\n] || {K, V} <- ConfigH],
ConfigBin = iolist_to_binary(ConfigSrc),
ok = CopyIfDifferent(CouchJSConfig, ConfigBin),
+MD5Config = case lists:keyfind(erlang_md5, 1, CouchConfig) of
+ {erlang_md5, true} ->
+ [{d, 'ERLANG_MD5', true}];
+ _ ->
+ []
+end,
+
%% TODO support curl on Windows
{JS_CFLAGS, JS_LDFLAGS} = case lists:keyfind(with_curl, 1, CouchConfig) of
{with_curl, true} ->
@@ -142,8 +156,9 @@ AddConfig = [
{port_specs, PortSpecs},
{erl_opts, PlatformDefines ++ [
{d, 'COUCHDB_VERSION', Version},
+ {d, 'COUCHDB_GIT_SHA', GitSha},
{i, "../"}
- ]},
+ ] ++ MD5Config},
{eunit_compile_opts, PlatformDefines}
].
diff --git a/src/couch/src/couch.app.src b/src/couch/src/couch.app.src
index cf5cee6b8..6af213624 100644
--- a/src/couch/src/couch.app.src
+++ b/src/couch/src/couch.app.src
@@ -31,7 +31,6 @@
kernel,
stdlib,
crypto,
- bcrypt,
sasl,
inets,
ssl,
diff --git a/src/couch/src/couch.erl b/src/couch/src/couch.erl
index f956b4b3d..fd5c9e101 100644
--- a/src/couch/src/couch.erl
+++ b/src/couch/src/couch.erl
@@ -21,7 +21,6 @@ deps() ->
inets,
os_mon,
crypto,
- bcrypt,
public_key,
ssl,
ibrowse,
diff --git a/src/couch/src/couch_auth_cache.erl b/src/couch/src/couch_auth_cache.erl
index 425cce010..157b0902e 100644
--- a/src/couch/src/couch_auth_cache.erl
+++ b/src/couch/src/couch_auth_cache.erl
@@ -92,8 +92,6 @@ get_admin(UserName) when is_list(UserName) ->
"-pbkdf2-" ++ HashedPwdSaltAndIterations ->
[HashedPwd, Salt, Iterations] = string:tokens(HashedPwdSaltAndIterations, ","),
make_admin_doc(HashedPwd, Salt, Iterations);
- "-bcrypt-" ++ HashedPwd ->
- make_admin_doc(HashedPwd);
_Else ->
nil
end.
@@ -111,11 +109,6 @@ make_admin_doc(DerivedKey, Salt, Iterations) ->
{<<"password_scheme">>, <<"pbkdf2">>},
{<<"derived_key">>, ?l2b(DerivedKey)}].
-make_admin_doc(DerivedKey) ->
- [{<<"roles">>, [<<"_admin">>]},
- {<<"password_scheme">>, <<"bcrypt">>},
- {<<"derived_key">>, ?l2b(DerivedKey)}].
-
get_from_cache(UserName) ->
exec_if_auth_db(
fun(_AuthDb) ->
diff --git a/src/couch/src/couch_bt_engine.erl b/src/couch/src/couch_bt_engine.erl
index a42d116f8..ee0d6d864 100644
--- a/src/couch/src/couch_bt_engine.erl
+++ b/src/couch/src/couch_bt_engine.erl
@@ -330,7 +330,7 @@ serialize_doc(#st{} = St, #doc{} = Doc) ->
Body = Compress(Doc#doc.body),
Atts = Compress(Doc#doc.atts),
SummaryBin = ?term_to_bin({Body, Atts}),
- Md5 = crypto:hash(md5, SummaryBin),
+ Md5 = couch_hash:md5_hash(SummaryBin),
Data = couch_file:assemble_file_chunk(SummaryBin, Md5),
% TODO: This is a terrible hack to get around the issues
% in COUCHDB-3255. We'll need to come back and figure
diff --git a/src/couch/src/couch_db.erl b/src/couch/src/couch_db.erl
index b47cc7ece..65ca54a59 100644
--- a/src/couch/src/couch_db.erl
+++ b/src/couch/src/couch_db.erl
@@ -938,7 +938,7 @@ new_revid(#doc{body=Body, revs={OldStart,OldRevs}, atts=Atts, deleted=Deleted})
?l2b(integer_to_list(couch_util:rand32()));
Atts2 ->
OldRev = case OldRevs of [] -> 0; [OldRev0|_] -> OldRev0 end,
- crypto:hash(md5, term_to_binary([Deleted, OldStart, OldRev, Body, Atts2], [{minor_version, 1}]))
+ couch_hash:md5_hash(term_to_binary([Deleted, OldStart, OldRev, Body, Atts2], [{minor_version, 1}]))
end.
new_revs([], OutBuckets, IdRevsAcc) ->
diff --git a/src/couch/src/couch_file.erl b/src/couch/src/couch_file.erl
index 9f668ea69..55cb95661 100644
--- a/src/couch/src/couch_file.erl
+++ b/src/couch/src/couch_file.erl
@@ -132,7 +132,7 @@ append_binary(Fd, Bin) ->
append_binary_md5(Fd, Bin) ->
ioq:call(Fd,
- {append_bin, assemble_file_chunk(Bin, crypto:hash(md5, Bin))},
+ {append_bin, assemble_file_chunk(Bin, couch_hash:md5_hash(Bin))},
erlang:get(io_priority)).
append_raw_chunk(Fd, Chunk) ->
@@ -175,7 +175,7 @@ pread_iolist(Fd, Pos) ->
{ok, IoList, <<>>} ->
{ok, IoList};
{ok, IoList, Md5} ->
- case crypto:hash(md5, IoList) of
+ case couch_hash:md5_hash(IoList) of
Md5 ->
{ok, IoList};
_ ->
@@ -333,7 +333,7 @@ read_header(Fd) ->
write_header(Fd, Data) ->
Bin = term_to_binary(Data),
- Md5 = crypto:hash(md5, Bin),
+ Md5 = couch_hash:md5_hash(Bin),
% now we assemble the final header binary and write to disk
FinalBin = <<Md5/binary, Bin/binary>>,
ioq:call(Fd, {write_header, FinalBin}, erlang:get(io_priority)).
@@ -559,7 +559,7 @@ load_header(Fd, Pos, HeaderLen, RestBlock) ->
end,
<<Md5Sig:16/binary, HeaderBin/binary>> =
iolist_to_binary(remove_block_prefixes(?PREFIX_SIZE, RawBin)),
- Md5Sig = crypto:hash(md5, HeaderBin),
+ Md5Sig = couch_hash:md5_hash(HeaderBin),
{ok, HeaderBin}.
diff --git a/src/couch/src/couch_hash.erl b/src/couch/src/couch_hash.erl
new file mode 100644
index 000000000..842b37423
--- /dev/null
+++ b/src/couch/src/couch_hash.erl
@@ -0,0 +1,45 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+% http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-module(couch_hash).
+
+-export([md5_hash/1, md5_hash_final/1, md5_hash_init/0, md5_hash_update/2]).
+
+-ifdef(ERLANG_MD5).
+
+md5_hash(Data) ->
+ erlang:md5(Data).
+
+md5_hash_final(Context) ->
+ erlang:md5_final(Context).
+
+md5_hash_init() ->
+ erlang:md5_init().
+
+md5_hash_update(Context, Data) ->
+ erlang:md5_update(Context, Data).
+
+-else.
+
+md5_hash(Data) ->
+ crypto:hash(md5, Data).
+
+md5_hash_final(Context) ->
+ crypto:hash_final(Context).
+
+md5_hash_init() ->
+ crypto:hash_init(md5).
+
+md5_hash_update(Context, Data) ->
+ crypto:hash_update(Context, Data).
+
+-endif.
diff --git a/src/couch/src/couch_httpd.erl b/src/couch/src/couch_httpd.erl
index 050282a0c..a8cfca6d2 100644
--- a/src/couch/src/couch_httpd.erl
+++ b/src/couch/src/couch_httpd.erl
@@ -622,7 +622,7 @@ rev_etag({Start, DiskRev}) ->
<<$", Rev/binary, $">>.
make_etag(Term) ->
- <<SigInt:128/integer>> = crypto:hash(md5, term_to_binary(Term)),
+ <<SigInt:128/integer>> = couch_hash:md5_hash(term_to_binary(Term)),
iolist_to_binary([$", io_lib:format("~.36B", [SigInt]), $"]).
etag_match(Req, CurrentEtag) when is_binary(CurrentEtag) ->
diff --git a/src/couch/src/couch_httpd_auth.erl b/src/couch/src/couch_httpd_auth.erl
index 74cbe5a08..6ac7b75af 100644
--- a/src/couch/src/couch_httpd_auth.erl
+++ b/src/couch/src/couch_httpd_auth.erl
@@ -309,12 +309,7 @@ handle_session_req(#httpd{method='POST', mochi_req=MochiReq}=Req, AuthModule) ->
Secret = ?l2b(ensure_cookie_auth_secret()),
UserSalt = couch_util:get_value(<<"salt">>, UserProps),
CurrentTime = make_cookie_time(),
- Cookie = case UserSalt of
- undefined ->
- cookie_auth_cookie(Req, ?b2l(UserName), <<Secret/binary>>, CurrentTime);
- _ ->
- cookie_auth_cookie(Req, ?b2l(UserName), <<Secret/binary, UserSalt/binary>>, CurrentTime)
- end,
+ Cookie = cookie_auth_cookie(Req, ?b2l(UserName), <<Secret/binary, UserSalt/binary>>, CurrentTime),
% TODO document the "next" feature in Futon
{Code, Headers} = case couch_httpd:qs_value(Req, "next", nil) of
nil ->
@@ -406,10 +401,7 @@ authenticate(Pass, UserProps) ->
Iterations = couch_util:get_value(<<"iterations">>, UserProps, 10000),
verify_iterations(Iterations),
{couch_passwords:pbkdf2(Pass, UserSalt, Iterations),
- couch_util:get_value(<<"derived_key">>, UserProps, nil)};
- <<"bcrypt">> ->
- UserHash = couch_util:get_value(<<"derived_key">>, UserProps, nil),
- {couch_passwords:bcrypt(Pass, UserHash), UserHash}
+ couch_util:get_value(<<"derived_key">>, UserProps, nil)}
end,
couch_passwords:verify(PasswordHash, ExpectedHash).
diff --git a/src/couch/src/couch_native_process.erl b/src/couch/src/couch_native_process.erl
index 8f8ce8b1d..eee8b2860 100644
--- a/src/couch/src/couch_native_process.erl
+++ b/src/couch/src/couch_native_process.erl
@@ -363,11 +363,11 @@ bindings(State, Sig, DDoc) ->
% thanks to erlview, via:
% http://erlang.org/pipermail/erlang-questions/2003-November/010544.html
makefun(State, Source) ->
- Sig = crypto:hash(md5, Source),
+ Sig = couch_hash:md5_hash(Source),
BindFuns = bindings(State, Sig),
{Sig, makefun(State, Source, BindFuns)}.
makefun(State, Source, {DDoc}) ->
- Sig = crypto:hash(md5, lists:flatten([Source, term_to_binary(DDoc)])),
+ Sig = couch_hash:md5_hash(lists:flatten([Source, term_to_binary(DDoc)])),
BindFuns = bindings(State, Sig, {DDoc}),
{Sig, makefun(State, Source, BindFuns)};
makefun(_State, Source, BindFuns) when is_list(BindFuns) ->
diff --git a/src/couch/src/couch_passwords.erl b/src/couch/src/couch_passwords.erl
index 77e136144..baf78f5d5 100644
--- a/src/couch/src/couch_passwords.erl
+++ b/src/couch/src/couch_passwords.erl
@@ -12,7 +12,7 @@
-module(couch_passwords).
--export([simple/2, pbkdf2/3, pbkdf2/4, bcrypt/2, verify/2]).
+-export([simple/2, pbkdf2/3, pbkdf2/4, verify/2]).
-export([hash_admin_password/1, get_unhashed_admins/0]).
-include_lib("couch/include/couch_db.hrl").
@@ -51,10 +51,7 @@ hash_admin_password("pbkdf2", ClearPassword) ->
Salt ,list_to_integer(Iterations)),
?l2b("-pbkdf2-" ++ ?b2l(DerivedKey) ++ ","
++ ?b2l(Salt) ++ ","
- ++ Iterations);
-hash_admin_password("bcrypt", ClearPassword) ->
- LogRounds = list_to_integer(config:get("couch_httpd_auth", "log_rounds", "10")),
- ?l2b("-bcrypt-" ++ couch_passwords:bcrypt(couch_util:to_binary(ClearPassword), LogRounds)).
+ ++ Iterations).
-spec get_unhashed_admins() -> list().
get_unhashed_admins() ->
@@ -63,8 +60,6 @@ get_unhashed_admins() ->
false; % already hashed
({_User, "-pbkdf2-" ++ _}) ->
false; % already hashed
- ({_User, "-bcrypt-" ++ _}) ->
- false; % already hashed
({_User, _ClearPassword}) ->
true
end,
@@ -128,16 +123,6 @@ pbkdf2(Password, Salt, Iterations, BlockIndex, Iteration, Prev, Acc) ->
pbkdf2(Password, Salt, Iterations, BlockIndex, Iteration + 1,
Next, crypto:exor(Next, Acc)).
-%% Define the bcrypt functions to hash a password
--spec bcrypt(binary(), binary()) -> binary();
- (binary(), integer()) -> binary().
-bcrypt(Password, Salt) when is_binary(Salt) ->
- {ok, Hash} = bcrypt:hashpw(Password, Salt),
- list_to_binary(Hash);
-bcrypt(Password, LogRounds) when is_integer(LogRounds) ->
- {ok, Salt} = bcrypt:gen_salt(LogRounds),
- bcrypt(Password, list_to_binary(Salt)).
-
%% verify two lists for equality without short-circuits to avoid timing attacks.
-spec verify(string(), string(), integer()) -> boolean().
verify([X|RestX], [Y|RestY], Result) ->
diff --git a/src/couch/src/couch_query_servers.erl b/src/couch/src/couch_query_servers.erl
index de8ef1e15..7047364e2 100644
--- a/src/couch/src/couch_query_servers.erl
+++ b/src/couch/src/couch_query_servers.erl
@@ -90,11 +90,8 @@ group_reductions_results(List) ->
finalize(<<"_approx_count_distinct",_/binary>>, Reduction) ->
true = hyper:is_hyper(Reduction),
{ok, round(hyper:card(Reduction))};
-finalize(<<"_stats",_/binary>>, {_, _, _, _, _} = Unpacked) ->
+finalize(<<"_stats",_/binary>>, Unpacked) ->
{ok, pack_stats(Unpacked)};
-finalize(<<"_stats",_/binary>>, {Packed}) ->
- % Legacy code path before we had the finalize operation
- {ok, {Packed}};
finalize(_RedSrc, Reduction) ->
{ok, Reduction}.
@@ -299,8 +296,12 @@ unpack_stats({PreRed}) when is_list(PreRed) ->
get_number(<<"sumsqr">>, PreRed)
}.
+
pack_stats({Sum, Cnt, Min, Max, Sqr}) ->
{[{<<"sum">>,Sum}, {<<"count">>,Cnt}, {<<"min">>,Min}, {<<"max">>,Max}, {<<"sumsqr">>,Sqr}]};
+pack_stats({Packed}) ->
+ % Legacy code path before we had the finalize operation
+ {Packed};
pack_stats(Stats) when is_list(Stats) ->
lists:map(fun pack_stats/1, Stats).
@@ -609,4 +610,49 @@ stat_values_test() ->
{18, 2, 5, 13, 194}
], stat_values([2,3,5], [7,11,13])).
+reduce_stats_test() ->
+ ?assertEqual([
+ {[{<<"sum">>,2},{<<"count">>,1},{<<"min">>,2},{<<"max">>,2},{<<"sumsqr">>,4}]}
+ ], test_reduce(<<"_stats">>, [[[null, key], 2]])),
+
+ ?assertEqual([[
+ {[{<<"sum">>,1},{<<"count">>,1},{<<"min">>,1},{<<"max">>,1},{<<"sumsqr">>,1}]},
+ {[{<<"sum">>,2},{<<"count">>,1},{<<"min">>,2},{<<"max">>,2},{<<"sumsqr">>,4}]}
+ ]], test_reduce(<<"_stats">>, [[[null, key],[1,2]]])),
+
+ ?assertEqual(
+ {[{<<"sum">>,2},{<<"count">>,1},{<<"min">>,2},{<<"max">>,2},{<<"sumsqr">>,4}]}
+ , element(2, finalize(<<"_stats">>, {2, 1, 2, 2, 4}))),
+
+ ?assertEqual([
+ {[{<<"sum">>,1},{<<"count">>,1},{<<"min">>,1},{<<"max">>,1},{<<"sumsqr">>,1}]},
+ {[{<<"sum">>,2},{<<"count">>,1},{<<"min">>,2},{<<"max">>,2},{<<"sumsqr">>,4}]}
+ ], element(2, finalize(<<"_stats">>, [
+ {1, 1, 1, 1, 1},
+ {2, 1, 2, 2, 4}
+ ]))),
+
+ ?assertEqual([
+ {[{<<"sum">>,1},{<<"count">>,1},{<<"min">>,1},{<<"max">>,1},{<<"sumsqr">>,1}]},
+ {[{<<"sum">>,2},{<<"count">>,1},{<<"min">>,2},{<<"max">>,2},{<<"sumsqr">>,4}]}
+ ], element(2, finalize(<<"_stats">>, [
+ {1, 1, 1, 1, 1},
+ {[{<<"sum">>,2},{<<"count">>,1},{<<"min">>,2},{<<"max">>,2},{<<"sumsqr">>,4}]}
+ ]))),
+
+ ?assertEqual([
+ {[{<<"sum">>,1},{<<"count">>,1},{<<"min">>,1},{<<"max">>,1},{<<"sumsqr">>,1}]},
+ {[{<<"sum">>,2},{<<"count">>,1},{<<"min">>,2},{<<"max">>,2},{<<"sumsqr">>,4}]}
+ ], element(2, finalize(<<"_stats">>, [
+ {[{<<"sum">>,1},{<<"count">>,1},{<<"min">>,1},{<<"max">>,1},{<<"sumsqr">>,1}]},
+ {2, 1, 2, 2, 4}
+ ]))),
+ ok.
+
+test_reduce(Reducer, KVs) ->
+ ?assertMatch({ok, _}, reduce(<<"javascript">>, [Reducer], KVs)),
+ {ok, Reduced} = reduce(<<"javascript">>, [Reducer], KVs),
+ {ok, Finalized} = finalize(Reducer, Reduced),
+ Finalized.
+
-endif.
diff --git a/src/couch/src/couch_server.erl b/src/couch/src/couch_server.erl
index 002f08ebb..ede8227c8 100644
--- a/src/couch/src/couch_server.erl
+++ b/src/couch/src/couch_server.erl
@@ -15,7 +15,7 @@
-behaviour(config_listener).
-vsn(3).
--export([open/2,create/2,delete/2,get_version/0,get_version/1,get_uuid/0]).
+-export([open/2,create/2,delete/2,get_version/0,get_version/1,get_git_sha/0,get_uuid/0]).
-export([all_databases/0, all_databases/2]).
-export([init/1, handle_call/3,sup_start_link/0]).
-export([handle_cast/2,code_change/3,handle_info/2,terminate/2]).
@@ -57,6 +57,7 @@ get_version(short) ->
[Version|_Rest] = string:tokens(get_version(), "+"),
Version.
+get_git_sha() -> ?COUCHDB_GIT_SHA.
get_uuid() ->
case config:get("couchdb", "uuid", undefined) of
diff --git a/src/couch/src/couch_stream.erl b/src/couch/src/couch_stream.erl
index 83b0611eb..033562932 100644
--- a/src/couch/src/couch_stream.erl
+++ b/src/couch/src/couch_stream.erl
@@ -98,9 +98,9 @@ foldl({Engine, EngineState}, Fun, Acc) ->
foldl(Engine, <<>>, Fun, Acc) ->
foldl(Engine, Fun, Acc);
foldl(Engine, Md5, UserFun, UserAcc) ->
- InitAcc = {crypto:hash_init(md5), UserFun, UserAcc},
+ InitAcc = {couch_hash:md5_hash_init(), UserFun, UserAcc},
{Md5Acc, _, OutAcc} = foldl(Engine, fun foldl_md5/2, InitAcc),
- Md5 = crypto:hash_final(Md5Acc),
+ Md5 = couch_hash:md5_hash_final(Md5Acc),
OutAcc.
@@ -128,7 +128,7 @@ range_foldl(Engine, From, To, UserFun, UserAcc) when To >= From ->
foldl_md5(Bin, {Md5Acc, UserFun, UserAcc}) ->
- NewMd5Acc = crypto:hash_update(Md5Acc, Bin),
+ NewMd5Acc = couch_hash:md5_hash_update(Md5Acc, Bin),
{NewMd5Acc, UserFun, UserFun(Bin, UserAcc)}.
@@ -201,8 +201,8 @@ init({Engine, OpenerPid, OpenerPriority, Options}) ->
{ok, #stream{
engine=Engine,
opener_monitor=erlang:monitor(process, OpenerPid),
- md5=crypto:hash_init(md5),
- identity_md5=crypto:hash_init(md5),
+ md5=couch_hash:md5_hash_init(),
+ identity_md5=couch_hash:md5_hash_init(),
encoding_fun=EncodingFun,
end_encoding_fun=EndEncodingFun,
max_buffer=couch_util:get_value(
@@ -227,7 +227,7 @@ handle_call({write, Bin}, _From, Stream) ->
encoding_fun = EncodingFun} = Stream,
if BinSize + BufferLen > Max ->
WriteBin = lists:reverse(Buffer, [Bin]),
- IdenMd5_2 = crypto:hash_update(IdenMd5, WriteBin),
+ IdenMd5_2 = couch_hash:md5_hash_update(IdenMd5, WriteBin),
case EncodingFun(WriteBin) of
[] ->
% case where the encoder did some internal buffering
@@ -238,7 +238,7 @@ handle_call({write, Bin}, _From, Stream) ->
WriteBin2 ->
NewEngine = do_write(Engine, WriteBin2),
WrittenLen2 = WrittenLen + iolist_size(WriteBin2),
- Md5_2 = crypto:hash_update(Md5, WriteBin2)
+ Md5_2 = couch_hash:md5_hash_update(Md5, WriteBin2)
end,
{reply, ok, Stream#stream{
@@ -268,9 +268,9 @@ handle_call(close, _From, Stream) ->
end_encoding_fun = EndEncodingFun} = Stream,
WriteBin = lists:reverse(Buffer),
- IdenMd5Final = crypto:hash_final(crypto:hash_update(IdenMd5, WriteBin)),
+ IdenMd5Final = couch_hash:md5_hash_final(couch_hash:md5_hash_update(IdenMd5, WriteBin)),
WriteBin2 = EncodingFun(WriteBin) ++ EndEncodingFun(),
- Md5Final = crypto:hash_final(crypto:hash_update(Md5, WriteBin2)),
+ Md5Final = couch_hash:md5_hash_final(couch_hash:md5_hash_update(Md5, WriteBin2)),
Result = case WriteBin2 of
[] ->
{do_finalize(Engine), WrittenLen, IdenLen, Md5Final, IdenMd5Final};
diff --git a/src/couch/src/couch_users_db.erl b/src/couch/src/couch_users_db.erl
index dd6d3208c..c7b41f1fc 100644
--- a/src/couch/src/couch_users_db.erl
+++ b/src/couch/src/couch_users_db.erl
@@ -23,7 +23,6 @@
-define(SIMPLE, <<"simple">>).
-define(PASSWORD_SHA, <<"password_sha">>).
-define(PBKDF2, <<"pbkdf2">>).
--define(BCRYPT, <<"bcrypt">>).
-define(ITERATIONS, <<"iterations">>).
-define(SALT, <<"salt">>).
-define(replace(L, K, V), lists:keystore(K, 1, L, {K, V})).
@@ -60,7 +59,7 @@ before_doc_update(Doc, Db) ->
% newDoc.salt = salt
% newDoc.password = null
save_doc(#doc{body={Body}} = Doc) ->
- %% Support all schemes to smooth migration from legacy scheme
+ %% Support both schemes to smooth migration from legacy scheme
Scheme = config:get("couch_httpd_auth", "password_scheme", "pbkdf2"),
case {couch_util:get_value(?PASSWORD, Body), Scheme} of
{null, _} -> % server admins don't have a user-db password entry
@@ -85,13 +84,6 @@ save_doc(#doc{body={Body}} = Doc) ->
Body3 = ?replace(Body2, ?SALT, Salt),
Body4 = proplists:delete(?PASSWORD, Body3),
Doc#doc{body={Body4}};
- {ClearPassword, "bcrypt"} ->
- LogRounds = list_to_integer(config:get("couch_httpd_auth", "log_rounds", "10")),
- DerivedKey = couch_passwords:bcrypt(ClearPassword, LogRounds),
- Body0 = ?replace(Body, ?PASSWORD_SCHEME, ?BCRYPT),
- Body1 = ?replace(Body0, ?DERIVED_KEY, DerivedKey),
- Body2 = proplists:delete(?PASSWORD, Body1),
- Doc#doc{body={Body2}};
{_ClearPassword, Scheme} ->
couch_log:error("[couch_httpd_auth] password_scheme value of '~p' is invalid.", [Scheme]),
throw({forbidden, "Server cannot hash passwords at this time."})
diff --git a/src/couch/src/test_engine_util.erl b/src/couch/src/test_engine_util.erl
index fef9e9f92..6cc6bccdc 100644
--- a/src/couch/src/test_engine_util.erl
+++ b/src/couch/src/test_engine_util.erl
@@ -186,7 +186,7 @@ gen_write(Engine, St, {create, {DocId, Body, Atts0}}, UpdateSeq) ->
[not_found] = Engine:open_docs(St, [DocId]),
Atts = [couch_att:to_disk_term(Att) || Att <- Atts0],
- Rev = crypto:hash(md5, term_to_binary({DocId, Body, Atts})),
+ Rev = couch_hash:md5_hash(term_to_binary({DocId, Body, Atts})),
Doc0 = #doc{
id = DocId,
@@ -323,11 +323,11 @@ gen_write(Engine, St, {Action, {DocId, Body, Atts0}}, UpdateSeq) ->
gen_revision(conflict, DocId, _PrevRev, Body, Atts) ->
- crypto:hash(md5, term_to_binary({DocId, Body, Atts}));
+ couch_hash:md5_hash(term_to_binary({DocId, Body, Atts}));
gen_revision(delete, DocId, PrevRev, Body, Atts) ->
gen_revision(update, DocId, PrevRev, Body, Atts);
gen_revision(update, DocId, PrevRev, Body, Atts) ->
- crypto:hash(md5, term_to_binary({DocId, PrevRev, Body, Atts})).
+ couch_hash:md5_hash(term_to_binary({DocId, PrevRev, Body, Atts})).
gen_path(conflict, _RevPos, _PrevRevId, Rev, Leaf) ->
@@ -373,7 +373,7 @@ prep_atts(Engine, St, [{FileName, Data} | Rest]) ->
write_att(Stream, FileName, OrigData, <<>>) ->
{StreamEngine, Len, Len, Md5, Md5} = couch_stream:close(Stream),
- couch_util:check_md5(Md5, crypto:hash(md5, OrigData)),
+ couch_util:check_md5(Md5, couch_hash:md5_hash(OrigData)),
Len = size(OrigData),
couch_att:new([
{name, FileName},
diff --git a/src/couch/src/test_request.erl b/src/couch/src/test_request.erl
index 4dfde1a33..48f49bda6 100644
--- a/src/couch/src/test_request.erl
+++ b/src/couch/src/test_request.erl
@@ -101,7 +101,11 @@ request(Method, Url, Headers, Body, Opts, N) ->
{error, {'EXIT', {normal, _}}} ->
% Connection closed right after a successful request that
% used the same connection.
- request(Method, Url, Headers, Body, N - 1);
+ request(Method, Url, Headers, Body, Opts, N - 1);
+ {error, retry_later} ->
+ % CouchDB is busy, let’s wait a bit
+ timer:sleep(3000 div N),
+ request(Method, Url, Headers, Body, Opts, N - 1);
Error ->
Error
end.
diff --git a/src/couch/src/test_util.erl b/src/couch/src/test_util.erl
index 738e9a3fb..efb506460 100644
--- a/src/couch/src/test_util.erl
+++ b/src/couch/src/test_util.erl
@@ -101,6 +101,9 @@ start_applications([App|Apps], Acc) ->
io:format(standard_error, "Application ~s was left running!~n", [App]),
application:stop(App),
start_applications([App|Apps], Acc);
+ {error, Reason} ->
+ io:format(standard_error, "Cannot start application '~s', reason ~p~n", [App, Reason]),
+ throw({error, {cannot_start, App, Reason}});
ok ->
start_applications(Apps, [App|Acc])
end.
diff --git a/src/couch/test/couch_passwords_tests.erl b/src/couch/test/couch_passwords_tests.erl
index a56627361..dea6d6b7b 100644
--- a/src/couch/test/couch_passwords_tests.erl
+++ b/src/couch/test/couch_passwords_tests.erl
@@ -14,6 +14,7 @@
-include_lib("couch/include/couch_eunit.hrl").
+
pbkdf2_test_()->
{"PBKDF2",
[
@@ -51,44 +52,3 @@ pbkdf2_test_()->
{ok, <<"eefe3d61cd4da4e4e9945b3d6ba2158c2634e984">>},
couch_passwords:pbkdf2(<<"password">>, <<"salt">>, 16777216, 20)
)}}]}.
-
-
-bcrypt_test_() ->
- {
- "Bcrypt",
- {
- setup,
- fun() ->
- test_util:start_applications([bcrypt])
- end,
- fun test_util:stop_applications/1,
- [
- {"Log rounds: 4",
- {timeout, 1, fun bcrypt_logRounds_4/0}},
- {"Log rounds: 5",
- {timeout, 1, fun bcrypt_logRounds_5/0}},
- {"Log rounds: 12",
- {timeout, 5, fun bcrypt_logRounds_12/0}},
- {"Null byte",
- {timeout, 5, fun bcrypt_null_byte/0}}
-
- ]
- }
- }.
-
-bcrypt_logRounds_4() ->
- bcrypt_assert_equal(<<"password">>, 4).
-
-bcrypt_logRounds_5() ->
- bcrypt_assert_equal(<<"password">>, 5).
-
-bcrypt_logRounds_12() ->
- bcrypt_assert_equal(<<"password">>, 12).
-
-bcrypt_null_byte() ->
- bcrypt_assert_equal(<<"passw\0rd">>, 12).
-
-bcrypt_assert_equal(Password, Rounds) when is_integer(Rounds) ->
- HashPass = couch_passwords:bcrypt(Password, Rounds),
- ReHashPass = couch_passwords:bcrypt(Password, HashPass),
- ?assertEqual(HashPass, ReHashPass).
diff --git a/src/couch/test/couchdb_attachments_tests.erl b/src/couch/test/couchdb_attachments_tests.erl
index a85a01f48..04859dbc9 100644
--- a/src/couch/test/couchdb_attachments_tests.erl
+++ b/src/couch/test/couchdb_attachments_tests.erl
@@ -208,7 +208,7 @@ should_upload_attachment_with_valid_md5_header({Host, DbName}) ->
Headers = [
{"Content-Length", "34"},
{"Content-Type", "text/plain"},
- {"Content-MD5", ?b2l(base64:encode(crypto:hash(md5, Body)))},
+ {"Content-MD5", ?b2l(base64:encode(couch_hash:md5_hash(Body)))},
{"Host", Host}
],
{ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
@@ -224,7 +224,7 @@ should_upload_attachment_by_chunks_with_valid_md5_header({Host, DbName}) ->
Body = [chunked_body([Part1, Part2]), "\r\n"],
Headers = [
{"Content-Type", "text/plain"},
- {"Content-MD5", ?b2l(base64:encode(crypto:hash(md5, AttData)))},
+ {"Content-MD5", ?b2l(base64:encode(couch_hash:md5_hash(AttData)))},
{"Host", Host},
{"Transfer-Encoding", "chunked"}
],
@@ -239,7 +239,7 @@ should_upload_attachment_by_chunks_with_valid_md5_trailer({Host, DbName}) ->
AttData = <<"We all live in a yellow submarine!">>,
<<Part1:21/binary, Part2:13/binary>> = AttData,
Body = [chunked_body([Part1, Part2]),
- "Content-MD5: ", base64:encode(crypto:hash(md5, AttData)),
+ "Content-MD5: ", base64:encode(couch_hash:md5_hash(AttData)),
"\r\n\r\n"],
Headers = [
{"Content-Type", "text/plain"},
diff --git a/src/couch_epi/src/couch_epi_data.erl b/src/couch_epi/src/couch_epi_data.erl
index 93e39f69d..bbed828bb 100644
--- a/src/couch_epi/src/couch_epi_data.erl
+++ b/src/couch_epi/src/couch_epi_data.erl
@@ -111,4 +111,4 @@ definitions({module, Modules}) ->
hash_of_file(FilePath) ->
{ok, Data} = file:read_file(FilePath),
- crypto:hash(md5, Data).
+ couch_hash:md5_hash(Data).
diff --git a/src/couch_epi/src/couch_epi_util.erl b/src/couch_epi/src/couch_epi_util.erl
index e99db4668..ea4b10ea8 100644
--- a/src/couch_epi/src/couch_epi_util.erl
+++ b/src/couch_epi/src/couch_epi_util.erl
@@ -22,7 +22,7 @@ module_version(Module) ->
VSNs.
hash(Term) ->
- <<SigInt:128/integer>> = crypto:hash(md5, term_to_binary(Term)),
+ <<SigInt:128/integer>> = couch_hash:md5_hash(term_to_binary(Term)),
lists:flatten(io_lib:format("\"~.36B\"",[SigInt])).
module_exists(Module) ->
diff --git a/src/couch_event/src/couch_event_os_sup.erl b/src/couch_event/src/couch_event_os_sup.erl
deleted file mode 100644
index f219d0000..000000000
--- a/src/couch_event/src/couch_event_os_sup.erl
+++ /dev/null
@@ -1,82 +0,0 @@
-% Licensed under the Apache License, Version 2.0 (the "License"); you may not
-% use this file except in compliance with the License. You may obtain a copy of
-% the License at
-%
-% http://www.apache.org/licenses/LICENSE-2.0
-%
-% Unless required by applicable law or agreed to in writing, software
-% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-% License for the specific language governing permissions and limitations under
-% the License.
-
-
-% This causes an OS process to spawned and it is notified every time a database
-% is updated.
-%
-% The notifications are in the form of a the database name sent as a line of
-% text to the OS processes stdout.
-
-
--module(couch_event_os_sup).
--behaviour(supervisor).
--behaviour(config_listener).
-
--vsn(2).
-
--export([
- start_link/0,
- init/1
-]).
-
--export([
- handle_config_change/5,
- handle_config_terminate/3
-]).
-
-
-start_link() ->
- supervisor:start_link({local, ?MODULE}, ?MODULE, []).
-
-
-init([]) ->
- UpdateNotifierExes = config:get("update_notification"),
- Children = [
- {
- config_listener_mon,
- {config_listener_mon, start_link, [?MODULE, nil]},
- permanent,
- 5000,
- worker,
- [config_listener_mon]
- }
- | [child(Id, Exe) || {Id, Exe} <- UpdateNotifierExes]],
-
- {ok, {
- {one_for_one, 10, 3600},
- Children
- }}.
-
-
-handle_config_change("update_notification", Id, deleted, _, _) ->
- supervisor:terminate_child(?MODULE, Id),
- supervisor:delete_child(?MODULE, Id),
- {ok, nil};
-handle_config_change("update_notification", Id, Exe, _, _) when is_list(Exe) ->
- supervisor:start_child(?MODULE, child(Id, Exe)),
- {ok, nil};
-handle_config_change(_, _, _, _, _) ->
- {ok, nil}.
-
-handle_config_terminate(_Server, _Reason, _State) ->
- ok.
-
-child(Id, Arg) ->
- {
- Id,
- {couch_event_os_listener, start_link, [Arg]},
- permanent,
- 1000,
- supervisor,
- [couch_event_os_listener]
- }.
diff --git a/src/couch_event/src/couch_event_sup2.erl b/src/couch_event/src/couch_event_sup2.erl
index 36fbe542e..2d88b93d4 100644
--- a/src/couch_event/src/couch_event_sup2.erl
+++ b/src/couch_event/src/couch_event_sup2.erl
@@ -38,13 +38,6 @@ init(_) ->
5000,
worker,
[couch_event_server]
- },
- {couch_event_os_sup,
- {couch_event_os_sup, start_link, []},
- permanent,
- 5000,
- supervisor,
- [couch_event_os_sup]
}
],
{ok, {{one_for_one, 5, 10}, Children}}.
diff --git a/src/couch_index/test/couch_index_ddoc_updated_tests.erl b/src/couch_index/test/couch_index_ddoc_updated_tests.erl
index 40dadcc62..0e23adf91 100644
--- a/src/couch_index/test/couch_index_ddoc_updated_tests.erl
+++ b/src/couch_index/test/couch_index_ddoc_updated_tests.erl
@@ -118,7 +118,7 @@ fake_index() ->
(idx_name, {_DbName, DDoc}) ->
DDoc#doc.id;
(signature, {_DbName, DDoc}) ->
- crypto:hash(md5, term_to_binary(DDoc));
+ couch_hash:md5_hash(term_to_binary(DDoc));
(update_seq, Seq) ->
Seq
end),
diff --git a/src/couch_mrview/src/couch_mrview.erl b/src/couch_mrview/src/couch_mrview.erl
index 82bbd7928..533dd2de9 100644
--- a/src/couch_mrview/src/couch_mrview.erl
+++ b/src/couch_mrview/src/couch_mrview.erl
@@ -220,7 +220,7 @@ query_all_docs(Db, Args, Callback, Acc) when is_list(Args) ->
query_all_docs(Db, Args0, Callback, Acc) ->
Sig = couch_util:with_db(Db, fun(WDb) ->
{ok, Info} = couch_db:get_db_info(WDb),
- couch_index_util:hexsig(crypto:hash(md5, term_to_binary(Info)))
+ couch_index_util:hexsig(couch_hash:md5_hash(term_to_binary(Info)))
end),
Args1 = Args0#mrargs{view_type=map},
Args2 = couch_mrview_util:validate_args(Args1),
diff --git a/src/couch_mrview/src/couch_mrview_util.erl b/src/couch_mrview/src/couch_mrview_util.erl
index eb461d017..120a9b873 100644
--- a/src/couch_mrview/src/couch_mrview_util.erl
+++ b/src/couch_mrview/src/couch_mrview_util.erl
@@ -157,7 +157,7 @@ ddoc_to_mrst(DbName, #doc{id=Id, body={Fields}}) ->
keyseq_indexed=KeySeqIndexed
},
SigInfo = {Views, Language, DesignOpts, couch_index_util:sort_lib(Lib)},
- {ok, IdxState#mrst{sig=crypto:hash(md5, term_to_binary(SigInfo))}}.
+ {ok, IdxState#mrst{sig=couch_hash:md5_hash(term_to_binary(SigInfo))}}.
set_view_type(_Args, _ViewName, []) ->
@@ -203,7 +203,7 @@ view_sig(Db, State, View, #mrargs{include_docs=true}=Args) ->
keyseq_indexed=KeySeqIndexed
} = State,
Term = view_sig_term(BaseSig, UpdateSeq, PurgeSeq, KeySeqIndexed, SeqIndexed),
- couch_index_util:hexsig(crypto:hash(md5, term_to_binary(Term)));
+ couch_index_util:hexsig(couch_hash:md5_hash(term_to_binary(Term)));
view_sig(Db, State, {_Nth, _Lang, View}, Args) ->
view_sig(Db, State, View, Args);
view_sig(_Db, State, View, Args0) ->
@@ -217,7 +217,7 @@ view_sig(_Db, State, View, Args0) ->
extra=[]
},
Term = view_sig_term(Sig, UpdateSeq, PurgeSeq, KeySeqIndexed, SeqIndexed, Args),
- couch_index_util:hexsig(crypto:hash(md5, term_to_binary(Term))).
+ couch_index_util:hexsig(couch_hash:md5_hash(term_to_binary(Term))).
view_sig_term(BaseSig, UpdateSeq, PurgeSeq, false, false) ->
{BaseSig, UpdateSeq, PurgeSeq};
@@ -1008,7 +1008,7 @@ sig_vsn_12x(State) ->
{ViewInfo, State#mrst.language, State#mrst.design_opts,
couch_index_util:sort_lib(State#mrst.lib)}
end,
- crypto:hash(md5, term_to_binary(SigData)).
+ couch_hash:md5_hash(term_to_binary(SigData)).
old_view_format(View) ->
{
diff --git a/src/couch_replicator/src/couch_replicator_auth.erl b/src/couch_replicator/src/couch_replicator_auth.erl
index 60273fc32..7f51cdd1c 100644
--- a/src/couch_replicator/src/couch_replicator_auth.erl
+++ b/src/couch_replicator/src/couch_replicator_auth.erl
@@ -28,7 +28,7 @@
-type code() :: non_neg_integer().
--define(DEFAULT_PLUGINS, "couch_replicator_auth_noop").
+-define(DEFAULT_PLUGINS, "couch_replicator_auth_session,couch_replicator_auth_noop").
% Behavior API
diff --git a/src/couch_replicator/src/couch_replicator_ids.erl b/src/couch_replicator/src/couch_replicator_ids.erl
index e8faf8ea3..e10b98082 100644
--- a/src/couch_replicator/src/couch_replicator_ids.erl
+++ b/src/couch_replicator/src/couch_replicator_ids.erl
@@ -112,7 +112,7 @@ maybe_append_filters(Base,
{error, FilterParseError} ->
throw({error, FilterParseError})
end,
- couch_util:to_hex(crypto:hash(md5, term_to_binary(Base2))).
+ couch_util:to_hex(couch_hash:md5_hash(term_to_binary(Base2))).
maybe_append_options(Options, RepOptions) ->
diff --git a/src/couch_replicator/test/couch_replicator_many_leaves_tests.erl b/src/couch_replicator/test/couch_replicator_many_leaves_tests.erl
index b2445a236..eee5b1647 100644
--- a/src/couch_replicator/test/couch_replicator_many_leaves_tests.erl
+++ b/src/couch_replicator/test/couch_replicator_many_leaves_tests.erl
@@ -141,7 +141,7 @@ add_doc_siblings(Db, _DocId, 0, AccDocs, AccRevs) ->
add_doc_siblings(Db, DocId, NumLeaves, AccDocs, AccRevs) ->
Value = ?l2b(?i2l(NumLeaves)),
- Rev = crypto:hash(md5, Value),
+ Rev = couch_hash:md5_hash(Value),
Doc = #doc{
id = DocId,
revs = {1, [Rev]},
diff --git a/src/couch_replicator/test/couch_replicator_test_helper.erl b/src/couch_replicator/test/couch_replicator_test_helper.erl
index 8ee2114f0..fd0409164 100644
--- a/src/couch_replicator/test/couch_replicator_test_helper.erl
+++ b/src/couch_replicator/test/couch_replicator_test_helper.erl
@@ -93,16 +93,16 @@ find_att([Att | Rest], Name) ->
att_md5(Att) ->
Md50 = couch_att:foldl(
Att,
- fun(Chunk, Acc) -> crypto:hash_update(Acc, Chunk) end,
- crypto:hash_init(md5)),
- crypto:hash_final(Md50).
+ fun(Chunk, Acc) -> couch_hash:md5_hash_update(Acc, Chunk) end,
+ couch_hash:md5_hash_init()),
+ couch_hash:md5_hash_final(Md50).
att_decoded_md5(Att) ->
Md50 = couch_att:foldl_decode(
Att,
- fun(Chunk, Acc) -> crypto:hash_update(Acc, Chunk) end,
- crypto:hash_init(md5)),
- crypto:hash_final(Md50).
+ fun(Chunk, Acc) -> couch_hash:md5_hash_update(Acc, Chunk) end,
+ couch_hash:md5_hash_init()),
+ couch_hash:md5_hash_final(Md50).
db_url(DbName) ->
iolist_to_binary([
diff --git a/src/fabric/src/fabric.erl b/src/fabric/src/fabric.erl
index 5c517a3bd..185ffebe5 100644
--- a/src/fabric/src/fabric.erl
+++ b/src/fabric/src/fabric.erl
@@ -289,13 +289,14 @@ purge_docs(_DbName, _IdsRevs) ->
not_implemented.
%% @doc spawns a process to upload attachment data and
-%% returns a function that shards can use to communicate
-%% with the spawned middleman process
+%% returns a fabric attachment receiver context tuple
+%% with the spawned middleman process, an empty binary,
+%% or exits with an error tuple {Error, Arg}
-spec att_receiver(#httpd{}, Length :: undefined | chunked | pos_integer() |
{unknown_transfer_encoding, any()}) ->
- function() | binary().
+ {fabric_attachment_receiver, pid(), chunked | pos_integer()} | binary().
att_receiver(Req, Length) ->
- fabric_doc_attachments:receiver(Req, Length).
+ fabric_doc_atts:receiver(Req, Length).
%% @equiv all_docs(DbName, [], Callback, Acc0, QueryArgs)
all_docs(DbName, Callback, Acc, QueryArgs) ->
diff --git a/src/mem3/src/mem3_rep.erl b/src/mem3/src/mem3_rep.erl
index 3d9187796..8d996d617 100644
--- a/src/mem3/src/mem3_rep.erl
+++ b/src/mem3/src/mem3_rep.erl
@@ -106,8 +106,8 @@ make_local_id(#shard{node=SourceNode}, #shard{node=TargetNode}, Filter) ->
make_local_id(SourceThing, TargetThing, Filter) ->
- S = couch_util:encodeBase64Url(crypto:hash(md5, term_to_binary(SourceThing))),
- T = couch_util:encodeBase64Url(crypto:hash(md5, term_to_binary(TargetThing))),
+ S = couch_util:encodeBase64Url(couch_hash:md5_hash(term_to_binary(SourceThing))),
+ T = couch_util:encodeBase64Url(couch_hash:md5_hash(term_to_binary(TargetThing))),
F = case is_function(Filter) of
true ->
{new_uniq, Hash} = erlang:fun_info(Filter, new_uniq),
@@ -339,7 +339,7 @@ update_locals(Acc) ->
find_repl_doc(SrcDb, TgtUUIDPrefix) ->
SrcUUID = couch_db:get_uuid(SrcDb),
- S = couch_util:encodeBase64Url(crypto:hash(md5, term_to_binary(SrcUUID))),
+ S = couch_util:encodeBase64Url(couch_hash:md5_hash(term_to_binary(SrcUUID))),
DocIdPrefix = <<"_local/shard-sync-", S/binary, "-">>,
FoldFun = fun(#doc{id = DocId, body = {BodyProps}} = Doc, _) ->
TgtUUID = couch_util:get_value(<<"target_uuid">>, BodyProps, <<>>),
diff --git a/src/setup/src/setup.erl b/src/setup/src/setup.erl
index 943318675..3ae455f54 100644
--- a/src/setup/src/setup.erl
+++ b/src/setup/src/setup.erl
@@ -30,15 +30,29 @@ require_node_count(undefined) ->
require_node_count(_) ->
ok.
-error_bind_address() ->
- throw({error, "Cluster setup requires bind_addres != 127.0.0.1"}).
-
-require_bind_address("127.0.0.1", undefined) ->
- error_bind_address();
-require_bind_address("127.0.0.1", <<"127.0.0.1">>) ->
- error_bind_address();
-require_bind_address(_, _) ->
- ok.
+error_local_bind_address() ->
+ throw({error, "Cluster setup requires a remote bind_address (not 127.0.0.1 nor ::1)"}).
+
+error_invalid_bind_address(InvalidBindAddress) ->
+ throw({error, io:format("Setup requires a valid IP bind_address. " ++
+ "~p is invalid.", [InvalidBindAddress])}).
+
+require_remote_bind_address(OldBindAddress, NewBindAddress) ->
+ case {OldBindAddress, NewBindAddress} of
+ {"127.0.0.1", undefined} -> error_local_bind_address();
+ {_, <<"127.0.0.1">>} -> error_local_bind_address();
+ {"::1", undefined} -> error_local_bind_address();
+ {_, <<"::1">>} -> error_local_bind_address();
+ {_, undefined} -> ok;
+ {_, PresentNewBindAddress} -> require_valid_bind_address(PresentNewBindAddress)
+ end.
+
+require_valid_bind_address(BindAddress) ->
+ ListBindAddress = binary_to_list(BindAddress),
+ case inet_parse:address(ListBindAddress) of
+ {ok, _} -> ok;
+ {error, _} -> error_invalid_bind_address(ListBindAddress)
+ end.
is_cluster_enabled() ->
% bind_address != 127.0.0.1 AND admins != empty
@@ -122,7 +136,6 @@ enable_cluster_http(Options) ->
{ok, "201", _, _} ->
ok;
Else ->
- couch_log:notice("send_req: ~p~n", [Else]),
{error, Else}
end.
@@ -143,13 +156,13 @@ enable_cluster_int(Options, false) ->
% if bind_address == 127.0.0.1 and no bind_address in req -> error
CurrentBindAddress = config:get("chttpd","bind_address"),
NewBindAddress = proplists:get_value(bind_address, Options),
- ok = require_bind_address(CurrentBindAddress, NewBindAddress),
+ ok = require_remote_bind_address(CurrentBindAddress, NewBindAddress),
NodeCount = couch_util:get_value(node_count, Options),
ok = require_node_count(NodeCount),
Port = proplists:get_value(port, Options),
setup_node(NewCredentials, NewBindAddress, NodeCount, Port),
- couch_log:notice("Enable Cluster: ~p~n", [Options]).
+ couch_log:debug("Enable Cluster: ~p~n", [Options]).
set_admin(Username, Password) ->
config:set("admins", binary_to_list(Username), binary_to_list(Password)).
@@ -162,6 +175,7 @@ setup_node(NewCredentials, NewBindAddress, NodeCount, Port) ->
set_admin(Username, Password)
end,
+ ok = require_valid_bind_address(NewBindAddress),
case NewBindAddress of
undefined ->
config:set("chttpd", "bind_address", "0.0.0.0");
@@ -211,7 +225,7 @@ enable_single_node(Options) ->
setup_node(NewCredentials, NewBindAddress, 1, Port),
Dbs = proplists:get_value(ensure_dbs_exist, Options, cluster_system_dbs()),
finish_cluster_int(Dbs, has_cluster_system_dbs(Dbs)),
- couch_log:notice("Enable Single Node: ~p~n", [Options]).
+ couch_log:debug("Enable Single Node: ~p~n", [Options]).
add_node(Options) ->
@@ -220,7 +234,7 @@ add_node(Options) ->
add_node_int(_Options, false) ->
{error, cluster_not_enabled};
add_node_int(Options, true) ->
- couch_log:notice("add node_int: ~p~n", [Options]),
+ couch_log:debug("add node_int: ~p~n", [Options]),
ErlangCookie = erlang:get_cookie(),
% POST to nodeB/_setup
@@ -251,7 +265,6 @@ add_node_int(Options, true) ->
% when done, PUT :5986/nodes/nodeB
create_node_doc(Host, Name);
Else ->
- couch_log:notice("send_req: ~p~n", [Else]),
Else
end.
diff --git a/test/javascript/tests/design_docs.js b/test/javascript/tests/design_docs.js
index 6e12001d7..ed1e72f3f 100644
--- a/test/javascript/tests/design_docs.js
+++ b/test/javascript/tests/design_docs.js
@@ -373,7 +373,13 @@ couchTests.design_docs = function(debug) {
}
T(db.deleteDoc(designDoc).ok);
- T(db.open(designDoc._id) == null);
+ waitForSuccess(function() {
+ var ddoc = db.open(designDoc._id)
+ if (ddoc != null) {
+ throw({});
+ }
+ return true;
+ }, 'db.open(designDoc._id)');
T(db.view("test/no_docs") == null);
T(db.ensureFullCommit().ok);
diff --git a/test/javascript/tests/users_db_security.js b/test/javascript/tests/users_db_security.js
index c55c76434..1db6c14c5 100644
--- a/test/javascript/tests/users_db_security.js
+++ b/test/javascript/tests/users_db_security.js
@@ -15,8 +15,6 @@ couchTests.users_db_security = function(debug) {
var usersDb = new CouchDB(db_name, {"X-Couch-Full-Commit":"false"});
try { usersDb.createDb(); } catch (e) { /* ignore if exists*/ }
- var passwordSchemes = ['pbkdf2', 'bcrypt'];
-
if (debug) debugger;
var loginUser = function(username) {
@@ -32,13 +30,7 @@ couchTests.users_db_security = function(debug) {
// the actual tests
var username1 = username.replace(/[0-9]$/, "");
var password = pws[username];
- waitForSuccess(function() {
- var req = CouchDB.login(username1, pws[username]);
- if (req.ok) {
- return true
- }
- throw({});
- }, 'loginUser');
+ T(CouchDB.login(username1, pws[username]).ok);
};
var open_as = function(db, docId, username) {
@@ -94,7 +86,7 @@ couchTests.users_db_security = function(debug) {
}
};
- var testFun = function(scheme, derivedKeyTest, saltTest)
+ var testFun = function()
{
// _users db
@@ -113,12 +105,11 @@ couchTests.users_db_security = function(debug) {
// jan's gonna be admin as he's the first user
TEquals(true, usersDb.save(userDoc).ok, "should save document");
+ wait(5000)
userDoc = open_as(usersDb, "org.couchdb.user:jchris", "jchris");
TEquals(undefined, userDoc.password, "password field should be null 1");
- TEquals(scheme, userDoc.password_scheme, "password_scheme should be " + scheme);
- derivedKeyTest(userDoc.derived_key);
- saltTest(userDoc.salt);
-
+ TEquals(40, userDoc.derived_key.length, "derived_key should exist");
+ TEquals(32, userDoc.salt.length, "salt should exist");
// create server admin
@@ -150,13 +141,10 @@ couchTests.users_db_security = function(debug) {
var jchrisDoc = open_as(usersDb, "org.couchdb.user:jchris", "jan");
TEquals(undefined, jchrisDoc.password, "password field should be null 2");
- TEquals(scheme, jchrisDoc.password_scheme, "password_scheme should be " + scheme);
- derivedKeyTest(jchrisDoc.derived_key);
- saltTest(jchrisDoc.salt);
+ TEquals(40, jchrisDoc.derived_key.length, "derived_key should exist");
+ TEquals(32, jchrisDoc.salt.length, "salt should exist");
- if(userDoc.salt || jchrisDoc.salt) {
- TEquals(true, userDoc.salt != jchrisDoc.salt, "should have new salt");
- }
+ TEquals(true, userDoc.salt != jchrisDoc.salt, "should have new salt");
TEquals(true, userDoc.derived_key != jchrisDoc.derived_key,
"should have new derived_key");
@@ -239,7 +227,7 @@ couchTests.users_db_security = function(debug) {
TEquals("forbidden", e.error, "non-admins can't read design docs");
}
- // admin should be able to read _list
+ // admin shold be able to read _list
var listPath = ddoc["_id"] + "/_list/names/test";
var result = request_as(usersDb, listPath, "jan");
var lines = result.responseText.split("\n");
@@ -385,140 +373,14 @@ couchTests.users_db_security = function(debug) {
});
};
- var derivedKeyTests = {
- pbkdf2: function(derived_key) {
- TEquals(40, derived_key.length, "derived_key should exist");
- },
- bcrypt: function(derived_key) {
- TEquals(60, derived_key.length, "derived_key should exist");
- }
- };
- var saltTests = {
- pbkdf2: function(salt) {
- TEquals(32, salt.length, "salt should exist");
- },
- bcrypt: function(salt) {
- TEquals(undefined, salt, "salt should not exist");
- }
- };
- passwordSchemes.forEach(function(scheme){
- run_on_modified_server(
- [{
- section: "couch_httpd_auth",
- key: "iterations", value: "1"
- }, {
- section: "couch_httpd_auth",
- key: "password_scheme", value: scheme
- }, {
- section: "admins",
- key: "jan", value: "apple"
- }],
- function() {
- try {
- testFun(scheme, derivedKeyTests[scheme], saltTests[scheme]);
- } catch (e) {
- throw(e)
- } finally {
- CouchDB.login("jan", "apple");
- usersDb.deleteDb(); // cleanup
- waitForSuccess(function() {
- var req = CouchDB.request("GET", db_name);
- if (req.status == 404) {
- return true
- }
- throw({});
- }, 'usersDb.deleteDb')
-
- usersDb.createDb();
- waitForSuccess(function() {
- var req = CouchDB.request("GET", db_name);
- if (req.status == 200) {
- return true
- }
- throw({});
- }, 'usersDb.creteDb')
- }
- }
- );
- });
-
- var testFunUpdatePasswordScheme = function() {
- var userDocs = {
- jchris: {
- _id: "org.couchdb.user:jchris",
- type: "user",
- name: "jchris",
- password: "mp3",
- roles: []
- },
- fdmanana: {
- _id: "org.couchdb.user:fdmanana",
- type: "user",
- name: "fdmanana",
- password: "foobar",
- roles: []
- }
- };
-
- // create new user (has pbkdf2 hash)
- TEquals(true, usersDb.save(userDocs.jchris).ok, "should save document");
- wait(5000);
- var userDoc = open_as(usersDb, "org.couchdb.user:jchris", "jchris");
- TEquals(undefined, userDoc.password, "password field should be null 1");
- TEquals("pbkdf2", userDoc.password_scheme, "password_scheme should be pbkdf2");
- derivedKeyTests.pbkdf2(userDoc.derived_key);
- saltTests.pbkdf2(userDoc.salt);
-
- // change scheme to bcrypt
- CouchDB.login("jan", "apple");
- var xhr = CouchDB.request("PUT", "/_node/node1@127.0.0.1/_config/couch_httpd_auth/password_scheme", {
- body : JSON.stringify("bcrypt"),
- headers: {"X-Couch-Persist": "false"}
- });
- TEquals(200, xhr.status);
- xhr = CouchDB.request("GET", "/_node/node1@127.0.0.1/_config/couch_httpd_auth/password_scheme");
- var scheme = JSON.parse(xhr.responseText);
- TEquals("bcrypt", scheme);
-
- // create new user (has bcrypt hash)
- TEquals(true, usersDb.save(userDocs.fdmanana).ok, "should save document");
- wait(5000);
- userDoc = open_as(usersDb, "org.couchdb.user:fdmanana", "fdmanana");
- TEquals(undefined, userDoc.password, "password field should be null 1");
- TEquals("bcrypt", userDoc.password_scheme, "password_scheme should be bcrypt");
- derivedKeyTests.bcrypt(userDoc.derived_key);
- saltTests.bcrypt(userDoc.salt);
-
- // test that both users can still log in
- TEquals(true, CouchDB.login(userDocs.jchris.name, userDocs.jchris.password).ok);
- TEquals(true, CouchDB.login(userDocs.fdmanana.name, userDocs.fdmanana.password).ok);
-
- // change scheme back to pbkdf2
- CouchDB.login("jan", "apple");
- var xhr = CouchDB.request("PUT", "/_node/node1@127.0.0.1/_config/couch_httpd_auth/password_scheme", {
- body : JSON.stringify("pbkdf2"),
- headers: {"X-Couch-Persist": "false"}
- });
- TEquals(200, xhr.status);
- xhr = CouchDB.request("GET", "/_node/node1@127.0.0.1/_config/couch_httpd_auth/password_scheme");
- var scheme = JSON.parse(xhr.responseText);
- TEquals("pbkdf2", scheme);
-
- // test that both users can still log in
- TEquals(true, CouchDB.login(userDocs.jchris.name, userDocs.jchris.password).ok);
- TEquals(true, CouchDB.login(userDocs.fdmanana.name, userDocs.fdmanana.password).ok);
- };
run_on_modified_server(
- [{
- section: "couch_httpd_auth",
- key: "iterations", value: "1"
- }, {
- section: "admins",
- key: "jan", value: "apple"
- }],
+ [{section: "couch_httpd_auth",
+ key: "iterations", value: "1"},
+ {section: "admins",
+ key: "jan", value: "apple"}],
function() {
try {
- testFunUpdatePasswordScheme();
+ testFun();
} finally {
CouchDB.login("jan", "apple");
usersDb.deleteDb(); // cleanup
@@ -540,6 +402,5 @@ couchTests.users_db_security = function(debug) {
}
}
);
-
CouchDB.logout();
};