From 869442ca93d783c66cd7a13f501d69ad56f99138 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Tue, 3 Jun 2025 23:15:54 +0200 Subject: [PATCH 1/4] =?UTF-8?q?=F0=9F=A9=B9=20[Patch]:=20Update=20README?= =?UTF-8?q?=20to=20clarify=20Context=20data=20storage=20and=20encryption?= =?UTF-8?q?=20details?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 63 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index e80161b4..5c2bd537 100644 --- a/README.md +++ b/README.md @@ -1,31 +1,31 @@ # Context Modules typically handle two types of data that benefit from persistent secure storage and management: module settings and user settings and secrets. -This module introduces the concept of `Contexts`, which store data locally on the machine where the module runs. It allows module developers to +This module introduces the concept of `Contexts`, which enable persistent and secure data storage for PowerShell modules. It allows module developers to separate user and module data from the module code, enabling users to resume their work without needing to reconfigure the module or log in again, provided the service supports session refresh mechanisms (e.g., refresh tokens). The module uses NaCl-based encryption, provided by the `libsodium` library, to encrypt and decrypt `Context` data. The module that delivers this -functionality is called [`Sodium`](https://github.com/someuser/Sodium) and is a dependency of this module. The -[`Sodium`](https://github.com/someuser/Sodium) module is automatically installed when you install this module. +functionality is called [`Sodium`](https://github.com/PSModule/Sodium) and is a dependency of this module. The +[`Sodium`](https://github.com/PSModule/Sodium) module is automatically installed when you install this module. ## What is a `Context`? -A `Context` is a way to securely persist user and module state on disk while ensuring data remains encrypted at rest. It stores structured data that -can be represented in JSON format, including regular values, arrays, objects and `SecureString`. It can hold multiple secrets (such as passwords or -API tokens) alongside general data like configuration settings, session metadata, or user preferences. `SecureStrings` are specially handled to -maintain their security when stored and retrieved. +The concept of `Context` is widely used to represent a collection of data that is relevant to a specific use-case. In this module, +a `Context` is a way to securely persist user and module data and offers a set of functions to manage this across modules that implement it. +Data that is stored in a `Context` can include user-specific settings, secrets, and module configuration data. +A `Context` is identified by a unique ID, which is typically a string that represents the module and user of a module (e.g., `GitHub/john_doe`), but +this is just an example. Any data that can be represented in JSON format can be stored in a `Context`. -When saving a `Context`, data is first structured as plain-text JSON, then encrypted and stored on disk. `SecureStrings` are marked with a special -prefix before encryption, ensuring they can be safely restored as secure strings when the `Context` is loaded back into memory. +When saving a `Context` using `Set-Context`, data is first converted to plain-text JSON, then encrypted before being saved to disk. `SecureStrings` are +marked with a special `[SECURESTRING]` prefix to indicate that they should be restored to a `SecureString`. When the `Context` is accessed using +`Get-Context` the data is read from disk and decrypted, restoring it as an object. Any `SecureString` values are restored to a `SecureString` within +that object. -When imported, the encrypted data is decrypted, converted back into its original structured format, and held in memory, ensuring both usability and -security. +### 1. Storing data (object or dictionary) to disk using `Set-Context` -
- 1. Storing data (object or dictionary) in persistent storage using `Set-Context` - -Typically, the first input to a `Context` is an object (though it can also be a hashtable or any other type that converts to JSON). +The `Set-Context` function is called to store a `Context` object or dictionary to disk. The function takes an ID and a context object as parameters. +The context object can be a PowerShell object or a dictionary (hashtable). ```pwsh Set-Context -ID 'john_doe' -Context ([PSCustomObject]@{ @@ -36,22 +36,37 @@ Set-Context -ID 'john_doe' -Context ([PSCustomObject]@{ TwoFactorMethods = @('TOTP', 'SMS') }) ``` -
-
- 2. How the data is ultimately stored – as processed JSON +### 2. The object is converted to JSON and prepared for encryption -This is how the object above is stored, shown here in an uncompressed format for readability. Notice that the `ID` property gets added. +When the `Set-Context` function is called, the object is converted to JSON format. If the context object contains any `SecureString` values, they are +marked with a `[SECURESTRING]` prefix. This indicates that these values should be restored as `SecureString` objects when the context is retrieved. ```json { "ID": "john_doe", "Username": "john_doe", "AuthToken": "[SECURESTRING]ghp_12345ABCDE67890FGHIJ", - "LoginTime": "2024-11-21T21:16:56.2518249+01:00" + "LoginTime": "2024-11-21T21:16:56.2518249+01:00", + "IsTwoFactorAuth": true, + "TwoFactorMethods": ["TOTP", "SMS"] +} +``` + +### 3. Storing the context object to disk + +When the context object is ready, it is encrypted using the `Sodium` module and saved to disk in a secure location. The file path is typically +`$HOME\.contextvault\.json`, where `` is a GUID that is auto generated by the module and provides a unique name for the file. +The JSON representation of the user data is added as a encrypted string to another object that holds metadata about the `Context`, like a unique ID +and info about the file that holds the `Context`. The metadata can be accessed using the `Get-ContextInfo` function. + +```json +{ + "ID": "PSModule.GitHub/github.com/john_doe", + "Path": "C:\\Users\\JohnDoe\\.contextvault\\d2edaa6e-95a1-41a0-b6ef-0ecc5d116030.json", + "Context": "0kGmtbQiEtih7 --< encrypted context data >-- ceqbMiBilUvEzO1Lk" } ``` -
## Installation @@ -71,13 +86,13 @@ Let's take a closer look at how to store these types of data using the module. A module developer can create additional `Contexts` for settings that share the same lifecycle, such as those associated with a module extension. For example, if we have a module called `GitHub` that needs to store some settings, the module developer could initialize a `Context` called `GitHub` -as part of the loading section in the module code. The module configuration is stored in `ContextVault` under the ID `GitHub`. +as part of the loading section in the module code. The module configuration is accessed using the ID `GitHub`. ### User Configuration To store user data, a module developer can create a `Context` that serves as a "namespace" for user-specific configurations. -Imagine a user named `BobMarley` logs into the `GitHub` module. The following would exist in `ContextVault`: +Imagine a user named `BobMarley` logs into the `GitHub` module. The following logical structure would be created: - `GitHub`: Contains module configuration, like default user, host, and client ID. - `GitHub/BobMarley`: Contains user configuration, secrets, and default values for API calls. @@ -147,4 +162,4 @@ If you code, we'd love your contributions! Please read the [Contribution Guideli ## Links -- Sodium [GitHub](https://github.com/someuser/Sodium) | [PSGallery](https://www.powershellgallery.com/packages/Sodium) +- Sodium [GitHub](https://github.com/PSModule/Sodium) | [PSGallery](https://www.powershellgallery.com/packages/Sodium) From 7ab73700b6ac231a649cf5854a3fc5f89f19b928 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Tue, 3 Jun 2025 23:20:29 +0200 Subject: [PATCH 2/4] Update README.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5c2bd537..7b1c4a76 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ marked with a `[SECURESTRING]` prefix. This indicates that these values should b When the context object is ready, it is encrypted using the `Sodium` module and saved to disk in a secure location. The file path is typically `$HOME\.contextvault\.json`, where `` is a GUID that is auto generated by the module and provides a unique name for the file. -The JSON representation of the user data is added as a encrypted string to another object that holds metadata about the `Context`, like a unique ID +The JSON representation of the user data is added as an encrypted string to another object that holds metadata about the `Context`, like a unique ID and info about the file that holds the `Context`. The metadata can be accessed using the `Get-ContextInfo` function. ```json From 8167580f0e2f33b2de84743cb64f844817402d0e Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Tue, 3 Jun 2025 23:20:39 +0200 Subject: [PATCH 3/4] Update README.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7b1c4a76..1e39d90e 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ this is just an example. Any data that can be represented in JSON format can be When saving a `Context` using `Set-Context`, data is first converted to plain-text JSON, then encrypted before being saved to disk. `SecureStrings` are marked with a special `[SECURESTRING]` prefix to indicate that they should be restored to a `SecureString`. When the `Context` is accessed using -`Get-Context` the data is read from disk and decrypted, restoring it as an object. Any `SecureString` values are restored to a `SecureString` within +`Get-Context`, the data is read from disk and decrypted, restoring it as an object. Any `SecureString` values are restored to a `SecureString` within that object. ### 1. Storing data (object or dictionary) to disk using `Set-Context` From 6a0794c1bb8c86a681eee26225d16b770da9ad37 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Tue, 3 Jun 2025 23:34:07 +0200 Subject: [PATCH 4/4] =?UTF-8?q?=F0=9F=A9=B9=20[Patch]:=20Refine=20README?= =?UTF-8?q?=20to=20clarify=20Context=20data=20storage=20process=20and=20en?= =?UTF-8?q?cryption=20details?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 1e39d90e..9dcbc41b 100644 --- a/README.md +++ b/README.md @@ -17,15 +17,10 @@ Data that is stored in a `Context` can include user-specific settings, secrets, A `Context` is identified by a unique ID, which is typically a string that represents the module and user of a module (e.g., `GitHub/john_doe`), but this is just an example. Any data that can be represented in JSON format can be stored in a `Context`. -When saving a `Context` using `Set-Context`, data is first converted to plain-text JSON, then encrypted before being saved to disk. `SecureStrings` are -marked with a special `[SECURESTRING]` prefix to indicate that they should be restored to a `SecureString`. When the `Context` is accessed using -`Get-Context`, the data is read from disk and decrypted, restoring it as an object. Any `SecureString` values are restored to a `SecureString` within -that object. - ### 1. Storing data (object or dictionary) to disk using `Set-Context` -The `Set-Context` function is called to store a `Context` object or dictionary to disk. The function takes an ID and a context object as parameters. -The context object can be a PowerShell object or a dictionary (hashtable). +To store data to disk, use the `Set-Context` function. The function needs an ID and the data object. +The object can be anything that can be converted and represented in JSON format. ```pwsh Set-Context -ID 'john_doe' -Context ([PSCustomObject]@{ @@ -39,8 +34,9 @@ Set-Context -ID 'john_doe' -Context ([PSCustomObject]@{ ### 2. The object is converted to JSON and prepared for encryption -When the `Set-Context` function is called, the object is converted to JSON format. If the context object contains any `SecureString` values, they are -marked with a `[SECURESTRING]` prefix. This indicates that these values should be restored as `SecureString` objects when the context is retrieved. +The object that is passed into `Set-Context` is first analyzed. If the object contains any `SecureString` values, they are converted to plain-text and +prefixed with `[SECURESTRING]`. This indicates that these values should be restored back to `SecureString`. The whole object is then converted to a +JSON string. ```json { @@ -55,10 +51,10 @@ marked with a `[SECURESTRING]` prefix. This indicates that these values should b ### 3. Storing the context object to disk -When the context object is ready, it is encrypted using the `Sodium` module and saved to disk in a secure location. The file path is typically -`$HOME\.contextvault\.json`, where `` is a GUID that is auto generated by the module and provides a unique name for the file. -The JSON representation of the user data is added as an encrypted string to another object that holds metadata about the `Context`, like a unique ID -and info about the file that holds the `Context`. The metadata can be accessed using the `Get-ContextInfo` function. +When the data is primed for storage, it is finally encrypted using the `Sodium` module and saved to disk. The file is stored in the user's home +directory `$HOME\.contextvault\.json`, where `` is a generated GUID, providing a unique name for the file. +The encrypted JSON representation of the data is added to metadata object that holds other info such as the ID of the `Context` and the path to the +file where it is stored. ```json { @@ -68,6 +64,8 @@ and info about the file that holds the `Context`. The metadata can be accessed u } ``` +The metadata can be accessed using the `Get-ContextInfo` function. + ## Installation You can install the module from the PowerShell Gallery using the following command: