implement Milestone 15: sensor interface with fingerprinting prevention

This commit is contained in:
2026-01-18 16:14:18 +01:00
parent 779f66b2bb
commit 4ab5e52259
6 changed files with 1258 additions and 1 deletions

View File

@@ -28,6 +28,7 @@ add_library(mosis-sandbox STATIC
../src/main/cpp/sandbox/microphone_interface.cpp
../src/main/cpp/sandbox/audio_output.cpp
../src/main/cpp/sandbox/location_interface.cpp
../src/main/cpp/sandbox/sensor_interface.cpp
)
target_include_directories(mosis-sandbox PUBLIC
../src/main/cpp/sandbox

View File

@@ -18,6 +18,7 @@
#include "microphone_interface.h"
#include "audio_output.h"
#include "location_interface.h"
#include "sensor_interface.h"
#include <filesystem>
#include <fstream>
#include <sstream>
@@ -2519,6 +2520,173 @@ bool Test_LocationLuaIntegration(std::string& error_msg) {
return true;
}
//=============================================================================
// Milestone 15: Sensors
//=============================================================================
bool Test_SensorRequiresPermission(std::string& error_msg) {
mosis::SensorInterface sensors("test.app");
// No permissions granted
std::string err;
auto sub = sensors.Subscribe("accelerometer", {}, err);
EXPECT_TRUE(sub == nullptr);
EXPECT_TRUE(err.find("permission") != std::string::npos);
return true;
}
bool Test_SensorAutoGrantsEnvironmental(std::string& error_msg) {
mosis::SensorInterface sensors("test.app");
// No motion permission
std::string err;
// Proximity should work without permission
auto proxSub = sensors.Subscribe("proximity", {}, err);
EXPECT_TRUE(proxSub != nullptr);
EXPECT_TRUE(proxSub->IsActive());
// Light should work without permission
auto lightSub = sensors.Subscribe("light", {}, err);
EXPECT_TRUE(lightSub != nullptr);
EXPECT_TRUE(lightSub->IsActive());
return true;
}
bool Test_SensorReducesPrecision(std::string& error_msg) {
mosis::SensorInterface sensors("test.app");
sensors.SetMotionPermission(true);
std::string err;
auto sub = sensors.Subscribe("accelerometer", {}, err);
EXPECT_TRUE(sub != nullptr);
mosis::SensorData received;
bool got_data = false;
sub->SetOnData([&](const mosis::SensorData& data) {
got_data = true;
received = data;
});
// Simulate high-precision data
mosis::SensorData precise;
precise.x = 9.80665123456;
precise.y = 0.12345678901;
precise.z = -0.98765432109;
precise.timestamp = 1234567890;
// Apply precision reduction manually (as SimulateData bypasses it)
mosis::SensorData reduced = sensors.ApplyPrecision(precise);
sub->SimulateData(reduced);
EXPECT_TRUE(got_data);
// Values should be rounded to 2 decimal places
EXPECT_TRUE(std::abs(received.x - 9.81) < 0.001);
EXPECT_TRUE(std::abs(received.y - 0.12) < 0.001);
EXPECT_TRUE(std::abs(received.z - (-0.99)) < 0.001);
return true;
}
bool Test_SensorLimitsFrequency(std::string& error_msg) {
mosis::SensorInterface sensors("test.app");
sensors.SetMotionPermission(true);
mosis::SensorOptions options;
options.frequency = 120; // Request 120 Hz
std::string err;
auto sub = sensors.Subscribe("gyroscope", options, err);
EXPECT_TRUE(sub != nullptr);
// Should be capped at 60 Hz
EXPECT_TRUE(sub->GetFrequency() <= 60);
return true;
}
bool Test_SensorSubscriptionLimit(std::string& error_msg) {
mosis::SensorInterface sensors("test.app");
sensors.SetMotionPermission(true);
std::vector<std::shared_ptr<mosis::SensorSubscription>> subs;
std::string err;
// Create MAX_SUBSCRIPTIONS (10)
for (int i = 0; i < 10; i++) {
auto sub = sensors.Subscribe("accelerometer", {}, err);
EXPECT_TRUE(sub != nullptr);
subs.push_back(sub);
}
// 11th should fail
auto extra = sensors.Subscribe("accelerometer", {}, err);
EXPECT_TRUE(extra == nullptr);
EXPECT_TRUE(err.find("limit") != std::string::npos ||
err.find("maximum") != std::string::npos);
return true;
}
bool Test_SensorCleansUpOnShutdown(std::string& error_msg) {
mosis::SensorInterface sensors("test.app");
sensors.SetMotionPermission(true);
std::string err;
auto sub1 = sensors.Subscribe("accelerometer", {}, err);
auto sub2 = sensors.Subscribe("gyroscope", {}, err);
EXPECT_TRUE(sensors.GetActiveSubscriptionCount() == 2);
sensors.Shutdown();
EXPECT_TRUE(sensors.GetActiveSubscriptionCount() == 0);
EXPECT_TRUE(!sub1->IsActive());
EXPECT_TRUE(!sub2->IsActive());
return true;
}
bool Test_SensorLuaIntegration(std::string& error_msg) {
SandboxContext ctx = TestContext();
LuaSandbox sandbox(ctx);
mosis::SensorInterface sensors("test.app");
mosis::RegisterSensorAPI(sandbox.GetState(), &sensors);
std::string script = R"lua(
-- Test that sensors global exists
if not sensors then
error("sensors global not found")
end
if not sensors.subscribe then
error("sensors.subscribe not found")
end
if not sensors.unsubscribeAll then
error("sensors.unsubscribeAll not found")
end
if not sensors.getSubscriptionCount then
error("sensors.getSubscriptionCount not found")
end
-- Subscription count should be 0 initially
if sensors.getSubscriptionCount() ~= 0 then
error("should have no active subscriptions initially")
end
)lua";
bool ok = sandbox.LoadString(script, "sensor_test");
if (!ok) {
error_msg = "Lua test failed: " + sandbox.GetLastError();
return false;
}
return true;
}
//=============================================================================
// MAIN
//=============================================================================
@@ -2693,6 +2861,15 @@ int main(int argc, char* argv[]) {
harness.AddTest("LocationCleansUpOnShutdown", Test_LocationCleansUpOnShutdown);
harness.AddTest("LocationLuaIntegration", Test_LocationLuaIntegration);
// Milestone 15: Sensors
harness.AddTest("SensorRequiresPermission", Test_SensorRequiresPermission);
harness.AddTest("SensorAutoGrantsEnvironmental", Test_SensorAutoGrantsEnvironmental);
harness.AddTest("SensorReducesPrecision", Test_SensorReducesPrecision);
harness.AddTest("SensorLimitsFrequency", Test_SensorLimitsFrequency);
harness.AddTest("SensorSubscriptionLimit", Test_SensorSubscriptionLimit);
harness.AddTest("SensorCleansUpOnShutdown", Test_SensorCleansUpOnShutdown);
harness.AddTest("SensorLuaIntegration", Test_SensorLuaIntegration);
// Run tests
auto results = harness.Run(filter);