Commit 1e423e01 authored by Evan W. Patton's avatar Evan W. Patton Committed by Jeffrey I. Schiller

Fix project download bug reported by @barreeeiroo

Change-Id: Ibe01541a106b37bffbde21f05ea7f1b2c134070a
parent e4fcdfdd
// -*- mode: java; c-basic-offset: 2; -*- // -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2015 MIT, All rights reserved // Copyright 2015-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0 // Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0 // http://www.apache.org/licenses/LICENSE-2.0
...@@ -33,7 +33,7 @@ import com.google.appinventor.server.util.PasswordHash; ...@@ -33,7 +33,7 @@ import com.google.appinventor.server.util.PasswordHash;
public class AdminInfoServiceImpl extends OdeRemoteServiceServlet implements AdminInfoService { public class AdminInfoServiceImpl extends OdeRemoteServiceServlet implements AdminInfoService {
// Storage of user settings // Storage of user settings
private final transient StorageIo storageIo = StorageIoInstanceHolder.INSTANCE; private final transient StorageIo storageIo = StorageIoInstanceHolder.getInstance();
/** /**
* Returns a list of AdminUsers, up to 20, based on the starting * Returns a list of AdminUsers, up to 20, based on the starting
......
// -*- mode: java; c-basic-offset: 2; -*- // -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved // Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved // Copyright 2011-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0 // Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0 // http://www.apache.org/licenses/LICENSE-2.0
...@@ -33,7 +33,7 @@ public class AndroidServlet extends OdeServlet { ...@@ -33,7 +33,7 @@ public class AndroidServlet extends OdeServlet {
// Content type for response header (to avoid security vulnerabilities) // Content type for response header (to avoid security vulnerabilities)
private static final String CONTENT_TYPE = "text/html; charset=utf-8"; private static final String CONTENT_TYPE = "text/html; charset=utf-8";
private final StorageIo storageIo = StorageIoInstanceHolder.INSTANCE; private final StorageIo storageIo = StorageIoInstanceHolder.getInstance();
@Override @Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
......
// -*- mode: java; c-basic-offset: 2; -*- // -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2015 MIT, All rights reserved // Copyright 2015-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0 // Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0 // http://www.apache.org/licenses/LICENSE-2.0
...@@ -39,7 +39,7 @@ public class BlobUpgradeServlet extends OdeServlet { ...@@ -39,7 +39,7 @@ public class BlobUpgradeServlet extends OdeServlet {
// Logging support // Logging support
private static final Logger LOG = Logger.getLogger(BlobUpgradeServlet.class.getName()); private static final Logger LOG = Logger.getLogger(BlobUpgradeServlet.class.getName());
private static final CapabilitiesService caps = CapabilitiesServiceFactory.getCapabilitiesService(); private static final CapabilitiesService caps = CapabilitiesServiceFactory.getCapabilitiesService();
private final StorageIo storageIo = StorageIoInstanceHolder.INSTANCE; private final StorageIo storageIo = StorageIoInstanceHolder.getInstance();
@Override @Override
public void doPost(HttpServletRequest req, HttpServletResponse resp) public void doPost(HttpServletRequest req, HttpServletResponse resp)
......
// -*- mode: java; c-basic-offset: 2; -*- // -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved // Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2013 MIT, All rights reserved // Copyright 2011-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0 // Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0 // http://www.apache.org/licenses/LICENSE-2.0
...@@ -48,7 +48,7 @@ public class BuildOutputServlet extends OdeServlet { ...@@ -48,7 +48,7 @@ public class BuildOutputServlet extends OdeServlet {
private final FileExporter fileExporter = new FileExporterImpl(); private final FileExporter fileExporter = new FileExporterImpl();
private final StorageIo storageIo = StorageIoInstanceHolder.INSTANCE; private final StorageIo storageIo = StorageIoInstanceHolder.getInstance();
@Override @Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
......
// -*- mode: java; c-basic-offset: 2; -*- // -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2015-2017 MIT, All rights reserved // Copyright 2015-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0 // Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0 // http://www.apache.org/licenses/LICENSE-2.0
...@@ -49,7 +49,7 @@ public class ComponentServiceImpl extends OdeRemoteServiceServlet ...@@ -49,7 +49,7 @@ public class ComponentServiceImpl extends OdeRemoteServiceServlet
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(ComponentServiceImpl.class.getName()); Logger.getLogger(ComponentServiceImpl.class.getName());
private final transient StorageIo storageIo = StorageIoInstanceHolder.INSTANCE; private final transient StorageIo storageIo = StorageIoInstanceHolder.getInstance();
private final FileImporter fileImporter = new FileImporterImpl(); private final FileImporter fileImporter = new FileImporterImpl();
......
// -*- mode: java; c-basic-offset: 2; -*- // -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved // Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved // Copyright 2011-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0 // Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0 // http://www.apache.org/licenses/LICENSE-2.0
...@@ -126,6 +126,7 @@ public class DownloadServlet extends OdeServlet { ...@@ -126,6 +126,7 @@ public class DownloadServlet extends OdeServlet {
// project in the export // project in the export
boolean includeYail = userInfoProvider.getIsAdmin(); boolean includeYail = userInfoProvider.getIsAdmin();
boolean includeScreenShots = includeYail; boolean includeScreenShots = includeYail;
StorageIoInstanceHolder.getInstance().assertUserHasProject(userId, projectId);
ProjectSourceZip zipFile = fileExporter.exportProjectSourceZip(userId, ProjectSourceZip zipFile = fileExporter.exportProjectSourceZip(userId,
projectId, includeProjectHistory, false, zipName, includeYail, projectId, includeProjectHistory, false, zipName, includeYail,
includeScreenShots, false, false); includeScreenShots, false, false);
...@@ -141,7 +142,7 @@ public class DownloadServlet extends OdeServlet { ...@@ -141,7 +142,7 @@ public class DownloadServlet extends OdeServlet {
String userIdOrEmail = uriComponents[USER_PROJECT_USERID_INDEX]; String userIdOrEmail = uriComponents[USER_PROJECT_USERID_INDEX];
String projectUserId; String projectUserId;
StorageIo storageIo = StorageIoInstanceHolder.INSTANCE; StorageIo storageIo = StorageIoInstanceHolder.getInstance();
if (userIdOrEmail.contains("@")) { if (userIdOrEmail.contains("@")) {
// email address // email address
try { try {
...@@ -215,6 +216,17 @@ public class DownloadServlet extends OdeServlet { ...@@ -215,6 +216,17 @@ public class DownloadServlet extends OdeServlet {
} }
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
throw CrashReport.createAndLogError(LOG, req, "user=" + userId, e); throw CrashReport.createAndLogError(LOG, req, "user=" + userId, e);
} catch (SecurityException e) {
// Not having appropriate permission is akin to not being able to find the project anyway,
// so we use 404 here to not leak that the project may exist.
final String message = "404 Not Found";
resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
resp.setContentType("text/plain");
resp.setContentLength(message.length());
ServletOutputStream out = resp.getOutputStream();
out.write(message.getBytes());
out.close();
return;
} }
String fileName = downloadableFile.getFileName(); String fileName = downloadableFile.getFileName();
......
// -*- mode: java; c-basic-offset: 2; -*- // -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved // Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2013 MIT, All rights reserved // Copyright 2011-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0 // Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0 // http://www.apache.org/licenses/LICENSE-2.0
...@@ -35,7 +35,7 @@ public class FeedbackServlet extends OdeServlet { ...@@ -35,7 +35,7 @@ public class FeedbackServlet extends OdeServlet {
private static final Logger LOG = Logger.getLogger(ReceiveBuildServlet.class.getName()); private static final Logger LOG = Logger.getLogger(ReceiveBuildServlet.class.getName());
private final OdeAuthFilter odeFilter = new OdeAuthFilter(); private final OdeAuthFilter odeFilter = new OdeAuthFilter();
private final transient StorageIo storageIo = StorageIoInstanceHolder.INSTANCE; private final transient StorageIo storageIo = StorageIoInstanceHolder.getInstance();
@Override @Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
......
// -*- mode: java; c-basic-offset: 2; -*- // -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved // Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved // Copyright 2011-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0 // Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0 // http://www.apache.org/licenses/LICENSE-2.0
...@@ -30,7 +30,7 @@ import javax.annotation.Nullable; ...@@ -30,7 +30,7 @@ import javax.annotation.Nullable;
*/ */
public final class FileExporterImpl implements FileExporter { public final class FileExporterImpl implements FileExporter {
private final StorageIo storageIo = StorageIoInstanceHolder.INSTANCE; private final StorageIo storageIo = StorageIoInstanceHolder.getInstance();
@Override @Override
public RawFile exportProjectOutputFile(String userId, long projectId, @Nullable String target) public RawFile exportProjectOutputFile(String userId, long projectId, @Nullable String target)
......
// -*- mode: java; c-basic-offset: 2; -*- // -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved // Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2017 MIT, All rights reserved // Copyright 2011-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0 // Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0 // http://www.apache.org/licenses/LICENSE-2.0
...@@ -51,7 +51,7 @@ public final class FileImporterImpl implements FileImporter { ...@@ -51,7 +51,7 @@ public final class FileImporterImpl implements FileImporter {
private static final Logger LOG = Logger.getLogger(FileImporterImpl.class.getName()); private static final Logger LOG = Logger.getLogger(FileImporterImpl.class.getName());
private final StorageIo storageIo = StorageIoInstanceHolder.INSTANCE; private final StorageIo storageIo = StorageIoInstanceHolder.getInstance();
@Override @Override
public UserProject importProject(String userId, String projectName, public UserProject importProject(String userId, String projectName,
......
// -*- mode: java; c-basic-offset: 2; -*- // -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved // Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved // Copyright 2011-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0 // Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0 // http://www.apache.org/licenses/LICENSE-2.0
...@@ -35,7 +35,7 @@ public class GetMotdServiceImpl extends OdeRemoteServiceServlet implements GetMo ...@@ -35,7 +35,7 @@ public class GetMotdServiceImpl extends OdeRemoteServiceServlet implements GetMo
private static final Flag<Integer> motdCheckIntervalSecs = private static final Flag<Integer> motdCheckIntervalSecs =
Flag.createFlag("motd.check.interval.secs", 300); Flag.createFlag("motd.check.interval.secs", 300);
private final StorageIo storageIo = StorageIoInstanceHolder.INSTANCE; private final StorageIo storageIo = StorageIoInstanceHolder.getInstance();
private final MemcacheService memcache = MemcacheServiceFactory.getMemcacheService(); private final MemcacheService memcache = MemcacheServiceFactory.getMemcacheService();
......
// -*- mode: java; c-basic-offset: 2; -*- // -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved // Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2014 MIT, All rights reserved // Copyright 2011-2019 MIT, All rights reserved
// Released under the MIT License https://raw.github.com/mit-cml/app-inventor/master/mitlicense.txt // Released under the MIT License https://raw.github.com/mit-cml/app-inventor/master/mitlicense.txt
package com.google.appinventor.server; package com.google.appinventor.server;
...@@ -65,7 +65,7 @@ import org.owasp.html.PolicyFactory; ...@@ -65,7 +65,7 @@ import org.owasp.html.PolicyFactory;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public class LoginServlet extends HttpServlet { public class LoginServlet extends HttpServlet {
private final StorageIo storageIo = StorageIoInstanceHolder.INSTANCE; private final StorageIo storageIo = StorageIoInstanceHolder.getInstance();
private static final Logger LOG = Logger.getLogger(LoginServlet.class.getName()); private static final Logger LOG = Logger.getLogger(LoginServlet.class.getName());
private static final Flag<String> mailServer = Flag.createFlag("localauth.mailserver", ""); private static final Flag<String> mailServer = Flag.createFlag("localauth.mailserver", "");
private static final Flag<String> password = Flag.createFlag("localauth.mailserver.password", ""); private static final Flag<String> password = Flag.createFlag("localauth.mailserver.password", "");
......
// -*- mode: java; c-basic-offset: 2; -*- // -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved // Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved // Copyright 2011-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0 // Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0 // http://www.apache.org/licenses/LICENSE-2.0
...@@ -56,7 +56,7 @@ public class OdeAuthFilter implements Filter { ...@@ -56,7 +56,7 @@ public class OdeAuthFilter implements Filter {
private static Crypter crypter = null; // accessed through getCrypter only private static Crypter crypter = null; // accessed through getCrypter only
private static final Object crypterSync = new Object(); private static final Object crypterSync = new Object();
private final StorageIo storageIo = StorageIoInstanceHolder.INSTANCE; private final StorageIo storageIo = StorageIoInstanceHolder.getInstance();
// Whether this server should use a whitelist to determine who can // Whether this server should use a whitelist to determine who can
// access it. Value is specified in the <system-properties> section // access it. Value is specified in the <system-properties> section
......
// -*- mode: java; c-basic-offset: 2; -*- // -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved // Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2017 MIT, All rights reserved // Copyright 2011-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0 // Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0 // http://www.apache.org/licenses/LICENSE-2.0
...@@ -59,7 +59,7 @@ public class ProjectServiceImpl extends OdeRemoteServiceServlet implements Proje ...@@ -59,7 +59,7 @@ public class ProjectServiceImpl extends OdeRemoteServiceServlet implements Proje
private static final long serialVersionUID = -8316312003804169166L; private static final long serialVersionUID = -8316312003804169166L;
private final transient StorageIo storageIo = StorageIoInstanceHolder.INSTANCE; private final transient StorageIo storageIo = StorageIoInstanceHolder.getInstance();
// RPC implementation for YoungAndroid projects // RPC implementation for YoungAndroid projects
private final transient YoungAndroidProjectService youngAndroidProject = private final transient YoungAndroidProjectService youngAndroidProject =
......
// -*- mode: java; c-basic-offset: 2; -*- // -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved // Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved // Copyright 2011-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0 // Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0 // http://www.apache.org/licenses/LICENSE-2.0
...@@ -37,7 +37,7 @@ public class ReceiveBuildServlet extends OdeServlet { ...@@ -37,7 +37,7 @@ public class ReceiveBuildServlet extends OdeServlet {
private static final Logger LOG = Logger.getLogger(ReceiveBuildServlet.class.getName()); private static final Logger LOG = Logger.getLogger(ReceiveBuildServlet.class.getName());
private final OdeAuthFilter odeFilter = new OdeAuthFilter(); private final OdeAuthFilter odeFilter = new OdeAuthFilter();
private final transient StorageIo storageIo = StorageIoInstanceHolder.INSTANCE; private final transient StorageIo storageIo = StorageIoInstanceHolder.getInstance();
@Override @Override
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException { public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
......
// -*- mode: java; c-basic-offset: 2; -*- // -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved // Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved // Copyright 2011-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0 // Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0 // http://www.apache.org/licenses/LICENSE-2.0
...@@ -101,7 +101,7 @@ public class RendezvousServlet extends HttpServlet { ...@@ -101,7 +101,7 @@ public class RendezvousServlet extends HttpServlet {
private final String rendezvousuuid = "c96d8ac6-e571-48bb-9e1f-58df18574e43"; // UUID Generated by JIS private final String rendezvousuuid = "c96d8ac6-e571-48bb-9e1f-58df18574e43"; // UUID Generated by JIS
private final StorageIo storageIo = StorageIoInstanceHolder.INSTANCE; private final StorageIo storageIo = StorageIoInstanceHolder.getInstance();
public void init(ServletConfig config) throws ServletException { public void init(ServletConfig config) throws ServletException {
super.init(config); super.init(config);
......
...@@ -28,7 +28,7 @@ public class TosServlet extends OdeServlet { ...@@ -28,7 +28,7 @@ public class TosServlet extends OdeServlet {
// Logging support // Logging support
private static final Logger LOG = Logger.getLogger(TosServlet.class.getName()); private static final Logger LOG = Logger.getLogger(TosServlet.class.getName());
private final StorageIo storageIo = StorageIoInstanceHolder.INSTANCE; private final StorageIo storageIo = StorageIoInstanceHolder.getInstance();
private static final long serialVersionUID = 8099788377554316289L; private static final long serialVersionUID = 8099788377554316289L;
// An URL to redirect requests to the first time they access App Inventor. // An URL to redirect requests to the first time they access App Inventor.
......
// -*- mode: java; c-basic-offset: 2; -*- // -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved // Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved // Copyright 2011-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0 // Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0 // http://www.apache.org/licenses/LICENSE-2.0
...@@ -24,7 +24,7 @@ import com.google.appinventor.shared.storage.StorageUtil; ...@@ -24,7 +24,7 @@ import com.google.appinventor.shared.storage.StorageUtil;
public class UserInfoServiceImpl extends OdeRemoteServiceServlet implements UserInfoService { public class UserInfoServiceImpl extends OdeRemoteServiceServlet implements UserInfoService {
// Storage of user settings // Storage of user settings
private final transient StorageIo storageIo = StorageIoInstanceHolder.INSTANCE; private final transient StorageIo storageIo = StorageIoInstanceHolder.getInstance();
private static final long serialVersionUID = -7316312435338169166L; private static final long serialVersionUID = -7316312435338169166L;
......
// -*- mode: java; c-basic-offset: 2; -*- // -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved // Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved // Copyright 2011-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0 // Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0 // http://www.apache.org/licenses/LICENSE-2.0
...@@ -91,7 +91,7 @@ public class ObjectifyGalleryStorageIo implements GalleryStorageIo { ...@@ -91,7 +91,7 @@ public class ObjectifyGalleryStorageIo implements GalleryStorageIo {
// we'll need to talk to the StorageIo to get developer names, so... // we'll need to talk to the StorageIo to get developer names, so...
private final transient StorageIo storageIo = private final transient StorageIo storageIo =
StorageIoInstanceHolder.INSTANCE; StorageIoInstanceHolder.getInstance();
/** /**
* creates a new gallery app * creates a new gallery app
......
// -*- mode: java; c-basic-offset: 2; -*- // -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved // Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved // Copyright 2011-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0 // Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0 // http://www.apache.org/licenses/LICENSE-2.0
...@@ -2941,4 +2941,25 @@ public class ObjectifyStorageIo implements StorageIo { ...@@ -2941,4 +2941,25 @@ public class ObjectifyStorageIo implements StorageIo {
return ival.intValue(); return ival.intValue();
} }
} }
@Override
public void assertUserHasProject(final String userId, final long projectId) {
try {
runJobWithRetries(new JobRetryHelper() {
@SuppressWarnings("RedundantThrows")
@Override
public void run(Objectify datastore) throws ObjectifyException, IOException {
Key<UserData> userKey = userKey(userId);
Key<UserProjectData> userProjectKey = userProjectKey(userKey, projectId);
UserProjectData data = datastore.find(userProjectKey);
if (data == null) { // User doesn't have the corresponding project.
throw new SecurityException("Unauthorized access");
}
// User has data for project, so everything checks out.
}
}, false);
} catch(ObjectifyException e) {
throw CrashReport.createAndLogError(LOG, null, null, e);
}
}
} }
// -*- mode: java; c-basic-offset: 2; -*- // -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved // Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved // Copyright 2011-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0 // Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0 // http://www.apache.org/licenses/LICENSE-2.0
...@@ -706,4 +706,15 @@ public interface StorageIo { ...@@ -706,4 +706,15 @@ public interface StorageIo {
public int getBuildStatus(String userId, long projectId); public int getBuildStatus(String userId, long projectId);
/**
* Checks that the user identified by {@code userId} has a reference to the project identified
* by {@code projectId}. If a corresponding UserProjectData is not found, this function throws
* a SecurityException to indicate unauthorized access.
*
* @param userId id for the user
* @param projectId id for the project
* @throws SecurityException if the user doesn't have access to the project
*/
void assertUserHasProject(String userId, long projectId);
} }
// -*- mode: java; c-basic-offset: 2; -*- // -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved // Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved // Copyright 2011-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0 // Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0 // http://www.apache.org/licenses/LICENSE-2.0
package com.google.appinventor.server.storage; package com.google.appinventor.server.storage;
import com.google.common.annotations.VisibleForTesting;
/** /**
* Holds the singleton StorageIo subclass object. We introduce this class * Holds the singleton StorageIo subclass object. We introduce this class
* so that we can switch out the underlying StorageIo subclass without changing * so that we can switch out the underlying StorageIo subclass without changing
...@@ -15,8 +17,19 @@ package com.google.appinventor.server.storage; ...@@ -15,8 +17,19 @@ package com.google.appinventor.server.storage;
* *
*/ */
public class StorageIoInstanceHolder { public class StorageIoInstanceHolder {
public static final StorageIo INSTANCE = new ObjectifyStorageIo(); private static StorageIo INSTANCE;
private StorageIoInstanceHolder() {} // not to be instantiated private StorageIoInstanceHolder() {} // not to be instantiated
public static StorageIo getInstance() {
if (INSTANCE == null) {
INSTANCE = new ObjectifyStorageIo();
}
return INSTANCE;
}
@VisibleForTesting
public static void setInstance(StorageIo instance) {
INSTANCE = instance;
}
} }
// -*- mode: java; c-basic-offset: 2; -*- // -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2017 MIT, All rights reserved // Copyright 2017-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0 // Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0 // http://www.apache.org/licenses/LICENSE-2.0
...@@ -316,7 +316,8 @@ public class ComponentServiceTest { ...@@ -316,7 +316,8 @@ public class ComponentServiceTest {
} }
private void assertAssetsWithPrefixRemoved(String prefix) { private void assertAssetsWithPrefixRemoved(String prefix) {
List<String> files = StorageIoInstanceHolder.INSTANCE.getProjectSourceFiles("1", projectId); List<String> files = StorageIoInstanceHolder.getInstance()
.getProjectSourceFiles("1", projectId);
for (String name : files) { for (String name : files) {
if (name.startsWith(prefix)) { if (name.startsWith(prefix)) {
fail("Expected for file " + name + " to be deleted."); fail("Expected for file " + name + " to be deleted.");
...@@ -325,7 +326,8 @@ public class ComponentServiceTest { ...@@ -325,7 +326,8 @@ public class ComponentServiceTest {
} }
private void assertAssetsOnServer(String path) { private void assertAssetsOnServer(String path) {
List<String> files = StorageIoInstanceHolder.INSTANCE.getProjectSourceFiles("1", projectId); List<String> files = StorageIoInstanceHolder.getInstance()
.getProjectSourceFiles("1", projectId);
for (String name : files) { for (String name : files) {
if (name.equals(path)) { if (name.equals(path)) {
return; return;
......
// -*- mode: java; c-basic-offset: 2; -*- // -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved // Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved // Copyright 2011-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0 // Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0 // http://www.apache.org/licenses/LICENSE-2.0
package com.google.appinventor.server; package com.google.appinventor.server;
import com.google.appinventor.server.storage.StorageIo;
import com.google.appinventor.server.storage.StorageIoInstanceHolder;
import com.google.appinventor.shared.rpc.project.ProjectSourceZip; import com.google.appinventor.shared.rpc.project.ProjectSourceZip;
import com.google.appinventor.shared.rpc.project.RawFile; import com.google.appinventor.shared.rpc.project.RawFile;
import com.riq.MockHttpServletRequest; import com.riq.MockHttpServletRequest;
...@@ -17,6 +19,7 @@ import org.powermock.api.easymock.PowerMock; ...@@ -17,6 +19,7 @@ import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner; import org.powermock.modules.junit4.PowerMockRunner;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
...@@ -50,6 +53,7 @@ public class DownloadServletTest { ...@@ -50,6 +53,7 @@ public class DownloadServletTest {
private FileExporterImpl exporterMock; private FileExporterImpl exporterMock;
private LocalUser localUserMock; private LocalUser localUserMock;
private StorageIo storageIoMock;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
...@@ -60,6 +64,9 @@ public class DownloadServletTest { ...@@ -60,6 +64,9 @@ public class DownloadServletTest {
exporterMock = PowerMock.createNiceMock(FileExporterImpl.class); exporterMock = PowerMock.createNiceMock(FileExporterImpl.class);
PowerMock.expectNew(FileExporterImpl.class).andReturn(exporterMock).anyTimes(); PowerMock.expectNew(FileExporterImpl.class).andReturn(exporterMock).anyTimes();
storageIoMock = PowerMock.createNiceMock(StorageIo.class);
StorageIoInstanceHolder.setInstance(storageIoMock);
dummyZip = new ProjectSourceZip(DUMMY_ZIP_FILENAME, new byte[] {}, 2); dummyZip = new ProjectSourceZip(DUMMY_ZIP_FILENAME, new byte[] {}, 2);
dummyZipWithTitle = new ProjectSourceZip(DUMMY_ZIP_FILENAME_WITH_TITLE, new byte[] {}, 2); dummyZipWithTitle = new ProjectSourceZip(DUMMY_ZIP_FILENAME_WITH_TITLE, new byte[] {}, 2);
dummyApk = new RawFile(DUMMY_APK_FILENAME, new byte[] {}); dummyApk = new RawFile(DUMMY_APK_FILENAME, new byte[] {});
...@@ -74,6 +81,8 @@ public class DownloadServletTest { ...@@ -74,6 +81,8 @@ public class DownloadServletTest {
@Test @Test
public void testDownloadProjectSourceZipWithoutTitle() throws Exception { public void testDownloadProjectSourceZipWithoutTitle() throws Exception {
storageIoMock.assertUserHasProject(USER_ID, PROJECT_ID);
PowerMock.expectLastCall().once();
MockHttpServletRequest request = new MockHttpServletRequest(DOWNLOAD_URL + MockHttpServletRequest request = new MockHttpServletRequest(DOWNLOAD_URL +
"project-source/1234"); "project-source/1234");
expect(exporterMock.exportProjectSourceZip(USER_ID, PROJECT_ID, true, false, null, false, false, false, false)) expect(exporterMock.exportProjectSourceZip(USER_ID, PROJECT_ID, true, false, null, false, false, false, false))
...@@ -89,6 +98,8 @@ public class DownloadServletTest { ...@@ -89,6 +98,8 @@ public class DownloadServletTest {
@Test @Test
public void testDownloadProjectSourceZipWithTitle() throws IOException { public void testDownloadProjectSourceZipWithTitle() throws IOException {
storageIoMock.assertUserHasProject(USER_ID, PROJECT_ID);
PowerMock.expectLastCall().once();
MockHttpServletRequest request = new MockHttpServletRequest(DOWNLOAD_URL + MockHttpServletRequest request = new MockHttpServletRequest(DOWNLOAD_URL +
"project-source/1234/My Project Title 123"); "project-source/1234/My Project Title 123");
expect(exporterMock.exportProjectSourceZip(USER_ID, PROJECT_ID, true, false, expect(exporterMock.exportProjectSourceZip(USER_ID, PROJECT_ID, true, false,
...@@ -105,20 +116,15 @@ public class DownloadServletTest { ...@@ -105,20 +116,15 @@ public class DownloadServletTest {
@Test @Test
public void testDownloadProjectSourceZipWithNonExistingProject() throws IOException { public void testDownloadProjectSourceZipWithNonExistingProject() throws IOException {
IllegalArgumentException expectedException = new IllegalArgumentException(); storageIoMock.assertUserHasProject(USER_ID, 12345L);
PowerMock.expectLastCall().andThrow(new SecurityException());
PowerMock.replayAll();
MockHttpServletRequest request = new MockHttpServletRequest(DOWNLOAD_URL + MockHttpServletRequest request = new MockHttpServletRequest(DOWNLOAD_URL +
"project-source/12345"); "project-source/12345");
expect(exporterMock.exportProjectSourceZip(USER_ID, 12345L, true, false, null, false, false, false, false))
.andThrow(expectedException);
PowerMock.replayAll();
DownloadServlet download = new DownloadServlet(); DownloadServlet download = new DownloadServlet();
try { MockHttpServletResponse response = new MockHttpServletResponse();
download.doGet(request, new MockHttpServletResponse()); download.doGet(request, response);
fail(); assertEquals(HttpServletResponse.SC_NOT_FOUND, response.getStatus());
} catch (IllegalArgumentException ex) {
assertEquals(expectedException, ex);
}
PowerMock.verifyAll();
} }
@Test @Test
......
// -*- mode: java; c-basic-offset: 2; -*- // -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved // Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved // Copyright 2011-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0 // Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0 // http://www.apache.org/licenses/LICENSE-2.0
...@@ -58,7 +58,7 @@ public class FileExporterImplTest extends LocalDatastoreTestCase { ...@@ -58,7 +58,7 @@ public class FileExporterImplTest extends LocalDatastoreTestCase {
@Override @Override
protected void setUp() throws Exception { protected void setUp() throws Exception {
super.setUp(); super.setUp();
storageIo = StorageIoInstanceHolder.INSTANCE; storageIo = StorageIoInstanceHolder.getInstance();
exporter = new FileExporterImpl(); exporter = new FileExporterImpl();
Project project = new Project(PROJECT_NAME); Project project = new Project(PROJECT_NAME);
project.setProjectType(FAKE_PROJECT_TYPE); project.setProjectType(FAKE_PROJECT_TYPE);
......
// -*- mode: java; c-basic-offset: 2; -*- // -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved // Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved // Copyright 2011-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0 // Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0 // http://www.apache.org/licenses/LICENSE-2.0
...@@ -43,7 +43,7 @@ public class FileImporterImplTest extends LocalDatastoreTestCase { ...@@ -43,7 +43,7 @@ public class FileImporterImplTest extends LocalDatastoreTestCase {
@Override @Override
protected void setUp() throws Exception { protected void setUp() throws Exception {
super.setUp(); super.setUp();
storageIo = StorageIoInstanceHolder.INSTANCE; storageIo = StorageIoInstanceHolder.getInstance();
// Create user with given parameters // Create user with given parameters
storageIo.getUser(USER_ID, USER_EMAIL_ADDRESS); storageIo.getUser(USER_ID, USER_EMAIL_ADDRESS);
fileImporter = new FileImporterImpl(); fileImporter = new FileImporterImpl();
......
// -*- mode: java; c-basic-offset: 2; -*- // -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved // Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2017 MIT, All rights reserved // Copyright 2011-2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0 // Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0 // http://www.apache.org/licenses/LICENSE-2.0
...@@ -103,7 +103,7 @@ public class ProjectServiceTest { ...@@ -103,7 +103,7 @@ public class ProjectServiceTest {
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
helper.setUp(); helper.setUp();
storageIo = StorageIoInstanceHolder.INSTANCE; storageIo = StorageIoInstanceHolder.getInstance();
PowerMock.mockStatic(LocalUser.class); PowerMock.mockStatic(LocalUser.class);
localUserMock = PowerMock.createMock(LocalUser.class); localUserMock = PowerMock.createMock(LocalUser.class);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment