Fix bug in decoding data URIs; Add tests in javase/, zxingorg/

This commit is contained in:
Sean Owen 2018-07-23 21:14:38 -05:00
parent e1b127c13a
commit d907537c05
12 changed files with 290 additions and 9 deletions

View file

@ -21,7 +21,6 @@ import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.net.URLDecoder;
/** /**
* Encapsulates reading URIs as images. * Encapsulates reading URIs as images.
@ -60,8 +59,7 @@ public final class ImageReader {
if (base64Start < 0) { if (base64Start < 0) {
throw new IOException("Unsupported data URI encoding"); throw new IOException("Unsupported data URI encoding");
} }
String base64DataEncoded = uriString.substring(base64Start + BASE64TOKEN.length()); String base64Data = uriString.substring(base64Start + BASE64TOKEN.length());
String base64Data = URLDecoder.decode(base64DataEncoded, "UTF-8");
byte[] imageBytes = Base64Decoder.getInstance().decode(base64Data); byte[] imageBytes = Base64Decoder.getInstance().decode(base64Data);
return ImageIO.read(new ByteArrayInputStream(imageBytes)); return ImageIO.read(new ByteArrayInputStream(imageBytes));
} }

View file

@ -0,0 +1,50 @@
/*
* Copyright 2018 ZXing authors
*
* 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.
*/
package com.google.zxing.client.j2se;
import com.beust.jcommander.JCommander;
import org.junit.Assert;
import org.junit.Test;
import java.net.URI;
import java.util.Collections;
import java.util.LinkedList;
import java.util.Queue;
/**
* Tests {@link DecodeWorker}.
*/
public final class DecodeWorkerTestCase extends Assert {
private static final String IMAGE_DATA_URI =
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACEAAAAhAQAAAAB/n//CAAAAkklEQVR42mP4DwQNDJjkB4" +
"E77A0M369N/d7A8CV6rjiQjPMFkWG1QPL7RVGg%2BAfREKCa/5/vA9V/nFSQ3sDwb7/KdiDJqX4dSH4pXN/A8DfyDVD2" +
"988HQPUfPVaqA0XKz%2BgD9bIk1AP1fgwvB7KlS9VBdqXbA82PT9AH2fiaH2SXGdDM71fDgeIfhIvKsbkTTAIAKYVr0N" +
"z5IloAAAAASUVORK5CYII=";
@Test
public void testWorker() throws Exception {
DecoderConfig config = new DecoderConfig();
JCommander jCommander = new JCommander(config);
jCommander.parse("--pure_barcode", IMAGE_DATA_URI);
Queue<URI> inputs = new LinkedList<>(Collections.singletonList(new URI(IMAGE_DATA_URI)));
DecodeWorker worker = new DecodeWorker(config, inputs);
assertEquals(1, worker.call().intValue());
}
}

View file

