summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Avdey <eiri@eiri.ca>2017-09-14 10:40:17 -0300
committerEric Avdey <eiri@eiri.ca>2017-09-14 12:45:53 -0300
commit369b442e647cf863bbeeb42c6ea8027b0f7b8123 (patch)
treecffcf9b8bb7f3e25ac2c7a007ec8fb99314aeee4
parented6ec66972f268b6d6d86b55730e73cc4ab54ceb (diff)
downloadcouchdb-369b442e647cf863bbeeb42c6ea8027b0f7b8123.tar.gz
Catch invalid base64 in inline attachments
-rw-r--r--src/couch/src/couch_att.erl55
-rw-r--r--test/javascript/tests/attachments.js18
2 files changed, 64 insertions, 9 deletions
diff --git a/src/couch/src/couch_att.erl b/src/couch/src/couch_att.erl
index e78d6ef11..5c040a8c4 100644
--- a/src/couch/src/couch_att.erl
+++ b/src/couch/src/couch_att.erl
@@ -413,13 +413,21 @@ follow_from_json(Att, Props) ->
inline_from_json(Att, Props) ->
B64Data = couch_util:get_value(<<"data">>, Props),
- Data = base64:decode(B64Data),
- Length = size(Data),
- RevPos = couch_util:get_value(<<"revpos">>, Props, 0),
- store([
- {data, Data}, {revpos, RevPos}, {disk_len, Length},
- {att_len, Length}
- ], Att).
+ try base64:decode(B64Data) of
+ Data ->
+ Length = size(Data),
+ RevPos = couch_util:get_value(<<"revpos">>, Props, 0),
+ store([
+ {data, Data}, {revpos, RevPos}, {disk_len, Length},
+ {att_len, Length}
+ ], Att)
+ catch
+ _:_ ->
+ Name = fetch(name, Att),
+ ErrMsg = <<"Invalid attachment data for ", Name/binary>>,
+ throw({bad_request, ErrMsg})
+ end.
+
encoded_lengths_from_json(Props) ->
@@ -787,8 +795,37 @@ attachment_disk_term_test_() ->
attachment_json_term_test_() ->
- %% We need to create a few variations including stubs and inline data.
- {"JSON term tests", []}.
+ Props = [
+ {<<"content_type">>, <<"application/json">>},
+ {<<"digest">>, <<"md5-QCNtWUNXV0UzJnEjMk92YUk1JA==">>},
+ {<<"length">>, 14},
+ {<<"revpos">>, 1}
+ ],
+ PropsInline = [{<<"data">>, <<"eyJhbnN3ZXIiOiA0Mn0=">>}] ++ Props,
+ InvalidProps = [{<<"data">>, <<"!Base64Encoded$">>}] ++ Props,
+ Att = couch_att:new([
+ {name, <<"attachment.json">>},
+ {type, <<"application/json">>}
+ ]),
+ ResultStub = couch_att:new([
+ {name, <<"attachment.json">>},
+ {type, <<"application/json">>},
+ {att_len, 14},
+ {disk_len, 14},
+ {md5, <<"@#mYCWWE3&q#2OvaI5$">>},
+ {revpos, 1},
+ {data, stub},
+ {encoding, identity}
+ ]),
+ ResultFollows = ResultStub#att{data = follows},
+ ResultInline = ResultStub#att{md5 = <<>>, data = <<"{\"answer\": 42}">>},
+ {"JSON term tests", [
+ ?_assertEqual(ResultStub, stub_from_json(Att, Props)),
+ ?_assertEqual(ResultFollows, follow_from_json(Att, Props)),
+ ?_assertEqual(ResultInline, inline_from_json(Att, PropsInline)),
+ ?_assertThrow({bad_request, _}, inline_from_json(Att, Props)),
+ ?_assertThrow({bad_request, _}, inline_from_json(Att, InvalidProps))
+ ]}.
attachment_stub_merge_test_() ->
diff --git a/test/javascript/tests/attachments.js b/test/javascript/tests/attachments.js
index cd6474d0f..2e831a731 100644
--- a/test/javascript/tests/attachments.js
+++ b/test/javascript/tests/attachments.js
@@ -33,6 +33,24 @@ couchTests.attachments= function(debug) {
var save_response = db.save(binAttDoc);
T(save_response.ok);
+ var badAttDoc = {
+ _id: "bad_doc",
+ _attachments: {
+ "foo.txt": {
+ content_type: "text/plain",
+ data: "notBase64Encoded="
+ }
+ }
+ };
+
+ try {
+ db.save(badAttDoc);
+ T(false && "Shouldn't get here!");
+ } catch (e) {
+ TEquals("bad_request", e.error);
+ TEquals("Invalid attachment data for foo.txt", e.message);
+ }
+
var xhr = CouchDB.request("GET", "/" + db_name + "/bin_doc/foo.txt");
T(xhr.responseText == "This is a base64 encoded text");
T(xhr.getResponseHeader("Content-Type") == "application/octet-stream");