Secret
☍
Manages read & write operations for files that contain sensitive encrypted data.
Each instance of this class represents a unique string containing secret information that must be encrypted before saving it to a file, and subsequently decrypted before it can be accessed again.
FAQ - How does the encryption work?
This class uses Fernet symmetric encryption from thecryptography
package to encrypt and decrypt data, optionally with extra protection in the
form of a password. The encrypted data is guaranteed to be
unreadable without the original key that was used to encrypt it.
Fernet keys are uniquely and randomly generated for each individual secret
at encryption time.
A secret is therefore represented in the file system by two separate .key
files, both of which are named using the secret's uid
(unique ID).
One of the files contains the encrypted content
of the secret, and the other
file contains the fernet
key required to decrypt it. Each of these files is
useless without the other.
Info - Fernet encryption with passwords
Factoring a password into the encryption of a secret can add an extra layer of protection because the password will not be stored anywhere on the file system. This means that even if a malicious actor were to gain access to both thecontent.key
and fernet.key
files of a secret, they still would not be able
to decipher the original data.
If a password is provided when a secret's
write()
method is invoked, the data will be
encrypted using an algorithm based on this reference implementation. The
password will be run through the PBKDF2HMAC
key derivation function to
obtain the Fernet key for the secret. As a result, the original password will
have to be accurately entered in order to "complete" the key every time the
secret is decrypted.
__init__(uid, requires_password=False, display_name=None, storage_directory=None, valid_pattern=None)
☍
Parameters:
Name | Type | Description | Default |
---|---|---|---|
uid |
str
|
A unique string to identify this secret. Will be used in the names of the files containing this secret's data. |
required |
requires_password |
bool
|
Whether a user-provided password is required in order to read and/or write the data for this secret. |
False
|
display_name |
str | None
|
A human-readable string describing this secret. Will be displayed in the
CLI when referring to this secret. If omitted, the |
None
|
storage_directory |
str | Path | None
|
Where to store the files containing this secret's data.
If omitted, they will be saved in a default
|
None
|
valid_pattern |
str | re.Pattern | Callable[[str], Any] | None
|
A string, regex |
None
|
Manages read & write operations for files that contain sensitive encrypted data.
Each instance of this class represents a unique string containing secret information that must be encrypted before saving it to a file, and subsequently decrypted before it can be accessed again.
FAQ - How does the encryption work?
This class uses Fernet symmetric encryption from thecryptography
package to encrypt and decrypt data, optionally with extra protection in the
form of a password. The encrypted data is guaranteed to be
unreadable without the original key that was used to encrypt it.
Fernet keys are uniquely and randomly generated for each individual secret
at encryption time.
A secret is therefore represented in the file system by two separate .key
files, both of which are named using the secret's uid
(unique ID).
One of the files contains the encrypted content
of the secret, and the other
file contains the fernet
key required to decrypt it. Each of these files is
useless without the other.
Info - Fernet encryption with passwords
Factoring a password into the encryption of a secret can add an extra layer of protection because the password will not be stored anywhere on the file system. This means that even if a malicious actor were to gain access to both thecontent.key
and fernet.key
files of a secret, they still would not be able
to decipher the original data.
If a password is provided when a secret's
write()
method is invoked, the data will be
encrypted using an algorithm based on this reference implementation. The
password will be run through the PBKDF2HMAC
key derivation function to
obtain the Fernet key for the secret. As a result, the original password will
have to be accurately entered in order to "complete" the key every time the
secret is decrypted.
file_path() -> Path
property
☍
The path of the file that may contain this secret's encrypted data.
This property will only return the content
file path, as the fernet
file is
irrelevant outside of this class. The return value will be an instance of
pathlib.Path
, but it is not guaranteed to point to an existing file
(e.g. if this secret hasn't been created/saved yet, or has been deleted).
min_pw_length() -> int
property
☍
The minimum length for this secret's password, if one is required.
For secrets that require a password, this property will return 8
(chosen arbitrarily to try and balance security vs. convenience).
For secrets that don't require a password, this will return 0
.
clear() -> None
☍
Deletes all files containing data related to this secret, if any exist.
This method does not scan the entire system to locate the files for a secret
- it only checks the storage_directory
that was specified upon instantiation.
Tip - Don't scramble your secrets!
If a secret's .key
files are renamed or moved out of their
original directory without a corresponding change to the uid
and/or
storage_directory
constructor parameters (or vice versa), then the secret
will behave as if there are no existing files associated with it.
Fortunately, this can easily be resolved by either moving the files back
into place or updating the constructor parameters in your code.
read(password: str | None = None) -> str | None
☍
Returns the decrypted data from this secret's file if it exists and is valid.
The password
param must be provided if this secret was originally
encrypted with a password, and must not be provided if the opposite is true.
If provided, it must match the original password or else the decrypted data
will not be valid and this method will return None
.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
password |
str | None
|
The password originally used to create this secret, if applicable.
Otherwise, this should be |
None
|
Returns:
Type | Description |
---|---|
str | None
|
The data for this secret if it exists & can be decrypted, otherwise |
write(data: str, password: str | None = None) -> None
☍
Encrypts and writes the data to a file, optionally protected by a password.
If the password
param is provided, it must be at least 8
characters long
(see min_pw_length
) and will have to
be provided again whenever read()
is invoked
to decrypt this secret.
Omitting the password
parameter means that only the secret's two
.key
files will be required in order to decrypt it.
This is both more convenient and more dangerous, so choose wisely.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
data |
str
|
A string containing sensitive information to be encrypted before being stored in a file. |
required |
password |
str | None
|
An optional string that can improve the security of this secret. If omitted, a password will not be factored into the encryption algorithm for this secret. |
None
|
Raises:
Type | Description |
---|---|
ValueError
|
If the |