@ -28,7 +28,7 @@ import java.net.URI;
public final class ImageReaderTestCase extends Assert { public final class ImageReaderTestCase extends Assert {
@Test @Test
public void testFoo() throws Exception { public void testDataURI() throws Exception {
String uri = String uri =
"data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////w" + "data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////w" +
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6" +

View file

@ -68,10 +68,9 @@ public final class Generator implements EntryPoint {
setupLeftPanel(); setupLeftPanel();
topPanel.getElement().setId("leftpanel"); topPanel.getElement().setId("leftpanel");
Widget leftPanel = topPanel;
HorizontalPanel mainPanel = new HorizontalPanel(); HorizontalPanel mainPanel = new HorizontalPanel();
mainPanel.add(leftPanel); mainPanel.add(topPanel);
SimplePanel div2 = new SimplePanel(); SimplePanel div2 = new SimplePanel();
div2.add(result); div2.add(result);

View file

@ -39,13 +39,17 @@ import java.util.concurrent.TimeUnit;
@WebFilter({"/w/decode", "/w/chart"}) @WebFilter({"/w/decode", "/w/chart"})
public final class DoSFilter implements Filter { public final class DoSFilter implements Filter {
static final int MAX_ACCESS_PER_TIME = 500;
static final long ACCESS_TIME_MS = TimeUnit.MILLISECONDS.convert(5, TimeUnit.MINUTES);
static final int MAX_ENTRIES = 10_000;
private Timer timer; private Timer timer;
private DoSTracker sourceAddrTracker; private DoSTracker sourceAddrTracker;
@Override @Override
public void init(FilterConfig filterConfig) { public void init(FilterConfig filterConfig) {
timer = new Timer("DoSFilter"); timer = new Timer("DoSFilter");
sourceAddrTracker = new DoSTracker(timer, 500, TimeUnit.MILLISECONDS.convert(5, TimeUnit.MINUTES), 10_000); sourceAddrTracker = new DoSTracker(timer, MAX_ACCESS_PER_TIME, ACCESS_TIME_MS, MAX_ENTRIES);
timer.scheduleAtFixedRate( timer.scheduleAtFixedRate(
new TimerTask() { new TimerTask() {
@Override @Override

View file

@ -38,7 +38,7 @@ final class DoSTracker {
DoSTracker(Timer timer, final int maxAccessesPerTime, long accessTimeMS, int maxEntries) { DoSTracker(Timer timer, final int maxAccessesPerTime, long accessTimeMS, int maxEntries) {
this.maxAccessesPerTime = maxAccessesPerTime; this.maxAccessesPerTime = maxAccessesPerTime;
this.numRecentAccesses = new LRUMap<>(maxEntries); this.numRecentAccesses = new LRUMap<>(maxEntries);
timer.scheduleAtFixedRate(new TimerTask() { timer.schedule(new TimerTask() {
@Override @Override
public void run() { public void run() {
synchronized (numRecentAccesses) { synchronized (numRecentAccesses) {

View file

@ -0,0 +1,42 @@
/*
* Copyright 2018 ZXing authors
*
* 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.
*/
package com.google.zxing.web;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import org.junit.Assert;
import org.junit.Test;
import java.nio.charset.StandardCharsets;
/**
* Tests {@link ChartServletRequestParameters}.
*/
public final class ChartServletRequestParametersTestCase extends Assert {
@Test
public void testParams() {
ChartServletRequestParameters params =
new ChartServletRequestParameters(10, 20, StandardCharsets.UTF_8, ErrorCorrectionLevel.H, 5, "foo");
assertEquals(10, params.getWidth());
assertEquals(20, params.getHeight());
assertEquals(StandardCharsets.UTF_8, params.getOutputEncoding());
assertEquals(ErrorCorrectionLevel.H, params.getEcLevel());
assertEquals(5, params.getMargin());
assertEquals("foo", params.getText());
}
}

View file

@ -0,0 +1,48 @@
/*
* Copyright 2018 ZXing authors
*
* 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.
*/
package com.google.zxing.web;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.mock.web.MockFilterChain;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import javax.servlet.http.HttpServletResponse;
/**
* Tests {@link DoSFilter}.
*/
public final class DoSFilterTestCase extends Assert {
@Test
public void testRedirect() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setRequestURI("/");
request.setRemoteAddr("1.2.3.4");
MockHttpServletResponse response = new MockHttpServletResponse();
DoSFilter filter = new DoSFilter();
filter.init(null);
for (int i = 0; i < DoSFilter.MAX_ACCESS_PER_TIME; i++) {
filter.doFilter(request, response, new MockFilterChain());
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
}
filter.doFilter(request, response, new MockFilterChain());
assertEquals(HttpServletResponse.SC_FORBIDDEN, response.getStatus());
}
}

View file

@ -0,0 +1,58 @@
/*
* Copyright 2018 ZXing authors
*
* 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.
*/
package com.google.zxing.web;
import org.junit.Assert;
import org.junit.Test;
import java.util.Timer;
/**
* Tests {@link DoSTracker}.
*/
public final class DoSTrackerTestCase extends Assert {
@Test
public void testDoS() throws Exception {
Timer timer = new Timer();
long timerTimeMS = 200;
DoSTracker tracker = new DoSTracker(timer, 2, timerTimeMS, 3);
assertFalse(tracker.isBanned("A"));
assertFalse(tracker.isBanned("A"));
assertTrue(tracker.isBanned("A"));
assertFalse(tracker.isBanned("B"));
assertFalse(tracker.isBanned("C"));
assertFalse(tracker.isBanned("D"));
assertFalse(tracker.isBanned("A"));
assertFalse(tracker.isBanned("A"));
assertTrue(tracker.isBanned("A"));
Thread.sleep(timerTimeMS * 3);
assertFalse(tracker.isBanned("A"));
assertFalse(tracker.isBanned("A"));
assertTrue(tracker.isBanned("A"));
assertTrue(tracker.isBanned("A"));
assertTrue(tracker.isBanned("A"));
assertTrue(tracker.isBanned("A"));
assertTrue(tracker.isBanned("A"));
Thread.sleep(timerTimeMS * 2);
assertTrue(tracker.isBanned("A"));
}
}

View file

@ -42,7 +42,6 @@ public final class HTTPSFilterTestCase extends Assert {
request.setRequestURI("/path"); request.setRequestURI("/path");
response = new MockHttpServletResponse(); response = new MockHttpServletResponse();
chain = new MockFilterChain(); chain = new MockFilterChain();
} }
@Test @Test

View file

@ -0,0 +1,39 @@
/*
* Copyright 2018 ZXing authors
*
* 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.
*/
package com.google.zxing.web;
import org.junit.Assert;
import org.junit.Test;
/**
* Tests {@link LRUMap}.
*/
public final class LRUMapTestCase extends Assert {
@Test
public void testLRU() {
LRUMap<String,String> map = new LRUMap<>(2);
map.put("foo", "bar");
map.put("bar", "baz");
assertEquals("bar", map.get("foo"));
assertEquals("baz", map.get("bar"));
map.put("baz", "bing");
assertEquals("bing", map.get("baz"));
assertNull(map.get("foo"));
}
}

View file

@ -0,0 +1,44 @@
/*
* Copyright 2018 ZXing authors
*
* 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.
*/
package com.google.zxing.web;
import com.google.common.net.HttpHeaders;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.mock.web.MockFilterChain;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import javax.servlet.http.HttpServletResponse;
/**
* Tests {@link WelcomeFilter}.
*/
public final class WelcomeFilterTestCase extends Assert {
@Test
public void testRedirect() {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setRequestURI("/");
MockHttpServletResponse response = new MockHttpServletResponse();
MockFilterChain chain = new MockFilterChain();
new WelcomeFilter().doFilter(request, response, chain);
assertEquals(HttpServletResponse.SC_MOVED_PERMANENTLY, response.getStatus());
assertEquals("/w/decode.jspx", response.getHeader(HttpHeaders.LOCATION));
}
}