Skip to content

Conversation

@kirre-bylund
Copy link
Contributor

File Configurable SDK

This is the first step of the publisher package. What it does is it allows for a .bytes file to be automatically read by the SDK on boot. If it exists, then that file is used to set the LootLocker SDK configuration.

Solves issue: https://github.com/lootlocker/index/issues/1260

Changes

  • Added LootLockerExternalFileConfig as a json serializable version of LootLockerConfig
  • Made the "package name" of the SDK configurable
  • Prepended Logs with a configurable label
  • Made LootLockerConfig look in a predictable directory for a file config on start. If it exists, then that overrides configuration.
  • Removed LootLocker mentions in logs unless specifically needed for the log
  • Added encryption utilities
  • Restructured LootLockerConfig.cs a bit

Extra Features

  • On top of the strictly necessary features I added the ability to add an identifier in addition to the "package name" allowing for quick switching between multiple configurations in a simpler way.
  • Added very basic (just a deterrent) encryption of the config file so that it is not straight up readable from disk
  • Allowed for the config file to be either encrypted or not, both can be parsed

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds support for external file-based configuration of the LootLocker SDK, allowing settings to be loaded from a .bytes file at initialization. The implementation includes optional encryption for the configuration file and makes the SDK package name configurable.

Changes:

  • Introduced ExternalFileConfig class for JSON-serializable SDK configuration
  • Added encryption utilities for optional config file obfuscation
  • Refactored LootLockerConfig to check for and load external file configurations on initialization
  • Updated log messages throughout the SDK to remove hardcoded "LootLocker" references, making them more generic

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
Runtime/Game/Utilities/LootLockerEncryptionUtilities.cs Implements AES encryption/decryption utilities for config files
Runtime/Game/Utilities/LootLockerEncryptionUtilities.cs.meta Unity metadata for encryption utilities
Runtime/Game/Resources/LootLockerExternalFileConfig.cs Defines serializable external configuration structure
Runtime/Game/Resources/LootLockerExternalFileConfig.cs.meta Unity metadata for external config
Runtime/Game/Resources/LootLockerConfig.cs Refactored to support file-based configuration loading with encryption support
Runtime/Game/Requests/WhiteLabelRequest.cs Updated error messages to remove "LootLocker" prefix
Runtime/Game/LootLockerSDKManager.cs Updated log messages for generic SDK references
Runtime/Game/LootLockerLogger.cs Added configurable log label functionality
Runtime/Editor/LogViewer/LootLockerLogViewerUI.cs Updated to handle new log label format
Runtime/Editor/Editor UI/LootLockerAdminExtension.cs Fixed formatting spacing
Runtime/Client/LootLockerLifecycleManager.cs Updated initialization log message
Runtime/Client/LootLockerHTTPClient.cs Updated HTTP client log messages
Runtime/Client/LootLockerEventSystem.cs Updated event system log message

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +9 to +12
private static readonly byte[] Key = {
0x81, 0x71, 0xF7, 0xD6, 0xE5, 0xC4, 0xB3, 0xA2,
0x8A, 0x9B, 0xAC, 0xBD, 0xCE, 0xDF, 0xE0, 0xF1
};
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hardcoded encryption key is embedded directly in the source code and will be visible in compiled assemblies. This provides minimal security as the key can be extracted through decompilation. Consider using a key derivation function or storing the key more securely, or document that this is intentionally basic encryption (as mentioned in the PR description) and should not be relied upon for security-critical data.

Copilot uses AI. Check for mistakes.
// If directory does not exist, create it
if (!Directory.Exists(ConfigResourceFolder))
{
Directory.CreateDirectory(ConfigResourceFolder);
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Directory creation can fail due to permissions or invalid paths. Add error handling with a meaningful error message to help developers diagnose issues when the config directory cannot be created.

Suggested change
Directory.CreateDirectory(ConfigResourceFolder);
try
{
Directory.CreateDirectory(ConfigResourceFolder);
}
catch (Exception ex)
{
Debug.LogError($"Failed to create config directory at path '{ConfigResourceFolder}'. Config asset will not be created. Exception: {ex}");
return;
}

Copilot uses AI. Check for mistakes.
Comment on lines +157 to +158
catch (Exception)
{
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The catch block silently swallows all exceptions without logging. This makes debugging configuration issues difficult. Consider logging the exception details or at minimum a warning message when file config loading fails.

Suggested change
catch (Exception)
{
catch (Exception ex)
{
Debug.LogWarning($"Failed to load external LootLocker config from file '{ConfigFilePath}'. Using default configuration instead. Exception: {ex}");

Copilot uses AI. Check for mistakes.
_current.ConstructUrls();
return _current;
}

Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing documentation for this important method. Add a summary comment explaining when this method is called, what it returns, and how it handles both encrypted and unencrypted config files.

Suggested change
/// <summary>
/// Attempts to load configuration values from an external config file in the Resources/Config folder.
/// Called by the configuration initialization logic before falling back to the ScriptableObject asset.
/// Returns a deserialized <see cref="ExternalFileConfig"/> when a valid config file with a non-empty api_key is found,
/// or null when the file is missing, invalid, or does not contain a usable api_key.
/// Handles both unencrypted JSON and encrypted config files: non-base64 content is treated as plain JSON,
/// while valid base64 content is decrypted before deserialization. Any exceptions during loading or
/// deserialization are caught and result in the method returning the last successfully read value or null.
/// </summary>

Copilot uses AI. Check for mistakes.
}
return fileConfig;
}

Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing documentation for this method. Add a summary comment explaining when this method is called and what it creates.

Suggested change
/// <summary>
/// Creates a new <see cref="LootLockerConfig"/> asset in the configured Resources path
/// when no existing configuration asset can be found, and assigns it to <c>_current</c>.
/// </summary>

Copilot uses AI. Check for mistakes.
{
// Skip regular HTTP log lines (let the enriched HTTP log handle it)
if (message.StartsWith("[LL HTTP]") || message.StartsWith("[LL HTTP RESPONSE]"))
if (message.Contains("[HTTP]") || message.Contains("[HTTP RESPONSE]"))
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using Contains for prefix matching is less precise than StartsWith. If the intent is to filter HTTP log lines, consider using StartsWith with the log label to avoid false positives from messages that happen to contain "[HTTP]" elsewhere in the text.

Suggested change
if (message.Contains("[HTTP]") || message.Contains("[HTTP RESPONSE]"))
if (message.StartsWith("[HTTP]") || message.StartsWith("[HTTP RESPONSE]"))

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant