Package: etoolkit
etoolkitetoolkitis a simple toolkit for defining and setting environment variables
in a flexible and secure way.Generaletoolkitstarted as a simple idea while I was working at the University
of Oslo. Later I felt the need for even more flexible solution. The following
goals were set:the ability to define env. var. "instances" with support for inheritanceencrypting values using a master passwordthe ability to spawn a child process with the defined variablessupport for macrosRequirementsApart from Python >= 3.7, the only requirement iscryptographyOverviewIn a typical UNIX environment, env. variables are usually set in one
or more of the initialization / startup files like f.i./etc/profile,~/.bash_profile,~/.bashrc,~/.tcshrc,~/.cshrc... depending
on the OS, shell, distribution... etc.
Env. variables represent key-value pairs (env. variable name and its value).A potential problem when dealing with env. variables containing sensitive
values like passwords, tokens, connection strings... is that they are inherited
by all child processes spawned from the login / interactive shell.A malicious / exploited process (like f.i. web browser) will then be able to
fetch those values by usinggetenv. Such process may in addition be able to
simply read~/.bashrcor any similar file readable by the process owner and
get the values from there if necessary.etoolkitattempts to solve both of these problems.When started, it reads env. variables from its own configuration file.
Sensitive data may be encrypted using a master password. Hence reading
etoolkit's configuration file will not reveal the real value of the data.Whenetoolkithas processed (decryption, macro replacement, etc) its data,
it may define new env. variables corresponding to that data and may start a new
interactive shell. The processed environment variables will not be available
for processes that were not spawned by that sameetoolkitsession.Installationpip (pypi)pipinstalletoolkitGentoo# add sgs' custom repository using app-eselect/eselect-repositoryeselectrepositoryaddsgs# ... or using layman (obsolete)layman-asgs

emergedev-python/etoolkitSetup and examplesMost users (including me) will simply use the command line interface (CLI).CLIetoolkitcomes with a simple CLI:python-metoolkit-h... or even (ifetoolkitwas installed using the methods described above)etoolkit-hTheetoolkitCLI loads the configuration located by default in~/.etoolkit.json. That file is based onetoolkit_sample.json.The"instances"part of the configuration defines unique instances, each of
which represents its own environment with its own defined env. variables.
Each instance consists of key-value pairs corresponding to env. name and value.
All pairs will result in corresponding env. variables being defined, with the
exception of the followingetoolkitinternal keys:ETOOLKIT_PARENT- string - reference to another instanceETOOLKIT_SENSITIVE- list - env. variables containing sensitive dataAll pairs defined in"general"(currently onlyMASTER_PASSWORD_HASH) areetoolkitinternal as well.An instance may inherit (and if desired overwrite) key value pairs from its
parent.Variables containing sensitive data can be encrypted / decrypted using a master
password. Currentlyetoolkitrequires that all values in a configuration
file are encrypted with the same master password. Setting a master password
hash is a recommended but not mandatory.etoolkit--generate-master-password-hashThat command will prompt for master password and output a hash that can then
be storedin ["general"]["MASTER_PASSWORD_HASH"].The hash is only used for verifying that a correct master password has been
provided at a later time. Issuing:etoolkit--encrypt-valuewill prompt for the master password, then for the value to be encrypted and
finally display the encrypted string of the value. Unless invoked with the-E/--echoparameteretoolkitwill not display the value that is about
to be encrypted.More than one value can be encrypted / decrypted with a single master password
prompt if-m/--multiple-valuesparameter is provided. Manual decryption
of single value(s):etoolkit--decrypt-value--multiple-valuesAnother possibility is to pass the value toetoolkit'sstdinusing a pipe.etoolkitwill then only prompt for password and not for a value:echomysecret|etoolkit--encrypt-value... or if theETOOLKIT_MASTER_PASSWORDenv. variable is defined, its value
will be used instead of prompting for password.Listing available instances defined in the configuration file and then
loading a specific instance can be achieved by:etoolkit--list
etoolkit<instance-name>Instances with names starting with_will be consideredabstractand will
not be displayed by--list.etoolkitwill prompt for the master password the first time it encounters
and encrypted value. Once provided the master password will be used to decrypt
the rest of the encrypted values.When all values are fetched from a given instance (and its parents) and then
decrypted, they are further processed by replacing macros with their
corresponding values. Currently the following macros are supported:%h- the home directory of the user runningetoolkit(~/)%i- the name of the instance that is about to be loaded%p- the parent value (for the same key)%u- the username of the user runningetoolkit(getpass.getuser())In addition, value starting with":"is appended to the existing value
(if any) of the env. variable about to be set
(likeMYVAR=$MYVAR<new value>)).The opposite is true for value ending with":"(MYVAR=<new value>$MYVAR).When the variables are finally processed,etoolkitsets / changes them as env.
variables (usingsetenv/os.environ.update) and spawns an interactive
child process (by invokingsystem($SHELL)).One can also spawn a different process than an interactive shell by using the-s/--spawnparameter.etoolkit--spawn/bin/othershell<instance-name>Contact the author for questions and suggestions! :)Using theEtoolkitInstanceclassetoolkitcomes with its ownetoolkitpackage that contains theEtoolkitInstanceclass.The class encapsulates the function of creating and processing instances
from a given structure (dict).It may be useful if one should prefer for example making her own CLI interface.
or theinstancesstructure being loaded from a diferent configuration file
(f.i. .yml).importosimportetoolkit# using some static methods in order to create encrypted valuesetoolkit.EtoolkitInstance.encrypt('the very secret passwd','secret1')# Out: 'enc-val$1$Y/TBb1F3siHTw6qZg9ERzZfA8PLPf2CwGSQLpu9jYWw=$FT5tS9o+ABvsxogIXpJim16Gz5SVtV8='etoolkit.EtoolkitInstance.encrypt('the very secret passwd','secret2')# Out: 'enc-val$1$vIBcoCNiYrsDLtF41uLuSEnppBjhliD0B8jwcBJcj/c=$KwOGe/y1dlxktDaCnJPIVNuaQ4Q7yNo='# The encrypted values will be used in our configuration structure# The following structure defines the 3 instances: default, dev and secretinstances={"general":{},"instances":{"_default":{"ETOOLKIT_PROMPT":"(%i)","PYTHONPATH":"/home/user/%i/python",},"dev":{"ETOOLKIT_PARENT":"_default","PYTHONPATH":"%p:/home/user/%i/.pythonpath",},"secret":{"ETOOLKIT_PARENT":"_default","ETOOLKIT_SENSITIVE":["PASSWORD"],"GNUPGHOME":"%h/private/.gnupg","PASSWORD":"enc-val$1$vIBcoCNiYrsDLtF41uLuSEnppBjhliD0B8jwcBJcj/c=$KwOGe/y1dlxktDaCnJPIVNuaQ4Q7yNo="}}}dev_instance=etoolkit.EtoolkitInstance('dev',instances)# fetch the variables before the processing stage (calling get_environ())# since raw_env_variables is a dict, it can be modified (f.i. .update())dev_instance.raw_env_variablesdev_instance.master_password='the very secret passwd'# or perhaps using getpassenv_vars=dev_instance.get_env()print(env_vars['PASSWORD'])# outputs: 'secret2'inst.dump_env(env_vars)# prints all values, with the exception of 'PASSWORD'# set the env. variables.os.environ.update(env_vars)TipsWhen starting a new interactive process (f.i. bash), the process will
in turn invoke its startup script (f.i.~/.bashrc).Avoid redefining the env. variables that have just been set byetoolkit!If you want your shell prompt to display the name of the loaded instance, you
can set a new env. variable (f.i. "ETOOLKIT_PROMPT" as shown in the sample
configuration above) and then add the following at the bottom of your startup
file (f.i. ~/.bashrc):if[-n"$ETOOLKIT_PROMPT"];thenexportPS1="$ETOOLKIT_PROMPT$PS1"fiA quick and dirty bash completion for available instances can be set at the
bottom of your bash startup file:complete-W'$(compgen -W "$(etoolkit -l)")'etoolkitA complete bash completion script foretoolkitcan be found here:https://github.com/blackm0re/etoolkit/blob/master/completion/etoolkit.bashChangelogA complete changelog can be found at:https://github.com/blackm0re/etoolkit/blob/master/CHANGELOG.mdSupport and contributingetoolkitis hosted on GitHub:https://github.com/blackm0re/etoolkitAuthorSimeon Simeonov - sgs @ LiberaChatLicenseCopyright (C) 2021-2022 Simeon Simeonov
All rights reserved.Licensedunder the
GNU General Public License v3.0 or later.
SPDX-License-Identifier: GPL-3.0-or-later