エンタープライズ機能
Tracelet には、軍事追跡、HIPAA 準拠の患者監視、暗号化検証された物流などの企業ユースケース向けに設計されたいくつかの高度なセキュリティ機能が搭載されています。
1. データ暗号化 (SQLCipher)
Tracelet がバックグラウンドで位置を記録する場合、サーバーと同期する前に、その位置を内部 SQLite データベースに一時的に保存します。デバイスが盗まれた場合、物理的なアクセスによって攻撃者がこれらの履歴ルートを読み取る可能性があります。
Tracelet は、SQLCipher を使用した 保存時のデータベース暗号化 を提供することでこの問題を解決します。
データ暗号化の仕組み
encryptDatabaseフラグを有効にすると、基礎となる Rust SQLite データベースが SQLCipher を介して AES-256 で即座に暗号化されます。- デフォルトでは、Tracelet は安全な 256 ビット キーを自動的に生成し、プラットフォームのネイティブの安全なストレージ (Android キーストア / iOS キーチェーン) に安全に保存します。キーを手動で管理する必要はありません。
- ディスクに書き込まれたすべてのデータは、キーがなければ完全に読み取ることができなくなります。
- フラグが有効になると、既存の暗号化されていないデータベースは自動的に暗号化されたデータベースに移行されます。
実装
プラットフォーム管理のセキュア キーを使用して暗号化を有効にするには (推奨):
final config = Config.balanced(
security: tl.SecurityConfig(
encryptDatabase: true, // This MUST be true to enable encryption
),
);カスタムキー管理 (上級)
アプリが独自のキーマテリアルを管理することを希望する場合 (例: flutter_secure_storage を使用)、カスタムの encryptionKey を提供できます。 encryptDatabase 依然として true である必要があることに注意してください。
// Generate a secure random key
final customKey = await tl.Tracelet.generateEncryptionKey();
await secureStorage.write(key: 'my_db_key', value: customKey);
// Pass it to Tracelet
final config = Config.balanced(
security: tl.SecurityConfig(
encryptDatabase: true,
encryptionKey: await secureStorage.read(key: 'my_db_key'),
),
);2. 監査証跡の管理と検証
機密性の高い物流や法執行機関では、位置記録が改ざん、なりすまし、事後変更されていないことを数学的に証明できなければなりません。 Tracelet は、暗号化された保管チェーンを作成するための 監査証跡 機能を提供します。
監査証跡管理の仕組み
AuditConfig.enabled が true に設定されている場合、Tracelet は緯度と経度を保存するだけではありません。あらゆる場所に「ブロックチェーンのような」レコードを作成します。基盤となる Rust エンジンは、このプロセスがアトミックかつ確実であることを保証します。
- ジェネシス ブロック: エンジンが新しいデバイスで最初に起動すると、ジェネシス ハッシュ
SHA-256("tracelet:genesis:{device_id}")が計算されます。 - 正規文字列生成: 場所ごとに、Tracelet は以前のハッシュと新しい場所の正確なデータを組み合わせた厳密で決定的な文字列形式を生成します。
- ハッシュ: この正規文字列はハッシュされ (デフォルトでは SHA-256 を使用)、現在の場所の
hashが生成されます。 - チェーン: このハッシュは次の場所の
previous_hashとなり、切れ目のないチェーンが作成されます。攻撃者がデータベース内の過去の位置の座標を 1 つでも変更すると、その位置のハッシュが変更され、後続のハッシュのチェーン全体が破壊されます。
構成
final config = Config.highAccuracy(
audit: tl.AuditConfig(
enabled: true,
hashAlgorithm: tl.HashAlgorithm.sha256,
),
);JSON ペイロード
Tracelet がこれらの場所をバックエンドに同期すると、各場所の JSON ペイロードには監査フィールドが直接含まれます。
{
"device": "tracelet-example",
"locationCount": 1,
"locations": [
{
"uuid": "loc-1234-abcd",
"timestamp": "2024-01-01T00:00:00Z",
"is_moving": true,
"coords": {
"latitude": 37.774900,
"longitude": -122.419400,
"accuracy": 10.0,
"speed": 15.5,
"heading": 90.0,
"altitude": 100.0
},
"audit_hash": "a1b2c3d4e5f6...",
"audit_previous_hash": "f6e5d4c3b2a1...",
"audit_chain_index": 42
}
]
}サーバー側の検証 (コードの検証方法)
サーバー上のデータの整合性を検証するには、Tracelet Rust コアが使用する正確な正規文字列を再作成し、結果のハッシュをペイロードの audit_hash フィールドと比較する必要があります。
1. 正規文字列を構築する
文字列は、パイプ | 文字で区切って、次のように正確にフォーマットする必要があります。
翻訳されない
重要な書式設定ルール (Tracelet の Rust コアに基づく):
latitudeおよびlongitude: 小数点以下 6 桁に正確にフォーマットされます (例:37.774900)。accuracy、speed、heading、altitude: 小数点以下 2 桁に正確にフォーマットされます (例:10.00)。is_moving:1(true) または0(false) としてフォーマットされます。
正規文字列の例:
f6e5d4c3b2a1...|TRACELET_AUDIT|42|loc-1234-abcd|37.774900|-122.419400|2024-01-01T00:00:00Z|10.00|15.50|90.00|100.00|12. ハッシュと比較
構築された正規文字列を標準の SHA-256 ハッシュ関数に渡し、小文字の 16 進文字列に変換します。
- 計算されたハッシュが
audit_hashフィールドと 一致する場合: その場所は数学的に改ざんされていないことが証明されています。 - 一致しない場合: 位置データが変更されています。すぐにこのレコードにフラグを立てて、デバイスを調査する必要があります。
3. 位置精度プロファイル (HF / LF)
Tracelet サンプル アプリを確認すると、LF Accuracy と HF Accuracy のボタンに気づくでしょう。これらは、Tracelet の事前構築された構成プロファイルに直接マッピングされます。
- LF (低周波数 / 低精度): これは
Config.lowPower()プロファイルにマッピングされます。これは、エンジンがセルタワーと Wi-Fi 三角測量のみを使用するように制限します (GPS は使用しません)。バッテリー効率が高く、より広い精度範囲を提供します。 - HF (高周波/高精度): これは
Config.highAccuracy()プロファイルにマッピングされます。物理的な GPS チップを強制的にオンにし、バッテリーの消耗が大きくなる代わりに 1 ~ 5 メートルの精度を提供します。
4. 二酸化炭素排出量の推定と旅行レポート
Tracelet には、組み込みの CarbonEstimator ユーティリティが含まれています。アクティビティ認識 (ユーザーが運転、歩行、またはサイクリングしているかどうかの検出) と正確な地理的距離を融合して、旅行の推定 CO₂ 排出量を計算します。これは、持続可能性報告、カーボン オフセット プログラム、または ESG (環境、社会、ガバナンス) コンプライアンスにとって非常に重要です。
仕組み
CarbonEstimatorをインスタンス化します。- ユーザーが移動を開始すると (
isMoving == true)、startTrip()を呼び出します。 - リアルタイムのアクティビティの変化 (歩行から運転への切り替えなど) と位置を推定器に入力します。
- ユーザーが移動を停止したとき (
isMoving == false)、endTrip()を呼び出してTripCarbonSummaryを生成します。
実装例
final carbonEstimator = tl.CarbonEstimator();
// 1. Listen for motion changes to start and end trips
Tracelet.onMotionChange((loc) {
if (loc.isMoving) {
carbonEstimator.startTrip();
} else {
final summary = carbonEstimator.endTrip();
if (summary != null) {
print('Trip ended: \${summary.totalCarbonGrams}g CO2');
print('Total Distance: \${summary.totalDistanceMeters}m');
print('Dominant Mode: \${summary.dominantMode}'); // e.g. "driving"
}
}
});
// 2. Feed Activity Recognition data to detect the transport mode
Tracelet.onActivityChange((evt) {
// Activity names map to emissions factors internally (e.g., driving vs walking)
carbonEstimator.setActivity(evt.activity.name);
});
// 3. Feed location coordinates to accumulate distance accurately
Tracelet.onLocation((loc) {
carbonEstimator.onLocationReceived(
loc.coords.latitude,
loc.coords.longitude,
);
});結果の TripCarbonSummary は、サーバーに同期したり、ユーザーに直接表示して、環境に優しい交通手段の選択を促すことができます。
5. リモート設定
3.6.2 以降、iOS と Android の両方でネイティブに取得および適用されます。以前のバージョンは remoteConfigUrl を受け入れましたが、それを取得することはありませんでした。ネイティブ側は暗黙的にローカル構成にフォールバックしました。
フリートや大規模な展開では、アプリのアップデートを配布せずに、精度、同期頻度、ジオフェンスの半径、バッテリーの割り当てなど、追跡動作を変更する必要があることがよくあります。 Tracelet の リモート構成 を使用すると、SDK が独自の HTTPS エンドポイントから構成ドキュメントを取得し、実行時にローカル構成の上に適用できます。
リモート構成の仕組み
AppConfigでremoteConfigUrl(およびオプションのヘッダー) を設定します。ready()では、SDK は最初にデバイス上のキャッシュから最後に正常に取得された 構成を適用します。そのため、ネットワーク呼び出しの前に、ready()をブロックすることなく、最新の公開設定で再起動が即座にオフラインで再開されます。- 次に、バックグラウンドのエンドポイントから新しいコピーをフェッチし、
setConfig()と同じランタイム パスを通じて適用します。これにより、追跡関連のキーが実際に変更された場合にのみ、アクティブな追跡パイプラインが再起動されます。 remoteConfigRefreshInterval周期 (分単位) で再取得することにより、構成を最新の状態に保ちます。
HTTPS URL のみが受け入れられます。http:// URL は拒否され、ログに記録されます。これは、設定によって追跡動作が制御され、転送中に改ざんされてはいけないためです。
エンドポイント契約
エンドポイントは、Tracelet 構成マップのような形の JSON オブジェクト (フラット、または Config.toMap() が生成する ネストされた { "geo": {…}, "app": {…}, "http": {…} } フォーム) で GET に応答します。含めたキーのみがオーバーライドされます。他の設定はすべてローカル値を保持します。
{
"geo": { "distanceFilter": 25.0, "desiredAccuracy": 0 },
"app": { "heartbeatInterval": 120 },
"http": { "autoSync": true }
}構成
final config = Config.balanced().copyWith(
app: tl.AppConfig(
remoteConfigUrl: 'https://config.mycompany.com/tracelet/fleet-a.json',
remoteConfigHeaders: {'Authorization': 'Bearer $token'},
remoteConfigTimeout: 15000, // milliseconds
remoteConfigRefreshInterval: 60, // minutes
),
);| フィールド | タイプ | デフォルト | 説明 |
|---|---|---|---|
| 非トランスレート | 翻訳1遅れ | null | JSON 構成マップを返す HTTPS エンドポイント。 null はリモート構成を無効にします。 |
| 非トランスレート | 翻訳1遅れ | null | フェッチとともに送信されるヘッダー (認証トークンなど)。 |
| 非トランスレート | 翻訳1遅れ | 60000 | フェッチタイムアウトをミリ秒単位で指定します。 |
| 非トランスレート | 翻訳1遅れ | 1440 | バックグラウンド更新間の分数 (ネイティブでは 15 分に設定されています)。 0 は 1 回フェッチすると、繰り返されません。 |
適用されたリモート値はデバイスの永続化された設定にマージされ、リモートのオーバーライドがローカルの値よりも優先されます。その URL を取得する すべて のデバイスが採用することを意図した値のみを公開します。各ビルドを異なる URL に指定することで、フリートごとまたはコホートごとにスコープを設定します。
Dart から適用されたリモート設定を観察する
リモート構成が取得され、ネイティブ側に適用されます。 3.6.10 以降、リモート オーバーライドが適用されるたびに (ready() で復元されたキャッシュされたコピーと 各バックグラウンド更新の両方)、SDK はそれを Dart に表示します。
Tracelet.activeConfig(したがってtracelet_doctorと Dart 側のバッテリー予算エンジン) は、ローカルに設定した最後の設定だけではなく、フェッチされた値を反映するようになりました。- サーバー主導の変更が発生したときに反応するようにサブスクライブします。
// Callback — fires after a remote override is applied.
// Tracelet.activeConfig already reflects the new values when this fires.
Tracelet.onRemoteConfig((Config config) {
print('Remote battery budget: ${config.geo.batteryBudgetPerHour}%/hr');
});
// …or listen to the broadcast stream directly.
final sub = Tracelet.remoteConfigStream.listen((config) {
// react to the merged, now-active config
});3.6.10 より前では、リモート値はネイティブ トラッキングに適用されていましたが、Tracelet.activeConfig にはミラーリングされなかったので、トラッキングですでにリモート値が使用されていたとしても、診断ではローカルに設定された最後の値が表示されることがありました。