mirror of
https://github.com/processone/ejabberd
synced 2025-10-03 09:49:18 +02:00
Handle CAPTCHA forms using captcha_form codec
This commit is contained in:
parent
6b3d0d154e
commit
f85488583c
2 changed files with 54 additions and 65 deletions
|
@ -24,7 +24,7 @@
|
||||||
{fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.1.1"}}},
|
{fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.1.1"}}},
|
||||||
{stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.16"}}},
|
{stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.16"}}},
|
||||||
{fast_xml, ".*", {git, "https://github.com/processone/fast_xml", "7fd02f3a2f"}},
|
{fast_xml, ".*", {git, "https://github.com/processone/fast_xml", "7fd02f3a2f"}},
|
||||||
{xmpp, ".*", {git, "https://github.com/processone/xmpp", "31413d7"}},
|
{xmpp, ".*", {git, "https://github.com/processone/xmpp", "3e2f1c5"}},
|
||||||
{fast_yaml, ".*", {git, "https://github.com/processone/fast_yaml", {tag, "1.0.19"}}},
|
{fast_yaml, ".*", {git, "https://github.com/processone/fast_yaml", {tag, "1.0.19"}}},
|
||||||
{yconf, ".*", {git, "https://github.com/processone/yconf", "dfeaa7e"}},
|
{yconf, ".*", {git, "https://github.com/processone/yconf", "dfeaa7e"}},
|
||||||
{jiffy, ".*", {git, "https://github.com/davisp/jiffy", {tag, "0.14.8"}}},
|
{jiffy, ".*", {git, "https://github.com/davisp/jiffy", {tag, "0.14.8"}}},
|
||||||
|
|
|
@ -74,15 +74,8 @@ captcha_text(Lang) ->
|
||||||
-spec mk_ocr_field(binary(), binary(), binary()) -> xdata_field().
|
-spec mk_ocr_field(binary(), binary(), binary()) -> xdata_field().
|
||||||
mk_ocr_field(Lang, CID, Type) ->
|
mk_ocr_field(Lang, CID, Type) ->
|
||||||
URI = #media_uri{type = Type, uri = <<"cid:", CID/binary>>},
|
URI = #media_uri{type = Type, uri = <<"cid:", CID/binary>>},
|
||||||
#xdata_field{var = <<"ocr">>,
|
[_, F] = captcha_form:encode([{ocr, <<>>}], Lang, [ocr]),
|
||||||
type = 'text-single',
|
xmpp:set_els(F, [#media{uri = [URI]}]).
|
||||||
label = captcha_text(Lang),
|
|
||||||
required = true,
|
|
||||||
sub_els = [#media{uri = [URI]}]}.
|
|
||||||
|
|
||||||
-spec mk_field(_, binary(), binary()) -> xdata_field().
|
|
||||||
mk_field(Type, Var, Value) ->
|
|
||||||
#xdata_field{type = Type, var = Var, values = [Value]}.
|
|
||||||
|
|
||||||
-spec create_captcha(binary(), jid(), jid(),
|
-spec create_captcha(binary(), jid(), jid(),
|
||||||
binary(), any(),
|
binary(), any(),
|
||||||
|
@ -94,13 +87,11 @@ create_captcha(SID, From, To, Lang, Limiter, Args) ->
|
||||||
Id = <<(p1_rand:get_string())/binary>>,
|
Id = <<(p1_rand:get_string())/binary>>,
|
||||||
JID = jid:encode(From),
|
JID = jid:encode(From),
|
||||||
CID = <<"sha1+", (str:sha(Image))/binary, "@bob.xmpp.org">>,
|
CID = <<"sha1+", (str:sha(Image))/binary, "@bob.xmpp.org">>,
|
||||||
Data = #bob_data{cid = CID, 'max-age' = 0, type = Type,
|
Data = #bob_data{cid = CID, 'max-age' = 0, type = Type, data = Image},
|
||||||
data = Image},
|
Fs = captcha_form:encode(
|
||||||
Fs = [mk_field(hidden, <<"FORM_TYPE">>, ?NS_CAPTCHA),
|
[{from, To}, {challenge, Id}, {sid, SID},
|
||||||
mk_field(hidden, <<"from">>, jid:encode(To)),
|
|
||||||
mk_field(hidden, <<"challenge">>, Id),
|
|
||||||
mk_field(hidden, <<"sid">>, SID),
|
|
||||||
mk_ocr_field(Lang, CID, Type)],
|
mk_ocr_field(Lang, CID, Type)],
|
||||||
|
Lang, [challenge]),
|
||||||
X = #xdata{type = form, fields = Fs},
|
X = #xdata{type = form, fields = Fs},
|
||||||
Captcha = #xcaptcha{xdata = X},
|
Captcha = #xcaptcha{xdata = X},
|
||||||
BodyString = {?T("Your subscription request and/or messages to ~s have been blocked. "
|
BodyString = {?T("Your subscription request and/or messages to ~s have been blocked. "
|
||||||
|
@ -108,8 +99,7 @@ create_captcha(SID, From, To, Lang, Limiter, Args) ->
|
||||||
Body = xmpp:mk_text(BodyString, Lang),
|
Body = xmpp:mk_text(BodyString, Lang),
|
||||||
OOB = #oob_x{url = get_url(Id)},
|
OOB = #oob_x{url = get_url(Id)},
|
||||||
Hint = #hint{type = 'no-store'},
|
Hint = #hint{type = 'no-store'},
|
||||||
Tref = erlang:send_after(?CAPTCHA_LIFETIME, ?MODULE,
|
Tref = erlang:send_after(?CAPTCHA_LIFETIME, ?MODULE, {remove_id, Id}),
|
||||||
{remove_id, Id}),
|
|
||||||
ets:insert(captcha,
|
ets:insert(captcha,
|
||||||
#captcha{id = Id, pid = self(), key = Key, tref = Tref,
|
#captcha{id = Id, pid = self(), key = Key, tref = Tref,
|
||||||
args = Args}),
|
args = Args}),
|
||||||
|
@ -125,27 +115,18 @@ create_captcha_x(SID, To, Lang, Limiter, #xdata{fields = Fs} = X) ->
|
||||||
Id = <<(p1_rand:get_string())/binary>>,
|
Id = <<(p1_rand:get_string())/binary>>,
|
||||||
CID = <<"sha1+", (str:sha(Image))/binary, "@bob.xmpp.org">>,
|
CID = <<"sha1+", (str:sha(Image))/binary, "@bob.xmpp.org">>,
|
||||||
Data = #bob_data{cid = CID, 'max-age' = 0, type = Type, data = Image},
|
Data = #bob_data{cid = CID, 'max-age' = 0, type = Type, data = Image},
|
||||||
HelpTxt = translate:translate(Lang,
|
HelpTxt = translate:translate(
|
||||||
?T("If you don't see the CAPTCHA image here, "
|
Lang, ?T("If you don't see the CAPTCHA image here, visit the web page.")),
|
||||||
"visit the web page.")),
|
|
||||||
Imageurl = get_url(<<Id/binary, "/image">>),
|
Imageurl = get_url(<<Id/binary, "/image">>),
|
||||||
NewFs = [mk_field(hidden, <<"FORM_TYPE">>, ?NS_CAPTCHA)|Fs] ++
|
[H|T] = captcha_form:encode(
|
||||||
[#xdata_field{type = fixed, var = <<"captcha-fallback-text">>, values = [HelpTxt]},
|
[{'captcha-fallback-text', HelpTxt},
|
||||||
#xdata_field{type = hidden, var = <<"captchahidden">>,
|
{'captcha-fallback-url', Imageurl},
|
||||||
values = [<<"workaround-for-psi">>]},
|
{from, To}, {challenge, Id}, {sid, SID},
|
||||||
#xdata_field{type = 'text-single', var = <<"captcha-fallback-url">>,
|
|
||||||
label = translate:translate(
|
|
||||||
Lang, ?T("CAPTCHA web page")),
|
|
||||||
values = [Imageurl]},
|
|
||||||
mk_field(hidden, <<"from">>, jid:encode(To)),
|
|
||||||
mk_field(hidden, <<"challenge">>, Id),
|
|
||||||
mk_field(hidden, <<"sid">>, SID),
|
|
||||||
mk_ocr_field(Lang, CID, Type)],
|
mk_ocr_field(Lang, CID, Type)],
|
||||||
Captcha = X#xdata{type = form, fields = NewFs},
|
Lang, [challenge]),
|
||||||
Tref = erlang:send_after(?CAPTCHA_LIFETIME, ?MODULE,
|
Captcha = X#xdata{type = form, fields = [H|Fs ++ T]},
|
||||||
{remove_id, Id}),
|
Tref = erlang:send_after(?CAPTCHA_LIFETIME, ?MODULE, {remove_id, Id}),
|
||||||
ets:insert(captcha,
|
ets:insert(captcha, #captcha{id = Id, key = Key, tref = Tref}),
|
||||||
#captcha{id = Id, key = Key, tref = Tref}),
|
|
||||||
{ok, [Captcha, Data]};
|
{ok, [Captcha, Data]};
|
||||||
Err -> Err
|
Err -> Err
|
||||||
end.
|
end.
|
||||||
|
@ -201,15 +182,23 @@ build_captcha_html(Id, Lang) ->
|
||||||
-spec process_reply(xmpp_element()) -> ok | {error, bad_match | not_found | malformed}.
|
-spec process_reply(xmpp_element()) -> ok | {error, bad_match | not_found | malformed}.
|
||||||
|
|
||||||
process_reply(#xdata{} = X) ->
|
process_reply(#xdata{} = X) ->
|
||||||
case {xmpp_util:get_xdata_values(<<"challenge">>, X),
|
Required = [<<"challenge">>, <<"ocr">>],
|
||||||
xmpp_util:get_xdata_values(<<"ocr">>, X)} of
|
Fs = lists:filter(
|
||||||
{[Id], [OCR]} ->
|
fun(#xdata_field{var = Var}) ->
|
||||||
|
lists:member(Var, [<<"FORM_TYPE">>|Required])
|
||||||
|
end, X#xdata.fields),
|
||||||
|
try captcha_form:decode(Fs, [?NS_CAPTCHA], Required) of
|
||||||
|
Props ->
|
||||||
|
Id = proplists:get_value(challenge, Props),
|
||||||
|
OCR = proplists:get_value(ocr, Props),
|
||||||
case check_captcha(Id, OCR) of
|
case check_captcha(Id, OCR) of
|
||||||
captcha_valid -> ok;
|
captcha_valid -> ok;
|
||||||
captcha_non_valid -> {error, bad_match};
|
captcha_non_valid -> {error, bad_match};
|
||||||
captcha_not_found -> {error, not_found}
|
captcha_not_found -> {error, not_found}
|
||||||
end;
|
end
|
||||||
_ ->
|
catch _:{captcha_form, Why} ->
|
||||||
|
?WARNING_MSG("Malformed CAPTCHA form: ~s",
|
||||||
|
[captcha_form:format_error(Why)]),
|
||||||
{error, malformed}
|
{error, malformed}
|
||||||
end;
|
end;
|
||||||
process_reply(#xcaptcha{xdata = #xdata{} = X}) ->
|
process_reply(#xcaptcha{xdata = #xdata{} = X}) ->
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue