-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
726 additions
and
155 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,27 @@ | ||
# platform_storage | ||
|
||
A Dart-only package for accessing platform-native storage functionality. | ||
Provides a unified API for accessing platform-native storage functionality, such as the iOS Keychain and Android SharedPreferences. | ||
Sync and async APIs are provided for all storage operations, where asynchronous APIs use an `Isolate` to perform the operation in | ||
a background thread. | ||
|
||
> See [Web support](#Web) below for more info on how this package behaves in a browser environment. | ||
## `PlatformStorage` | ||
|
||
All implementations conform to the `PlatformStorage` interface, which provides a simple API for reading and writing key-value pairs. | ||
|
||
There are two flavors of `PlatformStorage` currently: `PlatformLocalStorage` and `PlatformSecureStorage`. Both are constructed with | ||
a required `namespace` parameter and optional `scope`. The `namespace` represents the isolation boundary of the storage values, while | ||
the `scope` is used to separate storage data between different parts of the app, | ||
|
||
It is recommended to use your application or bundle identifier as the `namespace`. | ||
|
||
### `PlatformLocalStorage` | ||
|
||
The local storage APIs are useful for storing non-sensitive data that should persist across app restarts and be deleted alongside the app. | ||
|
||
The platform implementations for `PlatformLocalStorage` are: | ||
- **iOS/macOS**: The `UserDefaults` API with a [suite name](https://developer.apple.com/documentation/foundation/nsuserdefaults/1409957-initwithsuitename#discussion) of `namespace<.scope>`. | ||
- **Android**: The `SharedPreferences` API with a [name](https://developer.android.com/reference/android/content/Context.html#getSharedPreferences(java.lang.String,%20int)) of `namespace<.scope>`. | ||
- **Linux**: The `gsettings` API with a schema path of `namespace<.scope>`. | ||
- **Windows**: The `Windows.Storage.ApplicationData.Current.LocalSettings` API with a container name of `namespace<.scope>`. |
61 changes: 61 additions & 0 deletions
61
packages/platform/storage/lib/src/local/local_storage.linux.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import 'dart:convert'; | ||
import 'dart:io'; | ||
|
||
import 'package:native_synchronization/primitives.dart'; | ||
import 'package:path/path.dart' as p; | ||
import 'package:platform_storage/src/local/local_storage_platform.vm.dart'; | ||
import 'package:platform_storage/src/native/windows/windows_paths.dart'; | ||
|
||
final class LocalStoragePlatformLinux extends LocalStoragePlatform { | ||
LocalStoragePlatformLinux({ | ||
required super.namespace, | ||
super.scope, | ||
}) : super.base(); | ||
|
||
final Mutex _mutex = Mutex(); | ||
late final String _storagePath = p.joinAll([ | ||
// The RoamingAppData folder | ||
PathProviderWindows.getApplicationSupportPath()!, | ||
if (scope != null) '$namespace.$scope.json' else '$namespace.json', | ||
]); | ||
late final File _storage = File(_storagePath); | ||
|
||
Map<String, String> _readData() { | ||
if (!_storage.existsSync()) { | ||
return {}; | ||
} | ||
return (jsonDecode(_storage.readAsStringSync()) as Map).cast(); | ||
} | ||
|
||
void _writeData(Map<String, String> data) { | ||
if (!_storage.existsSync()) { | ||
_storage.createSync(recursive: true); | ||
} | ||
_storage.writeAsStringSync(jsonEncode(data)); | ||
} | ||
|
||
@override | ||
void clear() => _mutex.runLocked(() { | ||
if (_storage.existsSync()) { | ||
_storage.deleteSync(); | ||
} | ||
}); | ||
|
||
@override | ||
String? delete(String key) => _mutex.runLocked(() { | ||
final data = _readData(); | ||
final value = data.remove(key); | ||
_writeData(data); | ||
return value; | ||
}); | ||
|
||
@override | ||
String? read(String key) => _mutex.runLocked(() => _readData()[key]); | ||
|
||
@override | ||
String write(String key, String value) => _mutex.runLocked(() { | ||
final data = _readData()..[key] = value; | ||
_writeData(data); | ||
return value; | ||
}); | ||
} |
69 changes: 30 additions & 39 deletions
69
packages/platform/storage/lib/src/local/local_storage.windows.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,59 +1,50 @@ | ||
import 'dart:convert'; | ||
import 'dart:io'; | ||
|
||
import 'package:path/path.dart' as p; | ||
import 'package:platform_storage/src/native/windows/windows_paths.dart'; | ||
import 'package:platform_storage/src/secure/secure_storage_platform.vm.dart'; | ||
import 'package:windows_storage/windows_storage.dart'; | ||
|
||
final class SecureStoragePlatformWindows extends SecureStoragePlatform { | ||
SecureStoragePlatformWindows({ | ||
final class LocalStoragePlatformWindows extends SecureStoragePlatform { | ||
LocalStoragePlatformWindows({ | ||
required super.namespace, | ||
super.scope, | ||
}) : super.base(); | ||
|
||
late final String _storagePath = p.joinAll([ | ||
// The RoamingAppData folder | ||
PathProviderWindows.getApplicationSupportPath()!, | ||
if (scope != null) ...[namespace, '$scope.json'] else '$namespace.json', | ||
]); | ||
late final File _storage = File(_storagePath); | ||
final _settings = ApplicationData.current!.roamingSettings!; | ||
late final _container = scope == null | ||
? _settings | ||
: _settings.createContainer( | ||
scope!, | ||
ApplicationDataCreateDisposition.always, | ||
)!; | ||
|
||
Map<String, String> _readData() { | ||
if (!_storage.existsSync()) { | ||
return {}; | ||
} | ||
return (jsonDecode(_storage.readAsStringSync()) as Map).cast(); | ||
} | ||
|
||
void _writeData(Map<String, String> data) { | ||
if (!_storage.existsSync()) { | ||
_storage.createSync(recursive: true); | ||
} | ||
_storage.writeAsStringSync(jsonEncode(data)); | ||
@override | ||
String? delete(String key) { | ||
final stored = read(key); | ||
_container.values!.remove(key); | ||
return stored; | ||
} | ||
|
||
@override | ||
void clear() { | ||
if (_storage.existsSync()) { | ||
_storage.deleteSync(); | ||
} | ||
} | ||
String? read(String key) => _container.values!.lookup(key) as String?; | ||
|
||
@override | ||
String? delete(String key) { | ||
final data = _readData(); | ||
final value = data.remove(key); | ||
_writeData(data); | ||
String write(String key, String value) { | ||
_container.values!.insert(key, value); | ||
return value; | ||
} | ||
|
||
@override | ||
String? read(String key) => _readData()[key]; | ||
void clear() { | ||
for (final key in _container.values!.getView().keys) { | ||
_container.values!.remove(key); | ||
} | ||
if (scope case final scope?) { | ||
_settings.deleteContainer(scope); | ||
} | ||
} | ||
|
||
@override | ||
String write(String key, String value) { | ||
final data = _readData()..[key] = value; | ||
_writeData(data); | ||
return value; | ||
void close() { | ||
_container.close(); | ||
_settings.close(); | ||
super.close(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
43 changes: 43 additions & 0 deletions
43
packages/platform/storage/lib/src/native/windows/winrt/helpers.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import 'dart:ffi'; | ||
|
||
import 'package:win32/win32.dart'; | ||
|
||
/// @nodoc | ||
typedef IUnknown_AddRef_Native = Uint32 Function(VTablePointer lpVtbl); | ||
|
||
/// @nodoc | ||
typedef IUnknown_Release_Native = IUnknown_AddRef_Native; | ||
|
||
/// @nodoc | ||
typedef IUnknown_QueryInterface_Native = HRESULT Function( | ||
VTablePointer lpVtbl, Pointer<GUID> riid, Pointer<VTablePointer> ppvObject); | ||
|
||
/// @nodoc | ||
final class IUnknownVtbl extends Struct { | ||
external Pointer<NativeFunction<IUnknown_QueryInterface_Native>> | ||
QueryInterface; | ||
external Pointer<NativeFunction<IUnknown_AddRef_Native>> AddRef; | ||
external Pointer<NativeFunction<IUnknown_Release_Native>> Release; | ||
} | ||
|
||
/// @nodoc | ||
typedef IInspectable_GetIids_Native = HRESULT Function(VTablePointer lpVtbl, | ||
Pointer<Uint32> iidCount, Pointer<Pointer<GUID>> iids); | ||
|
||
/// @nodoc | ||
typedef IInspectable_GetRuntimeClassName_Native = HRESULT Function( | ||
VTablePointer lpVtbl, Pointer<IntPtr> className); | ||
|
||
/// @nodoc | ||
typedef IInspectable_GetTrustLevel_Native = HRESULT Function( | ||
VTablePointer lpVtbl, Pointer<Int32> trustLevel); | ||
|
||
/// @nodoc | ||
final class IInspectableVtbl extends Struct { | ||
external IUnknownVtbl baseVtbl; | ||
external Pointer<NativeFunction<IInspectable_GetIids_Native>> GetIids; | ||
external Pointer<NativeFunction<IInspectable_GetRuntimeClassName_Native>> | ||
GetRuntimeClassName; | ||
external Pointer<NativeFunction<IInspectable_GetTrustLevel_Native>> | ||
GetTrustLevel; | ||
} |
66 changes: 66 additions & 0 deletions
66
packages/platform/storage/lib/src/native/windows/winrt/icredentialfactory.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
// Copyright (c) 2023, Dart | Windows. Please see the AUTHORS file for details. | ||
// All rights reserved. Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
// THIS FILE IS GENERATED AUTOMATICALLY AND SHOULD NOT BE EDITED DIRECTLY. | ||
|
||
// ignore_for_file: constant_identifier_names, non_constant_identifier_names | ||
// ignore_for_file: unnecessary_import, unused_import | ||
|
||
import 'dart:async'; | ||
import 'dart:ffi'; | ||
|
||
import 'package:ffi/ffi.dart'; | ||
import 'package:platform_storage/src/native/windows/winrt/helpers.dart'; | ||
import 'package:win32/win32.dart' | ||
hide DocumentProperties, WinRTStringConversion; | ||
import 'package:windows_foundation/internal.dart'; | ||
import 'package:windows_foundation/windows_foundation.dart'; | ||
|
||
import 'passwordcredential.dart'; | ||
|
||
/// @nodoc | ||
const IID_ICredentialFactory = '{54ef13a1-bf26-47b5-97dd-de779b7cad58}'; | ||
|
||
class ICredentialFactory extends IInspectable { | ||
ICredentialFactory.fromPtr(super.ptr) | ||
: _vtable = ptr.ref.vtable.cast<_ICredentialFactoryVtbl>().ref; | ||
|
||
final _ICredentialFactoryVtbl _vtable; | ||
|
||
factory ICredentialFactory.from(IInspectable interface) => | ||
interface.cast(ICredentialFactory.fromPtr, IID_ICredentialFactory); | ||
|
||
PasswordCredential createPasswordCredential( | ||
String resource, String userName, String password) { | ||
final credential = calloc<COMObject>(); | ||
|
||
final hr = _vtable.CreatePasswordCredential.asFunction< | ||
int Function(VTablePointer lpVtbl, int resource, int userName, | ||
int password, Pointer<COMObject> credential)>()( | ||
lpVtbl, | ||
resource.toHString(), | ||
userName.toHString(), | ||
password.toHString(), | ||
credential); | ||
|
||
if (FAILED(hr)) { | ||
free(credential); | ||
throwWindowsException(hr); | ||
} | ||
|
||
return PasswordCredential.fromPtr(credential); | ||
} | ||
} | ||
|
||
final class _ICredentialFactoryVtbl extends Struct { | ||
external IInspectableVtbl baseVtbl; | ||
external Pointer< | ||
NativeFunction< | ||
HRESULT Function( | ||
VTablePointer lpVtbl, | ||
IntPtr resource, | ||
IntPtr userName, | ||
IntPtr password, | ||
Pointer<COMObject> credential)>> CreatePasswordCredential; | ||
} |
Oops, something went wrong.