CLI client for RFC 4226's HOTP and RFC 6238's TOTP.

Overview

One Time Password (OTP, TOTP/HOTP)

Python 3.10 Code style: black pdm-managed pre-commit


OTP serves as additional protection in case of password leaks.

onetimepass allows you to manage OTP codes and generate a master key. The master key allows the base to be decrypted and encrypted. Make sure to keep it in a safe place, otherwise it will not be possible to recover the data.

onetimepass supports as an optional dependency the integration with the system keychain (cross-platform) in which the application saves the master key.

Requirements

  • Python 3.10+
  • PDM 1.11+

Installation

$ pdm install

To include the optional keychain support:

$ pdm install -G keyring

Usage

Initialize database

At the very beginning, the database must be initialised, which additionally creates the master key. It will save it to the keychain if this has been installed.

By default, it will print the generated key to the STDOUT. You need this behavior if you don't use the optional keychain integration.

If you do, you can pass the -q, --quiet option to silence the output.

Keychain integration

The application will automatically detect if you have the keychain integration installed, however, if you want to force enable/disable it, you can by using respectively the -k, --keyring and -K, --no-keyring options.

Although, if you don't have the keychain integration installed, enabling it won't work:

Print the master key

It is possible to print the current master key stored in the keychain (if you need this for e.g. migrating the app to the different device).

This of course won't work if you don't use the keychain integration.

Adding new OTP alias

onetimepass identifies the added OTP codes via the user-specified aliases, which should be short, easy-to-remember names.

onetimepass allows you to add new alias in two ways, either by specifying all the parameters manually, using add hotp or add totp commands (depending on which type of the OTP you want to add), or by providing the de facto standard URI invented by the Google.

Adding via URI (command will aks interactively for the URI)

$ pdm run otp add uri AWS-root
Enter URI:
Repeat for confirmation:

Example URIs

Adding via totp/hotp subcommand (command will ask interactively for the secret):

$ pdm run otp add totp AWS-root
Enter secret:
Repeat for confirmation:
$ pdm run otp add hotp AWS-root
Enter secret:
Repeat for confirmation:

Removing OTP alias

$ pdm run otp rm <alias>
Are you sure? [y/N]:

To omit the interactive confirmation ( ⚠️ unsafe!), pas the --yes option.

Showing OTP code

Show single OTP identified by alias

$ pdm run otp show <alias>

You can force the app to wait until the new OTP code is valid, in case the current one will be invalid in a short period of time (so you won't have to rush with copy-pasting the code, or wait manually), using -w, --wait-for-next option.

$ pdm run otp show -w <seconds> <alias>

This will accept the seconds of tolerance (if the remaining time of the current code to be valid is less than seconds, the app will wait, otherwise it will show the current code).

You can easily automate it even more:

$ pdm run otp show -w 10 <alias> | cut -d' ' -f2 | pbcopy; alert

To extract the code when it's ready, then copy it to the system clipboard (pbcopy for macOS, xclip for Linux), and send the system notification to yourself when it's all finished (assuming you have the alert alias configured, available by default e.g. on Ubuntu Linux).

Show all codes

$ pdm run otp show-all

You can emulate the view known from the Google Authenticator (list of all the codes, refreshed dynamically) by wrapping the application in the external watcher (e.g. watch):

$ watch -c -p -n 1 pdm run otp show-all

Database import/export

In case you want to migrate the application to the different device, you can export the local database to the format of choice (currently only the json is supported) and then import it.

You can use this not only to transfer the application between the devices, but also to create backups: because onetimepass is a CLI-based tool, you can even implement the cronjob that will periodically run the export in the background ( ⚠️ just remember to encrypt the resulting file and store it somewhere safe).

Shell Completion

onetimepass can provide tab completion for commands, options, and choice values. Bash, Zsh, and Fish are supported

$ pdm run zsh
$ eval "$(_OTP_COMPLETE=zsh_source otp)"
$ pdm run bash
$ eval "$(_OTP_COMPLETE=bash_source otp)"

Rationale

As the onetimepass have multiple alternatives, you may ask why bother with reinventing the wheel instead of using any existing solution.
This section addresses that.

Existing alternatives

Google Authenticator

The main issue with this app is that it does not offer any way to backup the secrets, and synchronize them between the devices.

If you don't have the backup of the original QR codes, and you'll lose your mobile phone, you're screwed. Yes, services that provide the 2FA often offer the backup codes, but not every one of them, and this is not the optimal solution.

In theory, if you root the device, you can access the local database, but not everyone wants or can root their mobile phone, as this can e.g. void a device's warranty.

Besides, if you root the device, you can see the local database is stored in the plain text, which is a big security risk.

Authy

It does allow synchronizing secrets between the devices, but this happens through the provider servers. The application neither sent nor store your backup password, but it can still be non-optimal for some people to trust the external provider to handle such sensitive data.

Also, Authy does not support export or import of the secrets.

pass or gopass

pass is an extensible CLI-based password manager, and there is a pass-otp plugin to handle TOTP (although, HOTP is not supported).

One issue is that it uses GnuPG for encrypting the local database, which can be tedious to configure:

To be honest, a few first times I tried to configure it, I failed miserably. This should be much easier and faster. ~ Daniel Staśczak

The second issue is that, as mentioned above, pass is primarily the password manager. If one wants only the TOTP client, it's a little bit of an overkill to install the whole password manager for that.

The GUI clients in general

This is more of a personal preference, but if you use the GUI-based OTP client, especially on your mobile phone, there are some extra steps everytime you need to use it:

  1. You have to get your phone.
  2. You have to open the app.
  3. You have to type the code manually, if you need to enter the code on another device (e.g. to authorize on the desktop).

This is not very inconvenient, but I bet there were at least few times when you didn't had your phone with you while you had to authorize into the AWS account while working on something urgent, or get your phone out of the pocket every few hours, because the Keeper logged out you out of a sudden once again in a day.

If you're CLI power-user, using the CLI-based tool is just much quicker and convenient. And you can create some crazy pipelines (see the examples in the Usage section).

Security

While onetimepass does reinvent a wheel in general, one of the main goals of the project is to still be a secure solution, and do not reinvent the wheel in regard to the security. Because of this reason, for generating the master key and encrypting the local database, the high-level cryptographic library is used.

The main algorithm for the HOTP/TOTP is implemented based on the official RFC and the reference implementation.

There are some functionalities which can be a security hole if used in an irresponsible manner (e.g. export, key), but the same can be said about the sudo rm -rf --np-preserve-root /, right?

Nevertheless, if you see any security issue, please feel free to report it, we're more than happy to consider it.

Comments
  • `show-all` command increases all HOTP counters

    `show-all` command increases all HOTP counters

    As you can see on this GIF included in the README (!), the show-all command automatically increases all HOTP counters. This automatic behavior makes sense when printing the single HOTP using show, but in this case, it basically breaks the functionality.

    This is a critical bug.

    EDIT: Summary of the discussion: https://github.com/apptension/onetimepass/issues/27#issuecomment-999760403

    bug 
    opened by Toreno96 5
  • `add hotp` raises unhandled exception on missing `-c, --counter` option

    `add hotp` raises unhandled exception on missing `-c, --counter` option

    $ pdm run otp add hotp -h
    Usage: otp add hotp [OPTIONS] ALIAS
    
      Add the new HOTP secret as the specified ALIAS.
    
    Options:
      -c, --counter INTEGER
      -l, --label TEXT
      -i, --issuer TEXT
      -a, --algorithm [sha1|sha256|sha512]
                                      [default: sha1]
      -d, --digits-count INTEGER      [default: 6]
      -h, --help                      Show this message and exit.
    $ pdm run otp add hotp foo
    Enter secret:
    Repeat for confirmation:
    Traceback (most recent call last):
      File "/Users/dstasczak/development/projects/onetimepass/__pypackages__/3.10/bin/otp", line 8, in <module>
        sys.exit(otp())
      File "/Users/dstasczak/development/projects/onetimepass/__pypackages__/3.10/lib/click/core.py", line 1128, in __call__
        return self.main(*args, **kwargs)
      File "/Users/dstasczak/development/projects/onetimepass/__pypackages__/3.10/lib/click/core.py", line 1053, in main
        rv = self.invoke(ctx)
      File "/Users/dstasczak/development/projects/onetimepass/__pypackages__/3.10/lib/click/core.py", line 1659, in invoke
        return _process_result(sub_ctx.command.invoke(sub_ctx))
      File "/Users/dstasczak/development/projects/onetimepass/__pypackages__/3.10/lib/click/core.py", line 1659, in invoke
        return _process_result(sub_ctx.command.invoke(sub_ctx))
      File "/Users/dstasczak/development/projects/onetimepass/__pypackages__/3.10/lib/click/core.py", line 1395, in invoke
        return ctx.invoke(self.callback, **ctx.params)
      File "/Users/dstasczak/development/projects/onetimepass/__pypackages__/3.10/lib/click/core.py", line 754, in invoke
        return __callback(*args, **kwargs)
      File "/Users/dstasczak/development/projects/onetimepass/onetimepass/otp.py", line 414, in _wrapped
        return fn(*args, **kwargs)
      File "/Users/dstasczak/development/projects/onetimepass/__pypackages__/3.10/lib/click/decorators.py", line 26, in new_func
        return f(get_current_context(), *args, **kwargs)
      File "/Users/dstasczak/development/projects/onetimepass/onetimepass/otp.py", line 452, in add_hotp
        params=HOTPParams(counter=counter),
      File "/Users/dstasczak/development/projects/onetimepass/__pypackages__/3.10/lib/pydantic/main.py", line 406, in __init__
        raise validation_error
    pydantic.error_wrappers.ValidationError: 1 validation error for HOTPParams
    counter
      none is not an allowed value (type=type_error.none.not_allowed)
    

    We should either support the default value (e.g. -c 0) or reimplement this as the command argument (otp add hotp [OPTIONS] ALIAS COUNTER).

    bug 
    opened by Toreno96 2
  • `add uri` command does not conform in 100% to the Key Uri Format specification

    `add uri` command does not conform in 100% to the Key Uri Format specification

    The biggest issue is that the secret parameter is supposed to be:

    an arbitrary key value encoded in Base32 according to RFC 3548. The padding specified in RFC 3548 section 2.2 is not required and should be omitted. ~ source

    While the application handles this as plain text, not Base32.

    Apart from that, parameters that are specified as optional in the specification, are required in the application. I didn't go through all of them yet, but at least algorithm is required, I got this exception after I didn't include it in the URI:

    Traceback (most recent call last):
      File "/Users/dstasczak/development/projects/onetimepass/__pypackages__/3.10/bin/otp", line 8, in <module>
        sys.exit(otp())
      File "/Users/dstasczak/development/projects/onetimepass/__pypackages__/3.10/lib/click/core.py", line 1128, in __call__
        return self.main(*args, **kwargs)
      File "/Users/dstasczak/development/projects/onetimepass/__pypackages__/3.10/lib/click/core.py", line 1053, in main
        rv = self.invoke(ctx)
      File "/Users/dstasczak/development/projects/onetimepass/__pypackages__/3.10/lib/click/core.py", line 1659, in invoke
        return _process_result(sub_ctx.command.invoke(sub_ctx))
      File "/Users/dstasczak/development/projects/onetimepass/__pypackages__/3.10/lib/click/core.py", line 1659, in invoke
        return _process_result(sub_ctx.command.invoke(sub_ctx))
      File "/Users/dstasczak/development/projects/onetimepass/__pypackages__/3.10/lib/click/core.py", line 1395, in invoke
        return ctx.invoke(self.callback, **ctx.params)
      File "/Users/dstasczak/development/projects/onetimepass/__pypackages__/3.10/lib/click/core.py", line 754, in invoke
        return __callback(*args, **kwargs)
      File "/Users/dstasczak/development/projects/onetimepass/__pypackages__/3.10/lib/click/decorators.py", line 26, in new_func
        return f(get_current_context(), *args, **kwargs)
      File "/Users/dstasczak/development/projects/onetimepass/onetimepass/otp.py", line 374, in add_uri
        uri_parsed = otp_auth_uri.parse(input_uri)
      File "/Users/dstasczak/development/projects/onetimepass/onetimepass/otp_auth_uri.py", line 46, in parse
        algorithm = OTPAlgorithm(query_parsed.get("algorithm")[0].lower())
    TypeError: 'NoneType' object is not subscriptable
    
    bug 
    opened by Toreno96 1
  • Fix issue #26

    Fix issue #26

    Now, the app stores a local database in the OS-specific data directory.

    This commit also improves the overall code quality:

    Best practice:

    • abc module is used to implement abstract classes.
    • pathlib is used for the file paths, not str.
    • Exception handling in the init command is now more granular.

    Encapsulation:

    • Checking if the database already exists is now the responsibility of the database module, not the command implementation.

    • Redundant JSONEncryptedDB.exists classmethod was removed (it didn't do anything more than simple self.path.exist).

      I considered to replace it with the instance method, but that could be confusing (if the database requires both path and key to be created, does it check if the database with the specific path and key exists?).

    opened by Toreno96 1
  • `otp -k key` raises unhandled exception if the keyring is not installed

    `otp -k key` raises unhandled exception if the keyring is not installed

    $ pdm run otp -k key
    Traceback (most recent call last):
      File "/Users/dstasczak/development/projects/onetimepass/__pypackages__/3.10/bin/otp", line 8, in <module>
        sys.exit(otp())
      File "/Users/dstasczak/development/projects/onetimepass/__pypackages__/3.10/lib/click/core.py", line 1130, in __call__
        return self.main(*args, **kwargs)
      File "/Users/dstasczak/development/projects/onetimepass/__pypackages__/3.10/lib/click/core.py", line 1055, in main
        rv = self.invoke(ctx)
      File "/Users/dstasczak/development/projects/onetimepass/__pypackages__/3.10/lib/click/core.py", line 1657, in invoke
        return _process_result(sub_ctx.command.invoke(sub_ctx))
      File "/Users/dstasczak/development/projects/onetimepass/__pypackages__/3.10/lib/click/core.py", line 1404, in invoke
        return ctx.invoke(self.callback, **ctx.params)
      File "/Users/dstasczak/development/projects/onetimepass/__pypackages__/3.10/lib/click/core.py", line 760, in invoke
        return __callback(*args, **kwargs)
      File "/Users/dstasczak/development/projects/onetimepass/__pypackages__/3.10/lib/click/decorators.py", line 26, in new_func
        return f(get_current_context(), *args, **kwargs)
      File "/Users/dstasczak/development/projects/onetimepass/onetimepass/otp.py", line 228, in key
        click.echo(key_)
    UnboundLocalError: local variable 'key_' referenced before assignment
    
    bug 
    opened by Toreno96 0
  • GH Actions `CI` stopped working; it tries to use Python `3.8` for PDM

    GH Actions `CI` stopped working; it tries to use Python `3.8` for PDM

    Based on the https://github.com/apptension/onetimepass/actions, the last working Action was on 31 Jan, then the next one, on 14 Mar, failed.

    It fails on the build step, during installation of the dependencies: https://github.com/apptension/onetimepass/runs/5544580363 Even if there was no actual changes to the code or the dependencies: https://github.com/apptension/onetimepass/runs/5710372114

    Because it tries to use Python 3.8, not 3.10 defined in the earlier step 😕

    It seems that something changed in the https://github.com/pdm-project/setup-pdm that forces Python 3.8. The last commit was on 15 Feb, so it may be the reason.

    While looking into their repo, I saw that note in the README:

    You don't need actions/setup-python actually.

    Maybe we could actually remove the usage of actions/setup-python as suggested and define the Python version explicitly for the setup-pdm step instead.

    Also, we should maybe consider freezing the actions versions, if they happen to break between the versions 🤔

    bug 
    opened by Toreno96 0
  • Error for invalid hash algorithm shows the implementation details

    Error for invalid hash algorithm shows the implementation details

    In case the user passes the invalid value for the -a, --algorithm, the app shows the possible values as the canonical string representation of the enum objects:

    $ pdm run otp add hotp foo -a sha
    Usage: otp add hotp [OPTIONS] ALIAS
    Try 'otp add hotp -h' for help.
    
    Error: Invalid value for '-a' / '--algorithm': 'sha' is not one of <OTPAlgorithm.SHA1: 'sha1'>, <OTPAlgorithm.SHA256: 'sha256'>, <OTPAlgorithm.SHA512: 'sha512'>.
    

    which are not the actual values expected from the user, but their implementation details.

    The expected is a representation that directly translates to the expected values:

    $ pdm run otp add hotp foo -a sha
    Usage: otp add hotp [OPTIONS] ALIAS
    Try 'otp add hotp -h' for help.
    
    Error: Invalid value for '-a' / '--algorithm': 'sha' is not one of 'sha1', 'sha256', 'sha512'.
    
    bug 
    opened by Toreno96 0
  • Fix invalid type annotation of `wait` option

    Fix invalid type annotation of `wait` option

    This is a command-line option w/o the default, so there are cases when it will be None.

    The check was also unnecessary broad, which could be error-prone if we ever accept wait equal to 0 or any other False value.

    bug 
    opened by Toreno96 0
  • Fix #34

    Fix #34

    You can see in the changes, that I alternate between the typing.Optional and new union operator |, which introduces inconsistency.

    This is because:

    1. It seems the union operator | will be the preferred way to annotate the optionals: https://twitter.com/raymondh/status/1472426960349548549?s=20

      I think it makes sense, and tbh I like this syntax, so I decided to incorporate this preference into the project.

    2. Unfortunately, Pydantic does not support the new union operator | at all yet: https://github.com/samuelcolvin/pydantic/issues/3300.

      I've tried the suggested workaround, but it didn't work.

      As such, I decided to use typing.Optional in the case of Pydantic models, as an exception to the consistency.

    closes #34

    opened by Toreno96 0
  • The counter in HOTP should be incremented _before_ the OTP is shown

    The counter in HOTP should be incremented _before_ the OTP is shown

    Some details are here https://github.com/apptension/onetimepass/issues/27#issuecomment-991916029 and here https://github.com/apptension/onetimepass/issues/27#issuecomment-991927053.

    We should probably make the operation atomic: if there's any unexpected error before the OTP is shown, the counter should be decremented to the original value before calling the command.

    bug 
    opened by Toreno96 0
  • GH Action `CI` stopped working; `ModuleNotFoundError: No module named 'pip._vendor.html5lib'`

    GH Action `CI` stopped working; `ModuleNotFoundError: No module named 'pip._vendor.html5lib'`

    Based on the https://github.com/apptension/onetimepass/actions, the last working Action was on 4 Aug, then the next one, on 5 Sep, failed.

    It fails on the build step, during Setup PDM: https://github.com/apptension/onetimepass/actions/runs/2996025879/jobs/4806324623#step:4:73 with an exception ModuleNotFoundError: No module named 'pip._vendor.html5lib'.

    It looks like it's connected to https://github.com/pdm-project/pdm/issues/1261

    It seems it was fixed in https://github.com/pdm-project/pdm/pull/1266, which according to https://github.com/pdm-project/pdm/commit/79e91604985b29e76e46e49905c853b37389852f should be in PDM 1.15.5, however, I do not see 1.15.5 in the releases page https://github.com/pdm-project/pdm/releases?page=2 – the next release after 1.15.4 is 2.x 😕 Also, I do not see bug https://github.com/pdm-project/pdm/issues/1261 being mentioned in any release's changelog.

    I will try to contact the maintainers of PDM, while in the meantime, bumping up the version of PDM in the CI.

    bug 
    opened by Toreno96 1
  • Make sure `secret` is not injected in log files etc as plain text

    Make sure `secret` is not injected in log files etc as plain text

    This includes places like log files, error outputs, etc. If we need to inform the user in these that there was some kind of error in the secret's value, the actual value should not be shown.

    The suggested solution is to rely on the SecretStr and the SecretBytes data types provided by the Pydantic.

    enhancement 
    opened by Toreno96 0
  • Fix docs' invalid HOTP example

    Fix docs' invalid HOTP example

    https://github.com/apptension/onetimepass/blob/4a41930c6a5dc9e83a9d9b8bf615257ba87d6f05/README.md?plain=1#L87 This is supposed to be HOTP, but the value (both type and parameters) represents TOTP.

    documentation 
    opened by Toreno96 0
  • Fix docs' misinformation about Google Authenticator not supporting sync between devices

    Fix docs' misinformation about Google Authenticator not supporting sync between devices

    In the README's section about the Google Authenticator, there's info that:

    The main issue with this app is that it does not offer any way to backup the secrets, and synchronize them between the devices.

    This is not true anymore, as according to the app's official changelog, it is now possible to move accounts between the devices (although, I didn't check the details yet on how good it works).

    We should update the README, then.

    documentation 
    opened by Toreno96 0
  • Name `algorithm` is shadowed

    Name `algorithm` is shadowed

    https://github.com/apptension/onetimepass/blob/1ff20eac46925e7ae3b54dd1af3bf5a475462608/onetimepass/otp.py shadows the name algorithm from the import: https://github.com/apptension/onetimepass/blob/1ff20eac46925e7ae3b54dd1af3bf5a475462608/onetimepass/otp.py#L16 with the algorithm function argument: https://github.com/apptension/onetimepass/blob/1ff20eac46925e7ae3b54dd1af3bf5a475462608/onetimepass/otp.py#L401

    I suggest to not simply rename one of these to algorithm_, but actually rename both of them:
    probably to something along the lines of respectivelyotp_algorithm and hash_algorithm.

    Because let's be honest, algorithm is too much of a general name, it's worth to distinct both of them in a more clear way, and we actually use the hash_algorithm name already in some other parts of the codebase.

    bug enhancement 
    opened by Toreno96 0
Owner
Apptension
We are a fellow custom software development company for Startups, Investors and Agencies.
Apptension
A simple CLI based any Download Tool, that find files and let you stream or download thorugh WebTorrent CLI or Aria or any command tool

Privateer A simple CLI based any Download Tool, that find files and let you stream or download thorugh WebTorrent CLI or Aria or any command tool How

Shreyash Chavan 2 Apr 4, 2022
[WIP]An ani-cli like cli tool for movies and webseries

mov-cli A cli to browse and watch movies. Installation This project is a work in progress. However, you can try it out python git clone https://github

null 166 Dec 30, 2022
pyNPS - A cli Linux and Windows Nopaystation client made with python 3 and wget

Currently, all the work is being done inside the refactoring branch. pyNPS - A cli Linux and Windows Nopaystation client made with python 3 and wget P

Everton Correia 45 Dec 11, 2022
flora-dev-cli (fd-cli) is command line interface software to interact with flora blockchain.

Install git clone https://github.com/Flora-Network/fd-cli.git cd fd-cli python3 -m venv venv source venv/bin/activate pip install -e . --extra-index-u

null 14 Sep 11, 2022
AWS Interactive CLI - Allows you to execute a complex AWS commands by chaining one or more other AWS CLI dependency

AWS Interactive CLI - Allows you to execute a complex AWS commands by chaining one or more other AWS CLI dependency

Rafael Torres 2 Dec 10, 2021
Python-Stock-Info-CLI: Get stock info through CLI by passing stock ticker.

Python-Stock-Info-CLI Get stock info through CLI by passing stock ticker. Installation Use the following command to install the required modules at on

Ayush Soni 1 Nov 5, 2021
A command-line based, minimal torrent streaming client made using Python and Webtorrent-cli. Stream your favorite shows straight from the command line.

A command-line based, minimal torrent streaming client made using Python and Webtorrent-cli. Installation pip install -r requirements.txt It use

Jonardon Hazarika 17 Dec 11, 2022
A command-line based, minimal torrent streaming client made using Python and Webtorrent-cli.

ABOUT A command-line based, minimal torrent streaming client made using Python and Webtorrent-cli. Installation pip install -r requirements.txt It use

Janardon Hazarika 17 Dec 11, 2022
Pymongo based CLI client, to run operation on existing databases and collections

Mongodb-Operations-Console Pymongo based CLI client, to run operation on existing databases and collections Program developed by Gustavo Wydler Azuaga

Gus 1 Dec 1, 2021
triggercmd is a CLI client for the TRIGGERcmd cloud service.

TriggerCMD CLI client triggercmd is a CLI client for the TRIGGERcmd cloud service. installation the triggercmd package is available in PyPI. to instal

Gustavo Soares 7 Oct 18, 2022
CLI client for FerrisChat

A CLI Client for @FerrisChat using FerrisWheel

FerrisChat 2 Apr 1, 2022
RSS reader client for CLI (Command Line Interface),

rReader is RSS reader client for CLI(Command Line Interface)

Lee JunHaeng 10 Dec 24, 2022
A CLI tool for searching and watching videos on youtube with no spyware and MPV and yt-dlp

A CLI tool for searching and watching videos on youtube with no spyware and MPV and yt-dlp

TruncatedDinosour 3 Feb 22, 2022
Python wrapper and CLI utility to render LaTeX markup and equations as SVG using dvisvgm and svgo.

latex2svg Python wrapper and CLI utility to render LaTeX markup and equations as SVG using dvisvgm and svgo. Based on the original work by Tino Wagner

Matthias C. Hormann 4 Feb 18, 2022
A python script that enables a raspberry pi sd card through the CLI and automates the process of configuring network details and ssh.

This project is one script (wpa_helper.py) written in python that will allow for the user to automate the proccess of setting up a new boot disk and configuring ssh and network settings for the pi

Theo Kirby 6 Jun 24, 2021
CLI for SQLite Databases with auto-completion and syntax highlighting

litecli Docs A command-line client for SQLite databases that has auto-completion and syntax highlighting. Installation If you already know how to inst

dbcli 1.8k Dec 31, 2022
Postgres CLI with autocompletion and syntax highlighting

A REPL for Postgres This is a postgres client that does auto-completion and syntax highlighting. Home Page: http://pgcli.com MySQL Equivalent: http://

dbcli 10.8k Jan 2, 2023