mirror of
https://github.com/processone/ejabberd.git
synced 2024-12-22 17:28:25 +01:00
Improve validation of second-level options
This commit is contained in:
parent
fb17c1b99f
commit
b174e2c9c6
@ -441,7 +441,7 @@ get_opt_host(Host, Opts, Default) ->
|
||||
Val = get_opt(host, Opts, Default),
|
||||
ejabberd_regexp:greplace(Val, <<"@HOST@">>, Host).
|
||||
|
||||
-spec get_validators(binary(), module(), opts()) -> {ok, [{atom(), check_fun()}]} | undef.
|
||||
-spec get_validators(binary(), module(), opts()) -> dict:dict() | undef.
|
||||
get_validators(Host, Module, Opts) ->
|
||||
try Module:mod_opt_type('') of
|
||||
L ->
|
||||
@ -453,23 +453,29 @@ get_validators(Host, Module, Opts) ->
|
||||
true -> [ram_db_mod(Host, Opts, Module)];
|
||||
false -> []
|
||||
end,
|
||||
{ok, dict:to_list(
|
||||
lists:foldl(
|
||||
fun(Mod, D) ->
|
||||
try Mod:mod_opt_type('') of
|
||||
Os ->
|
||||
lists:foldl(
|
||||
fun({Opt, SubOpt} = O, Acc) ->
|
||||
F = Mod:mod_opt_type(O),
|
||||
dict:append(Opt, {SubOpt, F}, Acc);
|
||||
(O, Acc) ->
|
||||
F = Mod:mod_opt_type(O),
|
||||
dict:store(O, F, Acc)
|
||||
end, D, Os)
|
||||
catch _:undef ->
|
||||
D
|
||||
end
|
||||
end, dict:new(), [Module|SubMods1 ++ SubMods2]))}
|
||||
lists:foldl(
|
||||
fun(Mod, D) ->
|
||||
try Mod:mod_opt_type('') of
|
||||
Os ->
|
||||
lists:foldl(
|
||||
fun({Opt, SubOpt} = O, Acc) ->
|
||||
SubF = Mod:mod_opt_type(O),
|
||||
F = case Mod:mod_opt_type(Opt) of
|
||||
F1 when is_function(F1) ->
|
||||
F1;
|
||||
_ ->
|
||||
fun(X) -> X end
|
||||
end,
|
||||
dict:append_list(
|
||||
Opt, [F, {SubOpt, [SubF]}], Acc);
|
||||
(O, Acc) ->
|
||||
F = Mod:mod_opt_type(O),
|
||||
dict:store(O, [F], Acc)
|
||||
end, D, Os)
|
||||
catch _:undef ->
|
||||
D
|
||||
end
|
||||
end, dict:new(), [Module|SubMods1 ++ SubMods2])
|
||||
catch _:undef ->
|
||||
?WARNING_MSG("module '~s' doesn't export mod_opt_type/1",
|
||||
[Module]),
|
||||
@ -479,26 +485,30 @@ get_validators(Host, Module, Opts) ->
|
||||
-spec validate_opts(binary(), module(), opts()) -> opts().
|
||||
validate_opts(Host, Module, Opts) ->
|
||||
case get_validators(Host, Module, Opts) of
|
||||
{ok, Validators} ->
|
||||
validate_opts(Host, Module, Opts, Validators);
|
||||
undef ->
|
||||
Opts
|
||||
Opts;
|
||||
Validators ->
|
||||
validate_opts(Host, Module, Opts, dict:to_list(Validators))
|
||||
end.
|
||||
|
||||
validate_opts(Host, Module, Opts, Validators) when is_list(Opts) ->
|
||||
lists:flatmap(
|
||||
fun({Opt, Val}) when is_atom(Opt) ->
|
||||
case lists:keyfind(Opt, 1, Validators) of
|
||||
{_, VFun} when is_function(VFun) ->
|
||||
validate_opt(Module, Opt, Val, VFun);
|
||||
{_, SubValidators} ->
|
||||
try validate_opts(Host, Module, Val, SubValidators) of
|
||||
SubOpts -> [{Opt, SubOpts}]
|
||||
catch _:bad_option ->
|
||||
?ERROR_MSG("ignoring invalid value '~p' for "
|
||||
"option '~s' of module '~s'",
|
||||
[Val, Opt, Module]),
|
||||
[]
|
||||
{_, L} ->
|
||||
case lists:partition(fun is_function/1, L) of
|
||||
{[VFun|_], []} ->
|
||||
validate_opt(Module, Opt, Val, VFun);
|
||||
{[VFun|_], SubValidators} ->
|
||||
try validate_opts(Host, Module, Val, SubValidators) of
|
||||
SubOpts ->
|
||||
validate_opt(Module, Opt, SubOpts, VFun)
|
||||
catch _:bad_option ->
|
||||
?ERROR_MSG("ignoring invalid value '~p' for "
|
||||
"option '~s' of module '~s'",
|
||||
[Val, Opt, Module]),
|
||||
[]
|
||||
end
|
||||
end;
|
||||
false ->
|
||||
?ERROR_MSG("unknown option '~s' for module '~s' will be"
|
||||
|
136
src/mod_muc.erl
136
src/mod_muc.erl
@ -337,59 +337,9 @@ init_state(Host, Opts) ->
|
||||
AccessPersistent = gen_mod:get_opt(access_persistent, Opts, all),
|
||||
HistorySize = gen_mod:get_opt(history_size, Opts, 20),
|
||||
MaxRoomsDiscoItems = gen_mod:get_opt(max_rooms_discoitems, Opts, 100),
|
||||
DefRoomOpts1 = gen_mod:get_opt(default_room_options, Opts, []),
|
||||
DefRoomOpts = gen_mod:get_opt(default_room_options, Opts, []),
|
||||
QueueType = gen_mod:get_opt(queue_type, Opts,
|
||||
ejabberd_config:default_queue_type(Host)),
|
||||
DefRoomOpts =
|
||||
lists:flatmap(
|
||||
fun({Opt, Val}) ->
|
||||
Bool = fun(B) when is_boolean(B) -> B end,
|
||||
VFun = case Opt of
|
||||
allow_change_subj -> Bool;
|
||||
allow_private_messages -> Bool;
|
||||
allow_query_users -> Bool;
|
||||
allow_user_invites -> Bool;
|
||||
allow_visitor_nickchange -> Bool;
|
||||
allow_visitor_status -> Bool;
|
||||
anonymous -> Bool;
|
||||
captcha_protected -> Bool;
|
||||
logging -> Bool;
|
||||
members_by_default -> Bool;
|
||||
members_only -> Bool;
|
||||
moderated -> Bool;
|
||||
password_protected -> Bool;
|
||||
persistent -> Bool;
|
||||
public -> Bool;
|
||||
public_list -> Bool;
|
||||
mam -> Bool;
|
||||
allow_subscription -> Bool;
|
||||
password -> fun iolist_to_binary/1;
|
||||
title -> fun iolist_to_binary/1;
|
||||
allow_private_messages_from_visitors ->
|
||||
fun(anyone) -> anyone;
|
||||
(moderators) -> moderators;
|
||||
(nobody) -> nobody
|
||||
end;
|
||||
max_users ->
|
||||
fun(I) when is_integer(I), I > 0 -> I end;
|
||||
presence_broadcast ->
|
||||
fun(L) ->
|
||||
lists:map(
|
||||
fun(moderator) -> moderator;
|
||||
(participant) -> participant;
|
||||
(visitor) -> visitor
|
||||
end, L)
|
||||
end;
|
||||
_ ->
|
||||
?ERROR_MSG("unknown option ~p with value ~p",
|
||||
[Opt, Val]),
|
||||
fun(_) -> undefined end
|
||||
end,
|
||||
case ejabberd_config:prepare_opt_val(Opt, Val, VFun, undefined) of
|
||||
undefined -> [];
|
||||
NewVal -> [{Opt, NewVal}]
|
||||
end
|
||||
end, DefRoomOpts1),
|
||||
RoomShaper = gen_mod:get_opt(room_shaper, Opts, none),
|
||||
#state{host = MyHost,
|
||||
server_host = Host,
|
||||
@ -897,8 +847,6 @@ mod_opt_type(access_persistent) ->
|
||||
fun acl:access_rules_validator/1;
|
||||
mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end;
|
||||
mod_opt_type(ram_db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end;
|
||||
mod_opt_type(default_room_options) ->
|
||||
fun (L) when is_list(L) -> L end;
|
||||
mod_opt_type(history_size) ->
|
||||
fun (I) when is_integer(I), I >= 0 -> I end;
|
||||
mod_opt_type(host) -> fun iolist_to_binary/1;
|
||||
@ -938,11 +886,89 @@ mod_opt_type(user_presence_shaper) ->
|
||||
fun (A) when is_atom(A) -> A end;
|
||||
mod_opt_type(queue_type) ->
|
||||
fun(ram) -> ram; (file) -> file end;
|
||||
mod_opt_type({default_room_options, allow_change_subj}) ->
|
||||
fun(B) when is_boolean(B) -> B end;
|
||||
mod_opt_type({default_room_options, allow_private_messages}) ->
|
||||
fun(B) when is_boolean(B) -> B end;
|
||||
mod_opt_type({default_room_options, allow_query_users}) ->
|
||||
fun(B) when is_boolean(B) -> B end;
|
||||
mod_opt_type({default_room_options, allow_user_invites}) ->
|
||||
fun(B) when is_boolean(B) -> B end;
|
||||
mod_opt_type({default_room_options, allow_visitor_nickchange}) ->
|
||||
fun(B) when is_boolean(B) -> B end;
|
||||
mod_opt_type({default_room_options, allow_visitor_status}) ->
|
||||
fun(B) when is_boolean(B) -> B end;
|
||||
mod_opt_type({default_room_options, anonymous}) ->
|
||||
fun(B) when is_boolean(B) -> B end;
|
||||
mod_opt_type({default_room_options, captcha_protected}) ->
|
||||
fun(B) when is_boolean(B) -> B end;
|
||||
mod_opt_type({default_room_options, logging}) ->
|
||||
fun(B) when is_boolean(B) -> B end;
|
||||
mod_opt_type({default_room_options, members_by_default}) ->
|
||||
fun(B) when is_boolean(B) -> B end;
|
||||
mod_opt_type({default_room_options, members_only}) ->
|
||||
fun(B) when is_boolean(B) -> B end;
|
||||
mod_opt_type({default_room_options, moderated}) ->
|
||||
fun(B) when is_boolean(B) -> B end;
|
||||
mod_opt_type({default_room_options, password_protected}) ->
|
||||
fun(B) when is_boolean(B) -> B end;
|
||||
mod_opt_type({default_room_options, persistent}) ->
|
||||
fun(B) when is_boolean(B) -> B end;
|
||||
mod_opt_type({default_room_options, public}) ->
|
||||
fun(B) when is_boolean(B) -> B end;
|
||||
mod_opt_type({default_room_options, public_list}) ->
|
||||
fun(B) when is_boolean(B) -> B end;
|
||||
mod_opt_type({default_room_options, mam}) ->
|
||||
fun(B) when is_boolean(B) -> B end;
|
||||
mod_opt_type({default_room_options, allow_subscription}) ->
|
||||
fun(B) when is_boolean(B) -> B end;
|
||||
mod_opt_type({default_room_options, password}) ->
|
||||
fun iolist_to_binary/1;
|
||||
mod_opt_type({default_room_options, title}) ->
|
||||
fun iolist_to_binary/1;
|
||||
mod_opt_type({default_room_options, allow_private_messages_from_visitors}) ->
|
||||
fun(anyone) -> anyone;
|
||||
(moderators) -> moderators;
|
||||
(nobody) -> nobody
|
||||
end;
|
||||
mod_opt_type({default_room_options, max_users}) ->
|
||||
fun(I) when is_integer(I), I > 0 -> I end;
|
||||
mod_opt_type({default_room_options, presence_broadcast}) ->
|
||||
fun(L) ->
|
||||
lists:map(
|
||||
fun(moderator) -> moderator;
|
||||
(participant) -> participant;
|
||||
(visitor) -> visitor
|
||||
end, L)
|
||||
end;
|
||||
mod_opt_type(_) ->
|
||||
[access, access_admin, access_create, access_persistent,
|
||||
db_type, ram_db_type, default_room_options, history_size, host,
|
||||
db_type, ram_db_type, history_size, host,
|
||||
max_room_desc, max_room_id, max_room_name,
|
||||
max_rooms_discoitems, max_user_conferences, max_users,
|
||||
max_users_admin_threshold, max_users_presence,
|
||||
min_message_interval, min_presence_interval, queue_type,
|
||||
regexp_room_id, room_shaper, user_message_shaper, user_presence_shaper].
|
||||
regexp_room_id, room_shaper, user_message_shaper, user_presence_shaper,
|
||||
{default_room_options, allow_change_subj},
|
||||
{default_room_options, allow_private_messages},
|
||||
{default_room_options, allow_query_users},
|
||||
{default_room_options, allow_user_invites},
|
||||
{default_room_options, allow_visitor_nickchange},
|
||||
{default_room_options, allow_visitor_status},
|
||||
{default_room_options, anonymous},
|
||||
{default_room_options, captcha_protected},
|
||||
{default_room_options, logging},
|
||||
{default_room_options, members_by_default},
|
||||
{default_room_options, members_only},
|
||||
{default_room_options, moderated},
|
||||
{default_room_options, password_protected},
|
||||
{default_room_options, persistent},
|
||||
{default_room_options, public},
|
||||
{default_room_options, public_list},
|
||||
{default_room_options, mam},
|
||||
{default_room_options, allow_subscription},
|
||||
{default_room_options, password},
|
||||
{default_room_options, title},
|
||||
{default_room_options, allow_private_messages_from_visitors},
|
||||
{default_room_options, max_users},
|
||||
{default_room_options, presence_broadcast}].
|
||||
|
@ -1185,11 +1185,13 @@ mod_opt_type(file_format) ->
|
||||
end;
|
||||
mod_opt_type(file_permissions) ->
|
||||
fun (SubOpts) ->
|
||||
F = fun ({mode, Mode}, {_M, G}) -> {Mode, G};
|
||||
({group, Group}, {M, _G}) -> {M, Group}
|
||||
end,
|
||||
lists:foldl(F, {644, 33}, SubOpts)
|
||||
{proplists:get_value(mode, SubOpts, 644),
|
||||
proplists:get_value(group, SubOpts, 33)}
|
||||
end;
|
||||
mod_opt_type({file_permissions, mode}) ->
|
||||
fun(I) when is_integer(I), I>=0 -> I end;
|
||||
mod_opt_type({file_permissions, group}) ->
|
||||
fun(I) when is_integer(I), I>=0 -> I end;
|
||||
mod_opt_type(outdir) -> fun iolist_to_binary/1;
|
||||
mod_opt_type(spam_prevention) ->
|
||||
fun (B) when is_boolean(B) -> B end;
|
||||
@ -1203,5 +1205,5 @@ mod_opt_type(top_link) ->
|
||||
end;
|
||||
mod_opt_type(_) ->
|
||||
[access_log, cssfile, dirname, dirtype, file_format,
|
||||
file_permissions, outdir, spam_prevention, timezone,
|
||||
top_link].
|
||||
{file_permissions, mode}, {file_permissions, group},
|
||||
outdir, spam_prevention, timezone, top_link].
|
||||
|
@ -58,31 +58,12 @@ stop(Host) ->
|
||||
reload(_Host, _NewOpts, _OldOpts) ->
|
||||
ok.
|
||||
|
||||
mod_opt_type(roster) ->
|
||||
fun(Props) ->
|
||||
lists:map(
|
||||
fun({both, ACL}) -> {both, acl:access_rules_validator(ACL)};
|
||||
({get, ACL}) -> {get, acl:access_rules_validator(ACL)};
|
||||
({set, ACL}) -> {set, acl:access_rules_validator(ACL)}
|
||||
end, Props)
|
||||
end;
|
||||
mod_opt_type(message) ->
|
||||
fun(Props) ->
|
||||
lists:map(
|
||||
fun({outgoing, ACL}) -> {outgoing, acl:access_rules_validator(ACL)}
|
||||
end, Props)
|
||||
end;
|
||||
mod_opt_type(presence) ->
|
||||
fun(Props) ->
|
||||
lists:map(
|
||||
fun({managed_entity, ACL}) ->
|
||||
{managed_entity, acl:access_rules_validator(ACL)};
|
||||
({roster, ACL}) ->
|
||||
{roster, acl:access_rules_validator(ACL)}
|
||||
end, Props)
|
||||
end;
|
||||
mod_opt_type({roster, _}) -> fun acl:access_rules_validator/1;
|
||||
mod_opt_type({message, _}) -> fun acl:access_rules_validator/1;
|
||||
mod_opt_type({presence, _}) -> fun acl:access_rules_validator/1;
|
||||
mod_opt_type(_) ->
|
||||
[roster, message, presence].
|
||||
[{roster, both}, {roster, get}, {roster, set},
|
||||
{message, outgoing}, {presence, managed_entity}, {presence, roster}].
|
||||
|
||||
depends(_, _) ->
|
||||
[].
|
||||
|
@ -599,15 +599,18 @@ mod_opt_type(registration_watchers) ->
|
||||
[jid:decode(iolist_to_binary(S)) || S <- Ss]
|
||||
end;
|
||||
mod_opt_type(welcome_message) ->
|
||||
fun (Opts) ->
|
||||
S = proplists:get_value(subject, Opts, <<>>),
|
||||
B = proplists:get_value(body, Opts, <<>>),
|
||||
{iolist_to_binary(S), iolist_to_binary(B)}
|
||||
fun(L) ->
|
||||
{proplists:get_value(subject, L, <<"">>),
|
||||
proplists:get_value(body, L, <<"">>)}
|
||||
end;
|
||||
mod_opt_type({welcome_message, subject}) ->
|
||||
fun iolist_to_binary/1;
|
||||
mod_opt_type({welcome_message, body}) ->
|
||||
fun iolist_to_binary/1;
|
||||
mod_opt_type(_) ->
|
||||
[access, access_from, captcha_protected, ip_access,
|
||||
iqdisc, password_strength, registration_watchers,
|
||||
welcome_message].
|
||||
{welcome_message, subject}, {welcome_message, body}].
|
||||
|
||||
opt_type(registration_timeout) ->
|
||||
fun (TO) when is_integer(TO), TO > 0 -> TO;
|
||||
|
Loading…
Reference in New Issue
Block a user