Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,8 @@ public void put(String platform, String key, File source) throws ExtenderClientE
throw new ExtenderClientException(String.format("Failed to create cache dir %s", parentDir.getAbsolutePath()));
}

try {
Files.copy(new FileInputStream(source), cachedFile.toPath(), REPLACE_EXISTING);
try(InputStream is = new FileInputStream(source)) {
Files.copy(is, cachedFile.toPath(), REPLACE_EXISTING);
} catch (IOException e) {
throw new ExtenderClientException(String.format("Failed to copy %s to %s", source.getAbsolutePath(), cachedFile.getAbsolutePath()), e);
}
Expand All @@ -152,15 +152,13 @@ public void get(String platform, String key, File destination) throws ExtenderCl
throw new ExtenderClientException(String.format("The file %s wasn't cached with key %s", cachedFile.getAbsolutePath(), key));
}

try {
Files.copy(new FileInputStream(cachedFile), destination.toPath(), REPLACE_EXISTING);
try(InputStream is = new FileInputStream(cachedFile)) {
Files.copy(is, destination.toPath(), REPLACE_EXISTING);
} catch (IOException e) {
throw new ExtenderClientException(String.format("Failed to copy %s to %s", cachedFile.getAbsolutePath(), destination.getAbsolutePath()), e);
}
}

//

