diff options
author | Paul J. Davis <paul.joseph.davis@gmail.com> | 2019-03-26 16:09:28 -0500 |
---|---|---|
committer | Paul J. Davis <paul.joseph.davis@gmail.com> | 2019-03-26 16:09:28 -0500 |
commit | 628795ab535e05531fd35db29564979284184b2f (patch) | |
tree | 91d335f6eece40ac9818ee96cd19d00aaf11785d | |
parent | f6e64ec5fceb4b4f2abd60ae5c4e9a8451eddd85 (diff) | |
download | couchdb-628795ab535e05531fd35db29564979284184b2f.tar.gz |
Fix compiler errors
-rw-r--r-- | src/fabric/include/fabric.hrl | 4 | ||||
-rw-r--r-- | src/fabric/src/fabric2.erl | 116 | ||||
-rw-r--r-- | src/fabric/src/fabric2.hrl (renamed from src/fabric/include/fabric2.hrl) | 11 | ||||
-rw-r--r-- | src/fabric/src/fabric2_db.erl | 173 | ||||
-rw-r--r-- | src/fabric/src/fabric2_fdb.erl | 34 | ||||
-rw-r--r-- | src/fabric/src/fabric2_security.erl | 142 | ||||
-rw-r--r-- | src/fabric/src/fabric2_server.erl | 8 | ||||
-rw-r--r-- | src/fabric/src/fabric2_util.erl | 38 |
8 files changed, 202 insertions, 324 deletions
diff --git a/src/fabric/include/fabric.hrl b/src/fabric/include/fabric.hrl index 202304a2f..729253882 100644 --- a/src/fabric/include/fabric.hrl +++ b/src/fabric/include/fabric.hrl @@ -13,10 +13,6 @@ -include_lib("eunit/include/eunit.hrl"). --define(uint2bin(I), binary:encode_unsigned(I, little)). --define(bin2uint(I), binary:decode_unsigned(I, little)). - - -record(collector, { db_name=nil, query_args, diff --git a/src/fabric/src/fabric2.erl b/src/fabric/src/fabric2.erl deleted file mode 100644 index 6acf23f48..000000000 --- a/src/fabric/src/fabric2.erl +++ /dev/null @@ -1,116 +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. - --module(fabric2). - - - - - - - - - - -open_doc(Db, DocId, Options) -> - fabric2_db:with_tx(Db, fun(TxDb) -> - case fabric2_doc:get_fdi(TxDb, DocId) of - not_found -> - {not_found, missing}; - #full_doc_info{} = FDI -> - {_, Path} = couch_doc:to_doc_info_path(FDI), - case fabric2_doc:open(TxDb, DocId, Path) of - #doc{} = Doc -> {ok, Doc}; - Error -> Error - end - end - end). - - -open_revs(Db, DocId, Revs, Options) -> - fabric2_db:with_tx(Db, fun(TxDb) -> - case fabrci2_doc:get_fdi(TxDb, DocId) of - not_found -> - {not_found, missing}; - #full_doc_info{} = FDI -> - case fabric2_doc:open_revs(TxDb, FDI, Revs, Options) of - [_ | _] = Opened -> {ok, Opened}; - Error -> Error - end - end - end). - - -update_doc(Db, Doc, Options) -> - fabric2_db:with_tx(Db, fun(TxDb) -> - case fabric2_doc:update(TxDb, Doc, opts(Options)) of - {ok, []} -> - % replication no-op - #doc{revs = {Pos, [RevId | _]}} = doc(Db, Doc), - {ok, {Pos, RevId}}; - {ok, NewRev} -> - {ok, NewRev}; - {error, Error} -> - throw(Error) - end - end). - - -update_docs(DbName, Docs, Options) when is_binary(DbName) -> - update_docs(open_db(DbName, Options), Docs, Options); - -update_docs(Db, Docs, Options) -> - fabric2_db:with_tx(Db, fun(TxDb) -> - {Resps, Status} = lists:mapfoldl(fun(Doc, Acc) -> - case fabric2_doc:update(TxDb, Doc, opts(Options)) of - {ok, _} = Resp -> - {Resp, Acc}; - {error, _} = Resp -> - {Resp, error} - end - end, ok, Docs), - {Status, Resps} - end). - - -docs(Db, Docs) -> - lists:map(fun(Doc) -> doc(Db, Doc) end, Docs). - - -doc(_Db, #doc{} = Doc) -> - Doc; - -doc(Db, {_} = Doc) -> - couch_db:doc_from_json_obj_validate(Db, Doc); - -doc(_Db, Doc) -> - erlang:error({illegal_doc_format, Doc}). - - -opts(Options) -> - lists:foldl(fun(Opt, Acc) -> - add_option(Opt, Acc) - end, Options, [user_ctx, io_priority]). - - -add_option(Key, Options) -> - case couch_util:get_value(Key, Options) of - undefined -> - case erlang:get(Key) of - undefined -> - Options; - Value -> - [{Key, Value} | Options] - end; - _ -> - Options - end. diff --git a/src/fabric/include/fabric2.hrl b/src/fabric/src/fabric2.hrl index e56f84fdc..d63d35064 100644 --- a/src/fabric/include/fabric2.hrl +++ b/src/fabric/src/fabric2.hrl @@ -11,11 +11,6 @@ % the License. --define(SYSTEM_DATABASES, [ - <<"_dbs">>, - <<"_global_changes">>, - <<"_metadata">>, - <<"_nodes">>, - <<"_replicator">>, - <<"_users">> -]). +-define(uint2bin(I), binary:encode_unsigned(I, little)). +-define(bin2uint(I), binary:decode_unsigned(I, little)). + diff --git a/src/fabric/src/fabric2_db.erl b/src/fabric/src/fabric2_db.erl index 5df51dde7..d172209bd 100644 --- a/src/fabric/src/fabric2_db.erl +++ b/src/fabric/src/fabric2_db.erl @@ -18,6 +18,10 @@ open/2, delete/2, + is_admin/1, + check_is_admin/1, + check_is_member/1, + name/1, get_after_doc_read_fun/1, get_before_doc_update_fun/1, @@ -119,6 +123,7 @@ ]). +-include_lib("couch/include/couch_db.hrl"). -include_lib("fabric/include/fabric2.hrl"). @@ -132,13 +137,13 @@ create(DbName, Options) -> - Result = fabric2_util:transactional(DbName, Options, fun(TxDb) -> + Result = transactional(DbName, Options, fun(TxDb) -> case fabric2_fdb:db_exists(TxDb) of true -> {error, file_exists}; false -> fabric2_fdb:db_create(TxDb) - end, + end end), % We cache outside of the transaction so that we're sure % that this request created the database @@ -153,17 +158,17 @@ create(DbName, Options) -> open(DbName, Options) -> case fabric2_server:fetch(DbName) of #{} = Db -> - fabric2_util:transactional(Db, fun(TxDb) -> + with_tx(Db, fun(TxDb) -> case fabric2_fdb:db_is_current(TxDb) of true -> Db; false -> - Reopend = fabric2_fdb:db_open(TxDb), + Reopened = fabric2_fdb:db_open(TxDb), fabric2_server:store(Reopened) end end); undefined -> - fabric2_util:transactional(DbName, Options, fun(TxDb) -> + transactional(DbName, Options, fun(TxDb) -> Opened = fabric2_fdb:db_open(TxDb), fabric2_server:store(Opened) end) @@ -178,6 +183,34 @@ delete(DbName, Options) -> end). +is_admin(Db) -> + % TODO: Need to re-consider couch_db_plugin:check_is_admin/1 + {SecProps} = get_security(Db), + UserCtx = get_user_ctx(Db), + {Admins} = get_admins(SecProps), + is_authorized(Admins, UserCtx). + + +check_is_admin(Db) -> + case is_admin(Db) of + true -> + ok; + false -> + UserCtx = get_user_ctx(Db), + Reason = <<"You are not a db or server admin.">>, + throw_security_error(UserCtx, Reason) + end. + + +check_is_member(Db) -> + case is_member(Db) of + true -> + ok; + false -> + UserCtx = get_user_ctx(Db), + throw_security_error(UserCtx) + end. + name(#{name := DbName}) -> DbName. @@ -190,7 +223,7 @@ get_after_doc_read_fun(#{after_doc_read := AfterDocRead}) -> get_before_doc_update_fun(#{before_doc_update := BeforeDocUpdate}) -> BeforeDocUpdate. -get_commited_update_seq(#{} = Db) -> +get_committed_update_seq(#{} = Db) -> get_update_seq(Db). @@ -198,7 +231,7 @@ get_compacted_seq(#{} = Db) -> get_update_seq(Db). -get_compactor_pid(#{} = Db) -> +get_compactor_pid(#{} = _Db) -> nil. @@ -211,7 +244,7 @@ get_db_info(#{} = Db) -> {cluster, {[{n, 0}, {q, 0}, {r, 0}, {w, 0}]}}, {compact_running, false}, {data_size, 0}, - {db_name, DbName}, + {db_name, name(Db)}, {disk_format_version, 0}, {disk_size, 0}, {instance_start_time, <<"0">>}, @@ -246,7 +279,7 @@ get_doc_count(Db, Key) -> end). -get_instance_startime(#{}) -> +get_instance_start_time(#{}) -> 0. @@ -271,6 +304,10 @@ get_update_seq(#{} = Db) -> end. +get_user_ctx(#{user_ctx := UserCtx}) -> + UserCtx. + + get_uuid(#{uuid := UUID}) -> UUID. @@ -336,7 +373,7 @@ open_doc(#{} = Db, DocId) -> open_doc(Db, DocId, []). -open_doc(#{} = Db, DocId, Options) -> +open_doc(#{} = Db, DocId, _Options) -> with_tx(Db, fun(TxDb) -> case fabric2_fdb:get_full_doc_info(TxDb, DocId) of not_found -> @@ -372,7 +409,7 @@ open_doc_revs(Db, FDI, Revs, Options) -> % We have the rev in our list but know nothing about it {{not_found, missing}, {Pos, Rev}}; _ -> - case fabric2_fdb:get_doc_body(Db, Id, RevPath) of + case fabric2_fdb:get_doc_body(TxDb, Id, RevPath) of #doc{} = Doc -> {ok, Doc}; Else -> {Else, {Pos, Rev}} end @@ -400,7 +437,7 @@ update_docs(Db, Docs) -> update_docs(Db, Docs, Options) -> with_tx(Db, fun(TxDb) -> {Resps, Status} = lists:mapfoldl(fun(Doc, Acc) -> - case fabric2_doc:update(TxDb, Doc, opts(Options)) of + case fabric2_doc:update(TxDb, Doc, Options) of {ok, _} = Resp -> {Resp, Acc}; {error, _} = Resp -> @@ -440,6 +477,92 @@ new_revid(Doc) -> Doc#doc{revs = {OldStart + 1, [Rev | OldRevs]}}. +is_member(Db) -> + {SecProps} = get_security(Db), + case is_admin(Db) of + true -> + true; + false -> + case is_public_db(SecProps) of + true -> + true; + false -> + {Members} = get_members(SecProps), + UserCtx = get_user_ctx(Db), + is_authorized(Members, UserCtx) + end + end. + + +is_authorized(Group, UserCtx) -> + #user_ctx{ + name = UserName, + roles = UserRoles + } = UserCtx, + Names = fabric2_util:get_value(<<"names">>, Group, []), + Roles = fabric2_util:get_value(<<"roles">>, Group, []), + case check_security(roles, UserRoles, [<<"_admin">> | Roles]) of + true -> + true; + false -> + check_security(names, UserName, Names) + end. + + +check_security(roles, [], _) -> + false; +check_security(roles, UserRoles, Roles) -> + UserRolesSet = ordsets:from_list(UserRoles), + RolesSet = ordsets:from_list(Roles), + not ordsets:is_disjoint(UserRolesSet, RolesSet); +check_security(names, _, []) -> + false; +check_security(names, null, _) -> + false; +check_security(names, UserName, Names) -> + lists:member(UserName, Names). + + +throw_security_error(#user_ctx{name = null} = UserCtx) -> + Reason = <<"You are not authorized to access this db.">>, + throw_security_error(UserCtx, Reason); +throw_security_error(#user_ctx{name = _} = UserCtx) -> + Reason = <<"You are not allowed to access this db.">>, + throw_security_error(UserCtx, Reason). + + +throw_security_error(#user_ctx{} = UserCtx, Reason) -> + Error = security_error_type(UserCtx), + throw({Error, Reason}). + + +security_error_type(#user_ctx{name = null}) -> + unauthorized; +security_error_type(#user_ctx{name = _}) -> + forbidden. + + +is_public_db(SecProps) -> + {Members} = get_members(SecProps), + Names = fabric2_util:get_value(<<"names">>, Members, []), + Roles = fabric2_util:get_value(<<"roles">>, Members, []), + Names =:= [] andalso Roles =:= []. + + +get_admins(SecProps) -> + fabric2_util:get_value(<<"admins">>, SecProps, {[]}). + + +get_members(SecProps) -> + % we fallback to readers here for backwards compatibility + case fabric2_util:get_value(<<"members">>, SecProps) of + undefined -> + fabric2_util:get_value(<<"readers">>, SecProps, {[]}); + Members -> + Members + end. + + % TODO: Handle _local docs separately. update_doc_int(#{} = Db, #doc{} = Doc0, Options) -> UpdateType = case lists:member(replicated_changes, Options) of @@ -449,7 +572,7 @@ update_doc_int(#{} = Db, #doc{} = Doc0, Options) -> try FDI1 = fabric2_fdb:get_full_doc_info(Db, Doc0#doc.id), - Doc1 = prep_and_validate(TxDb, FDI1, Doc0, UpdateType), + Doc1 = prep_and_validate(Db, FDI1, Doc0, UpdateType), Doc2 = case UpdateType of interactive_edit -> new_revid(Doc1); replicated_changes -> Doc1 @@ -466,7 +589,7 @@ update_doc_int(#{} = Db, #doc{} = Doc0, Options) -> end, NewExists = not FDI3#full_doc_info.deleted, - ok = fabric2_fdb:write_doc(Db, FDI3, Doc3) + ok = fabric2_fdb:write_doc(Db, FDI3, Doc3), case {OldExists, NewExists} of {false, true} -> @@ -482,6 +605,9 @@ update_doc_int(#{} = Db, #doc{} = Doc0, Options) -> % Need to count design documents % Need to track db size changes + #doc{ + revs = {RevStart, [Rev | _]} + } = Doc3, {ok, {RevStart, Rev}} catch throw:{?MODULE, Return} -> Return @@ -526,9 +652,9 @@ prep_and_validate(Db, FDI, Doc, interactive_edit) -> ?RETURN({error, conflict}) end end, - prep_and_validate(TxDb, Doc, GetDocFun); + prep_and_validate(Db, Doc, GetDocFun); -prep_and_validate(TxDb, FDI, Doc, replicated_changes) -> +prep_and_validate(Db, FDI, Doc, replicated_changes) -> #full_doc_info{ rev_tree = RevTree } = FDI, @@ -570,7 +696,7 @@ prep_and_validate(TxDb, FDI, Doc, replicated_changes) -> ?RETURN({ok, []}) end, - prep_and_validate(TxDb, Doc, GetDocFun). + prep_and_validate(Db, Doc, GetDocFun). prep_and_validate(Db, Doc, GetDocBody) -> @@ -606,7 +732,7 @@ merge_rev_tree(FDI, Doc, interactive_edit) when FDI#full_doc_info.deleted -> % Update the new doc based on revisions in OldInfo #doc_info{revs=[WinningRev | _]} = couch_doc:to_doc_info(FDI), #rev_info{rev={OldPos, OldRev}} = WinningRev, - Body = case couch_util:get_value(comp_body, Doc#doc.meta) of + Body = case fabric2_util:get_value(comp_body, Doc#doc.meta) of CompBody when is_binary(CompBody) -> couch_compress:decompress(CompBody); _ -> @@ -676,9 +802,6 @@ merge_rev_tree(FDI, Doc, replicated_changes) -> validate_doc_update(Db, #doc{id = <<"_design/", _/binary>>} = Doc, _) -> - #{ - security_doc := Security - } = Db, case catch check_is_admin(Db) of ok -> validate_ddoc(Db, Doc); Error -> ?RETURN(Error) @@ -693,7 +816,7 @@ validate_doc_update(Db, Doc, GetDiskDocFun) -> } = Db, Fun = fun() -> DiskDoc = GetDiskDocFun(), - JsonCtx = fabric2_util:user_ctx_to_json(TxDb), + JsonCtx = fabric2_util:user_ctx_to_json(UserCtx), try lists:map(fun(VDU) -> case VDU(Doc, DiskDoc, JsonCtx, Security) of @@ -742,6 +865,12 @@ find_prev_known_rev(Pos, [{_Rev, #leaf{}} | _] = DocPath) -> {Pos, [Rev || {Rev, _Val} <- DocPath]}. +transactional(DbName, Options, Fun) -> + fabric2_util:transactional(fun(Tx) -> + Fun(fabric2_fdb:init(Tx, DbName, Options)) + end). + + with_tx(#{tx := undefined} = Db, Fun) -> fabric2_util:transactional(fun(Tx) -> Fun(Db#{tx => Tx}) diff --git a/src/fabric/src/fabric2_fdb.erl b/src/fabric/src/fabric2_fdb.erl index 4764331ae..e5bd81a63 100644 --- a/src/fabric/src/fabric2_fdb.erl +++ b/src/fabric/src/fabric2_fdb.erl @@ -38,6 +38,10 @@ ]). +-include("couch/include/couch_db.hrl"). +-include("fabric2.hrl"). + + % This will eventually be the `\xFFmetadataVersion` key that is % currently only available in FoundationDB master. % @@ -55,18 +59,20 @@ -define(CLUSTER_CONFIG, 0). -define(ALL_DBS, 1). -define(DBS, 15). + -define(DB_CONFIG, 16). -define(DB_STATS, 17). -define(DB_ALL_DOCS, 18). -define(DB_CHANGES, 19). --define(DB_DOCS, 20). --define(DB_REVS, 21). +-define(DB_REVS, 20). +-define(DB_DOCS, 21). +-define(DB_LOCAL_DOCS, 22). % Various utility macros -define(REQUIRE_TX(Db), {erlfdb_transaction, _} = maps:get(Db, tx)). --define(REQUIRE_CURRENT(Db), true = db_is_current(Db)). +-define(REQUIRE_CURRENT(Db), true = is_current(Db)). -define(UNSET_VS, {versionstamp, 16#FFFFFFFFFFFFFFFF, 16#FFFF}). @@ -95,7 +101,7 @@ create(#{} = Db) -> % we're just using the DbName so that debugging is easier. DbKey = erlfdb_tuple:pack({?ALL_DBS, DbName}, LayerPrefix), DbPrefix = erlfdb_tuple:pack({?DBS, DbName}, LayerPrefix), - ets:set(Tx, DbKey, DbPrefix), + erlfdb:set(Tx, DbKey, DbPrefix), UUID = fabric2_util:uuid(), @@ -121,7 +127,7 @@ create(#{} = Db) -> db_prefix => DbPrefix, version => Version, revs_limit => 1000, - security_doc => {[]} + security_doc => {[]}, validate_doc_update_funs => [], user_ctx => #user_ctx{}, @@ -161,7 +167,6 @@ open(#{} = Db0) -> after_doc_read => undefined }, - Config = db_get_config(Db1), lists:foldl(fun({Key, Val}) -> case Key of <<"uuid">> -> @@ -171,7 +176,7 @@ open(#{} = Db0) -> <<"security_doc">> -> Db1#{security_doc => ?JSON_DECODE(Val)} end - end, Db1, db_get_config(Db1)). + end, Db1, get_config(Db1)). delete(#{} = Db) -> @@ -186,7 +191,7 @@ delete(#{} = Db) -> DbKey = erlfdb_tuple:pack({?DBS, DbName}, LayerPrefix), erlfdb:clear(Tx, DbKey), erlfdb:clear_range_startswith(Tx, DbPrefix), - bump_metadata_version(), + bump_metadata_version(Db), ok. @@ -207,7 +212,7 @@ exists(#{name := DbName} = Db) when is_binary(DbName) -> is_current(#{} = Db) -> ?REQUIRE_TX(Db), #{ - name := DbName, + tx := Tx, md_version := MetaDataVersion } = Db, @@ -220,7 +225,6 @@ is_current(#{} = Db) -> get_info(#{} = Db) -> ?REQUIRE_CURRENT(Db), #{ - name := DbName, tx := Tx, db_prefix := DbPrefix } = Db, @@ -361,10 +365,6 @@ store_doc(#{} = Db, #full_doc_info{} = FDI, #doc{} = Doc) -> update_seq = OldUpdateSeq } = FDI, - #doc{ - revs = {RevStart, [Rev | _]} - } = Doc, - % Delete old entry in changes feed OldSeqKey = erlfdb_tuple:pack({?DB_CHANGES, OldUpdateSeq}, DbPrefix), erlfdb:clear(Tx, OldSeqKey), @@ -378,7 +378,7 @@ store_doc(#{} = Db, #full_doc_info{} = FDI, #doc{} = Doc) -> erlfdb:set(Tx, NewDocKey, NewDocVal), % Update revision tree entry - {NewFDIKey, NewFDIVal} = fdi_to_fdb(TxDb, FDI), + {NewFDIKey, NewFDIVal} = fdi_to_fdb(Db, FDI), erlfdb:set_versionstamped_value(Tx, NewFDIKey, NewFDIVal). @@ -453,7 +453,7 @@ fdi_to_fdb(Db, #full_doc_info{} = FDI) -> ValTuple = { Deleted, RevTreeBin, - {versionstamp, 16#FFFFFFFFFFFFFFFF, 16#FFFF} + ?UNSET_VS }, Val = erlfdb_tuple:pack_vs(ValTuple), {Key, Val}. @@ -487,4 +487,4 @@ fdb_to_fdi(_Db, Id, Bin) when is_binary(Bin) -> update_seq = UpdateSeq }; fdb_to_fdi(_Db, _Id, not_found) -> - not_found.
\ No newline at end of file + not_found. diff --git a/src/fabric/src/fabric2_security.erl b/src/fabric/src/fabric2_security.erl deleted file mode 100644 index b3f13886d..000000000 --- a/src/fabric/src/fabric2_security.erl +++ /dev/null @@ -1,142 +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. - --module(fabric_security). - - --export([ - check_is_admin/2, - check_is_member/2, - - is_admin/2, - is_member/2 -]). - - --include_lib("couch/include/couch_db.hrl"). - - -check_is_admin(DbName, UserCtx) -> - case is_admin(DbName, UserCtx) of - true -> - ok; - false -> - Reason = <<"You are not a db or server admin.">>, - throw_security_error(UserCtx, Reason) - end. - - -check_is_member(DbName, UserCtx) -> - case is_member(DbName, UserCtx) of - true -> - ok; - false -> - throw_security_error(UserCtx) - end. - - -is_admin(DbName, UserCtx) when is_binary(DbName) -> - {SecProps} = fabric2:get_security(DbName), - is_admin(SecProps, UserCtx); - -is_admin(SecProps, UserCtx) -> - % Need to re-consider couch_db_plugin:check_is_admin/1 - {Admins} = get_admins(SecProps), - is_authorized(Admins, UserCtx). - - -is_member(DbName, UserCtx) when is_binary(DbName) -> - {SecProps} = fabric2:get_security(DbName), - is_member(SecProps, UserCtx); - -is_member(SecProps, UserCtx) -> - case is_admin(SecProps, UserCtx) of - true -> - true; - false -> - case is_public_db(SecProps) of - true -> - true; - false -> - {Members} = get_members(SecProps), - is_authorized(Members, UserCtx) - end - end. - - -is_authorized(Group, UserCtx) -> - #user_ctx{ - name = UserName, - roles = UserRoles - } = UserCtx, - Names = couch_util:get_value(<<"names">>, Group, []), - Roles = couch_util:get_value(<<"roles">>, Group, []), - case check_security(roles, UserRoles, [<<"_admin">> | Roles]) of - true -> - true; - false -> - check_security(names, UserName, Names) - end. - - -check_security(roles, [], _) -> - false; -check_security(roles, UserRoles, Roles) -> - UserRolesSet = ordsets:from_list(UserRoles), - RolesSet = ordsets:from_list(Roles), - not ordsets:is_disjoint(UserRolesSet, RolesSet); -check_security(names, _, []) -> - false; -check_security(names, null, _) -> - false; -check_security(names, UserName, Names) -> - lists:member(UserName, Names). - - -throw_security_error(#user_ctx{name=null}=UserCtx) -> - Reason = <<"You are not authorized to access this db.">>, - throw_security_error(UserCtx, Reason); -throw_security_error(#user_ctx{name=_}=UserCtx) -> - Reason = <<"You are not allowed to access this db.">>, - throw_security_error(UserCtx, Reason). - - -throw_security_error(#user_ctx{}=UserCtx, Reason) -> - Error = security_error_type(UserCtx), - throw({Error, Reason}). - - -security_error_type(#user_ctx{name=null}) -> - unauthorized; -security_error_type(#user_ctx{name=_}) -> - forbidden. - - -is_public_db(SecProps) -> - {Members} = get_members(SecProps), - Names = couch_util:get_value(<<"names">>, Members, []), - Roles = couch_util:get_value(<<"roles">>, Members, []), - Names =:= [] andalso Roles =:= []. - - -get_admins(SecProps) -> - couch_util:get_value(<<"admins">>, SecProps, {[]}). - - -get_members(SecProps) -> - % we fallback to readers here for backwards compatibility - case couch_util:get_value(<<"members">>, SecProps) of - undefined -> - couch_util:get_value(<<"readers">>, SecProps, {[]}); - Members -> - Members - end. diff --git a/src/fabric/src/fabric2_server.erl b/src/fabric/src/fabric2_server.erl index 58223315a..9a0e4fac2 100644 --- a/src/fabric/src/fabric2_server.erl +++ b/src/fabric/src/fabric2_server.erl @@ -32,6 +32,9 @@ ]). +-include_lib("couch/include/couch_db.hrl"). + + -define(CLUSTER_FILE, "/usr/local/etc/foundationdb/fdb.cluster"). @@ -41,7 +44,7 @@ start_link() -> fetch(DbName) when is_binary(DbName) -> case ets:lookup(?MODULE, DbName) of - [{DbName, #{} = Db] -> Db; + [{DbName, #{} = Db}] -> Db; [] -> undefined end. @@ -51,7 +54,7 @@ store(#{name := DbName} = Db0) when is_binary(DbName) -> tx => undefined, user_ctx => #user_ctx{} }, - true = ets:insert(?MODULE, {DbName, Db1}}), + true = ets:insert(?MODULE, {DbName, Db1}), Db1. @@ -66,7 +69,6 @@ init(_) -> ClusterStr = config:get("erlfdb", "cluster_file", ?CLUSTER_FILE), Db = erlfdb:open(iolist_to_binary(ClusterStr)), application:set_env(fabric, db, Db), - init_cluster(Db), {ok, nil}. diff --git a/src/fabric/src/fabric2_util.erl b/src/fabric/src/fabric2_util.erl index 1c47222f6..230a5841b 100644 --- a/src/fabric/src/fabric2_util.erl +++ b/src/fabric/src/fabric2_util.erl @@ -14,26 +14,28 @@ -export([ - transactional/2, - transactional/3, - + transactional/1, get_db_handle/0, user_ctx_to_json/1, - uuid/0, - + get_value/2, + get_value/3, to_hex/1, + uuid/0, debug_cluster/0, debug_cluster/2 ]). +-include_lib("couch/include/couch_db.hrl"). + + -define(PDICT_DB_KEY, '$erlfdb_handle'). -trasactional(Fun) when is_function(Fun, 1) -> +transactional(Fun) when is_function(Fun, 1) -> Db = get_db_handle(), erlfdb:transactional(Db, Fun). @@ -53,14 +55,22 @@ user_ctx_to_json(Db) -> UserCtx = fabric2_db:get_user_ctx(Db), {[ {<<"db">>, fabric2_db:name(Db)}, - {<<"name">>, Ctx#user_ctx.name}, - {<<"roles">>, Ctx#user_ctx.roles} + {<<"name">>, UserCtx#user_ctx.name}, + {<<"roles">>, UserCtx#user_ctx.roles} ]}. +get_value(Key, List) -> + get_value(Key, List, undefined). -uuid() -> - to_hex(crypto:strong_rand_bytes(16)). + +get_value(Key, List, Default) -> + case lists:keysearch(Key, 1, List) of + {value, {Key,Value}} -> + Value; + false -> + Default + end. to_hex(Bin) -> @@ -70,7 +80,7 @@ to_hex(Bin) -> to_hex_int(<<>>) -> []; to_hex_int(<<Hi:4, Lo:4, Rest/binary>>) -> - [nibble_to_hex(Hi), nibble_to_hex(Lo) | to_hex(Rest)]; + [nibble_to_hex(Hi), nibble_to_hex(Lo) | to_hex(Rest)]. nibble_to_hex(I) -> @@ -94,6 +104,10 @@ nibble_to_hex(I) -> end. +uuid() -> + to_hex(crypto:strong_rand_bytes(16)). + + debug_cluster() -> debug_cluster(<<>>, <<16#FE, 16#FF, 16#FF>>). @@ -106,4 +120,4 @@ debug_cluster(Start, End) -> erlfdb_util:repr(Val) ]) end, erlfdb:get_range(Tx, Start, End)) - end).
\ No newline at end of file + end). |