private static MessageDigest getHasher() throws ExtenderClientException {
MessageDigest md = null;
try {
Expand Down Expand Up @@ -198,8 +196,8 @@ private void saveCache() {

private void loadCache() {
Properties properties = new Properties();
try {
properties.load(new FileInputStream(getCacheFile()));
try(InputStream is = new FileInputStream(getCacheFile())) {
properties.load(is);
} catch (IOException e) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,18 +205,19 @@ public void testUploadStructure(String cacheResponse, List<String> expectedFilen
assertNotNull(sourceCodeArchiveEntity);
assertTrue(sourceCodeArchiveEntity.getBody() instanceof BinaryBody);
BinaryBody archiveBody = (BinaryBody)sourceCodeArchiveEntity.getBody();
ZipInputStream zis = new ZipInputStream(archiveBody.getInputStream());
ZipEntry zipEntry = zis.getNextEntry();
List<String> zipEntriesFilenames = new ArrayList<>();
while (zipEntry != null) {
zipEntriesFilenames.add(zipEntry.getName());
zipEntry = zis.getNextEntry();
try (ZipInputStream zis = new ZipInputStream(archiveBody.getInputStream())) {
ZipEntry zipEntry = zis.getNextEntry();
List<String> zipEntriesFilenames = new ArrayList<>();
while (zipEntry != null) {
zipEntriesFilenames.add(zipEntry.getName());
zipEntry = zis.getNextEntry();
}
assertTrue(
expectedFilenames.size() == zipEntriesFilenames.size() &&
expectedFilenames.containsAll(zipEntriesFilenames) &&
zipEntriesFilenames.containsAll(expectedFilenames)
);
}
assertTrue(
expectedFilenames.size() == zipEntriesFilenames.size() &&
expectedFilenames.containsAll(zipEntriesFilenames) &&
zipEntriesFilenames.containsAll(expectedFilenames)
);
}
catch (Exception e) {
System.out.println("ERROR LOG:");
Expand Down
4 changes: 2 additions & 2 deletions server/build-docker.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ DOCKER_XBOX_PRIVATE_REGISTRY=$REGISTRY_PREFIX/extender-xbox-private-registry
MULTI_ARCH="linux/amd64"
[[ -z "$NO_ARM64" ]] && MULTI_ARCH+=",linux/arm64"

# base stage image (shared across Dockerfiles)
echo "Base stage image with archs: $MULTI_ARCH"
# build env image (shared across Dockerfiles)
echo "Build env image with archs: $MULTI_ARCH"
docker buildx build --load --platform $MULTI_ARCH -t $DOCKER_REGISTRY/extender-build-env:1.0.0 -t $DOCKER_REGISTRY/extender-build-env:latest -f $SCRIPT_DIR/docker/Dockerfile.build-env $SCRIPT_DIR/docker

# base images
Expand Down
7 changes: 7 additions & 0 deletions server/configs/application-local-dev-app.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
extender:
sdk:
sdk-urls: >
https://d.defold.com/archive/stable/%s/engine/defoldsdk.zip,
https://d.defold.com/archive/%s/engine/defoldsdk.zip
mappings-urls: >
https://d.defold.com/archive/stable/%s/engine/platform.sdks.json,
https://d.defold.com/archive/%s/engine/platform.sdks.json
instance-type: FRONTEND_ONLY
remote-builder:
enabled: true
Expand Down
6 changes: 3 additions & 3 deletions server/envs/generate_user_env.sh
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ echo "XCTOOLCHAIN_PATH=${PLATFORMSDK_DIR}/XcodeDefault${XCODE_VERSION}.xctoolcha

echo "PATH=\"${APPENDED_PATH}\"" >> $OUTPUT_FILE

echo ";DM_DEBUG_COMMANDS=1" >> $OUTPUT_FILE
echo ";DYNAMO_HOME=" >> $OUTPUT_FILE
echo ";DM_DEBUG_KEEP_JOB_FOLDER=1" >> $OUTPUT_FILE
echo "#DM_DEBUG_COMMANDS=1" >> $OUTPUT_FILE
echo "#DYNAMO_HOME=" >> $OUTPUT_FILE
echo "#DM_DEBUG_KEEP_JOB_FOLDER=1" >> $OUTPUT_FILE

echo "Generation completed."
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,23 @@ private static class ILoggerWrapper implements ILogger {
public ILoggerWrapper(Logger logger) {
this.logger = logger;
}

@Override
public void error(Throwable t, String msgFormat, Object... args) {
AndroidManifestMerger.logger.log(Level.SEVERE, msgFormat, args);
}

@Override
public void warning(String msgFormat, Object... args) {
AndroidManifestMerger.logger.log(Level.WARNING, msgFormat, args);
}

@Override
public void info(String msgFormat, Object... args) {
AndroidManifestMerger.logger.log(Level.INFO, msgFormat, args);
}

@Override
public void verbose(String msgFormat, Object... args) {
AndroidManifestMerger.logger.log(Level.FINE, msgFormat, args);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.io.FileNotFoundException;
import java.util.Iterator;
import java.util.ArrayList;
Expand Down Expand Up @@ -151,14 +152,16 @@ else if (baseMergePolicy == MergePolicy.MERGE) {


private XMLPropertyListConfiguration loadPlist(File file) {
try {
try(Reader fr = new FileReader(file)) {
XMLPropertyListConfiguration plist = new XMLPropertyListConfiguration();
plist.read(new FileReader(file));
plist.read(fr);
return plist;
} catch (ConfigurationException e) {
throw new RuntimeException(String.format("Failed to parse plist '%s': %s", file.getAbsolutePath(), e.toString()));
} catch (FileNotFoundException e) {
throw new RuntimeException(String.format("File not found: %s", file.getAbsolutePath()));
} catch (IOException e) {
throw new RuntimeException(String.format("Exception when closing file %s", e.getMessage()));
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.defold.manifestmergetool;

import java.io.File;
import java.io.Reader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
Expand Down Expand Up @@ -132,14 +133,16 @@ private void mergeConfigs(XMLPropertyListConfiguration base, XMLPropertyListConf
}

private XMLPropertyListConfiguration loadConfig(File file) {
try {
try(Reader fr = new FileReader(file)) {
XMLPropertyListConfiguration plist = new XMLPropertyListConfiguration();
plist.read(new FileReader(file));
plist.read(fr);
return plist;
} catch (ConfigurationException e) {
throw new RuntimeException(String.format("Failed to parse plist '%s': %s", file.getAbsolutePath(), e.toString()));
} catch (FileNotFoundException e) {
throw new RuntimeException(String.format("File not found: %s", file.getAbsolutePath()));
} catch (IOException e) {
throw new RuntimeException(String.format("Exception when closing file %s", e.getMessage()));
}
}

Expand Down
2 changes: 1 addition & 1 deletion server/scripts/debug_defoldsdk.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
domain=os.environ.get("DM_ARCHIVE_DOMAIN", "d.defold.com")

def get_latest_version():
url = "http://d.defold.com/stable/info.json"
url = "https://d.defold.com/stable/info.json"
response = urllib.request.urlopen(url)
if response.getcode() == 200:
return json.loads(response.read())
Expand Down
28 changes: 16 additions & 12 deletions server/src/main/java/com/defold/extender/Extender.java
Original file line number Diff line number Diff line change
Expand Up @@ -219,17 +219,15 @@
baseVariantManifest = Extender.loadYaml(builder.jobDirectory, baseVariantFile, AppManifestConfiguration.class);
}
}
this.buildState = new ExtenderBuildState(builder, appManifest);

if (config.platforms.get(buildState.fullPlatform) == null) {
throw new ExtenderException(String.format("Unsupported platform %s by this sdk", buildState.fullPlatform));
if (config.platforms.get(builder.platform) == null) {
throw new ExtenderException(String.format("Unsupported platform %s by this sdk", builder.platform));
}

// Merge the platform configs from build.yml into a single instance: common -> platform -> arch-platform
this.platformConfig = new PlatformConfig();
this.platformConfig.context = new HashMap<>(config.context); // the context from build.yml

for (String platformAlt : ExtenderUtil.getPlatformAlternatives(buildState.fullPlatform)) {
for (String platformAlt : ExtenderUtil.getPlatformAlternatives(builder.platform)) {
PlatformConfig platformConfigAlt = config.platforms.get(platformAlt);
if (platformConfigAlt == null)
continue;
Expand All @@ -240,7 +238,7 @@
// Merge the variant info into a single config
this.platformVariantConfig = new PlatformConfig();
if (baseVariantManifest != null) {
for (String platformAlt : ExtenderUtil.getPlatformAlternatives(buildState.fullPlatform)) {
for (String platformAlt : ExtenderUtil.getPlatformAlternatives(builder.platform)) {
AppManifestPlatformConfig configAlt = baseVariantManifest.platforms.get(platformAlt);
if (configAlt == null)
continue;
Expand All @@ -251,7 +249,7 @@

// Merge the app manifest info into a single config
this.platformAppConfig = new PlatformConfig();
for (String platformAlt : ExtenderUtil.getPlatformAlternatives(buildState.fullPlatform)) {
for (String platformAlt : ExtenderUtil.getPlatformAlternatives(builder.platform)) {
AppManifestPlatformConfig configAlt = appManifest.platforms.get(platformAlt);
if (configAlt == null) {
continue;
Expand All @@ -261,17 +259,17 @@
ExtenderUtil.mergeObjects(this.platformAppConfig, platformConfigAlt);
}

LOGGER.info("Using context for platform: {}", buildState.fullPlatform);
LOGGER.info("Using context for platform: {}", builder.platform);

Check warning

Code scanning / CodeQL

Log Injection Medium

This log entry depends on a
user-provided value
.

processExecutor.setCwd(buildState.jobDir);
processExecutor.setCwd(builder.jobDirectory);

{
HashMap<String, Object> envContext = new HashMap<>();
envContext.put("build_folder", buildState.buildDir);
envContext.put("dynamo_home", buildState.sdk);
envContext.put("build_folder", builder.buildDirectory);
envContext.put("dynamo_home", builder.sdk);
envContext.put("env.LD_LIBRARY_PATH", "."); // Easier when running a standalone local without such a variable

processExecutor.putEnv("DYNAMO_HOME", buildState.sdk.getAbsolutePath());
processExecutor.putEnv("DYNAMO_HOME", builder.sdk.getAbsolutePath());
String java_home = System.getenv("JAVA_HOME");
if (java_home != null)
{
Expand Down Expand Up @@ -307,6 +305,12 @@
// The user input (ext.manifest + _app/app.manifest) will be checked against this validator
ExtensionManifestValidator manifestValidator = new ExtensionManifestValidator(new WhitelistConfig(), this.platformConfig.allowedFlags, allowedSymbols);

// Validate the top-level app.manifest context (e.g. debugSourcePath) before
// ExtenderBuildState reads any field from it.
manifestValidator.validateAppManifestContext(appManifest.context);

this.buildState = new ExtenderBuildState(builder, appManifest);

// Make sure the user hasn't input anything invalid in the manifest
manifestValidator.validate(this.appManifestPath, buildState.uploadDir, this.platformAppConfig.context);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ class ExtensionManifestValidator {
private final List<Pattern> allowedDefines = new ArrayList<>();
private final List<Pattern> allowedSymbols = new ArrayList<>();

private static final Pattern VALID_INCLUDE_PATH = Pattern.compile("^[A-Za-z0-9._+\\-/]+$");
private static final Pattern VALID_SYMBOL_IDENTIFIER = Pattern.compile("^[A-Za-z_][A-Za-z0-9_]*$");

ExtensionManifestValidator(WhitelistConfig whitelistConfig, List<String> allowedFlags, List<String> allowedSymbols) {
this.allowedDefines.add(WhitelistConfig.compile(whitelistConfig.defineRe));
this.allowedLibs.add(WhitelistConfig.compile(whitelistConfig.libraryRe));
Expand All @@ -32,8 +35,37 @@ private static boolean isListOfStrings(List<Object> list) {
return list != null && list.stream().allMatch(o -> o instanceof String);
}

// Validates the top-level app.manifest `context` map (the one read by
// ExtenderBuildState). Whitespace is intentionally rejected: the rendered
// command is split on spaces in ProcessExecutor.execute(String), so any
// space here would inject extra argv elements (compiler-flag injection).
void validateAppManifestContext(Map<String, Object> appContext) throws ExtenderException {
if (appContext == null) {
return;
}
Object debugSourcePath = appContext.get(ExtenderBuildState.APPMANIFEST_DEBUG_SOURCE_PATH);
if (debugSourcePath != null) {
if (!(debugSourcePath instanceof String)) {
throw new ExtenderException(String.format(
"Error in app.manifest: '%s' must be a string.",
ExtenderBuildState.APPMANIFEST_DEBUG_SOURCE_PATH));
}
String s = (String) debugSourcePath;
if (!s.isEmpty() && !VALID_INCLUDE_PATH.matcher(s).matches()) {
throw new ExtenderException(String.format(
"Error in app.manifest: invalid '%s' value '%s'. Allowed characters: letters, digits and '._+-/'.",
ExtenderBuildState.APPMANIFEST_DEBUG_SOURCE_PATH, s));
}
}
}

private void validateIncludePaths(String extensionName, File extensionFolder, List<String> includes) throws ExtenderException {
for (String include : includes) {
if (include == null || include.isEmpty() || !VALID_INCLUDE_PATH.matcher(include).matches()) {
throw new ExtenderException(String.format(
"Error in '%s': Invalid include path '%s'. Include paths may only contain letters, digits and '._+-/'.",
extensionName, include));
}
String[] tokens = include.split("/");
for (int i = 0; i < tokens.length; ++i)
{
Expand Down Expand Up @@ -98,6 +130,17 @@ void validate(String extensionName, File extensionFolder, Map<String, Object> co
continue;

case "symbols":
if (v instanceof List) {
for (String sym : (List<String>) v) {
if (sym == null || !VALID_SYMBOL_IDENTIFIER.matcher(sym).matches()) {
throw new ExtenderException(String.format(
"Error in '%s': Invalid symbol '%s'. Symbols must be valid C identifiers.",
extensionName, sym));
}
}
}
continue;

case "excludeLibs":
case "excludeJars":
case "excludeJsLibs":
Expand Down
Loading
Loading