Package: immudb-py
immudb-pyOfficialimmudbclient for Python.Try it on the immudb Playground!ContentsIntroductionPrerequisitesInstallationSupported VersionsQuickstartStep by step guideCreating a ClientIntroductionimmu-py implements agrpcimmudb client. A minimalist API is exposed for applications while cryptographic
verifications and state update protocol implementation are fully implemented by this client.
Latest validated immudb state may be kept in the local filesystem when using defaultrootService,
please readimmudb research paperfor details of how immutability is ensured byimmudb.Prerequisitesimmu-py assumes there is an existing instance of the immudb server up and running.
Runningimmudbis quite simple, please refer to the
following link for downloading and running it:https://immudb.io/docs/quickstart.htmlimmudb-py requires python version 3.6 or greater.
If you are using 3.6, you'll need dataclasses package; on 3.7+,
dataclasses is part of the python distribution.InstallationYou can install latest version cloning this repository, and then use the make command to install
prerequisites and the package itself:makeinitmakeinstallOr, you can install latest stable version using pip:pip3installimmudb-pyThen, in you code, import the client library as as follows:fromimmudbimportImmudbClientNote: immudb-py needgrpciomodule from google. On Alpine linux, you need
these packages in order to correctly build (and install) grpcio:linux-headerspython3-devg++Supported Versionsimmu-py supports thelatest immudb release.QuickstartHello Immutable World!example can be found inimmudb-client-examplesrepo.Step by step guideCreating a ClientThe following code snippets shows how to create a client.Using default configuration:client=ImmudbClient()Settingimmudburl and port:client=ImmudbClient("mycustomurl:someport")client=ImmudbClient("10.105.20.32:8899")User sessionsUseloginandlogoutmethods to initiate and terminate user sessions:client.login("usr1","pwd1");//Interactwithimmudbusingloggeduserclient.logout();EncodingPlease note that, in order to provide maximum flexibility, all functions accept byte arrays as parameters.
Therefore, unicode strings must be properly encoded.
It is possible to store structured objects, but they must be serialized (e.g., with pickle or json).Creating a databaseCreating a new database is quite simple:client.createDatabase(b"db1");Setting the active databaseSpecify the active database with:client.useDatabase(b"db1");If not specified, the default databased used is "defaultdb".Traditional read and writeimmudb provides read and write operations that behave as a traditional
key-value store i.e. no cryptographic verification is done. This operations
may be used when validations can be post-poned:client.set(b"k123",b"value123");result=client.get(b"k123");Verified read and writeimmudb provides built-in cryptographic verification for any entry. The client
implements the mathematical validations while the application uses as a traditional
read or write operation:try:client.verifiedSet(b"k123",b"v123");results=client.verifiedGet(b"k123");ExceptVerificationExceptionase:# Do somethingMulti-key read and writeTransactional multi-key read and write operations are supported by immudb and immudb-py.
Atomic multi-key write (all entries are persisted or none):normal_dictionary={b"key1":b"value1",b"key2":b"value2"}client.setAll(normal_dictionary);Atomic multi-key read (all entries are retrieved or none):normal_dictionary={b"key1":b"value1",b"key2":b"value2"}results_dictionary=client.getAll(normal_dictionary.keys())# Or manuallyclient.get([b"key1",b"key2"])User managementUsers can be added and granted access to databases.Adding a userThecreateUserfunctions create a new users and grants the specified permission to a database.user='newuser'password='Pw1:pasdfoiu'permission=immudb.constants.PERMISSION_RWdatabase='defaultdb'client.createUser(user,password,permission,database)The database must exists at the time the user is created. The password must be between 8 and 32 characters in length, and must have at least one upper case letter, a symbol and a digit.Permission are defined in immudb.constants and are:PERMISSION_SYS_ADMINPERMISSION_ADMINPERMISSION_NONEPERMISSION_RPERMISSION_RWChangin passwordThe user must must provide both old and new password:newPassword="pW1:a0s98d7gfy"resp=client.changePassword(user,newPassword,oldPassword)It is applied the same password policy of user creation.User listTo get the list of user created on immudb, simply calllistUsers:resp=client.listUsers()print(users.userlist.users)Closing the clientTo programatically close the connection with immudb server use theshutdownoperation:client.shutdown();Note: after shutdown, a new client needs to be created to establish a new connection.State persistanceAn important immudb feature is the ability for a client to check every transaction for tampering. In order to
be able to do that, it is necessary to persist client state (i.e., save it to disk) so that if some tampering
on the server happens between two runs, it is immediatly detected.ARootServiceimplements just that: it stores immudb client after every transaction, in order to be able to
use it afterward to check the server correctness.Using the Persistent Root ServiceThe default RootService, for simplicity, commits the state to RAM, and so it is unsuitable for real time safe
application. To have persistance, the application must instantiate aPersistentRootServiceobject, which stores
its state to disk.Let's see a simple example that uses state persistance:fromimmudb.clientimportImmudbClient,PersistentRootServiceclient=ImmudbClient(rs=PersistentRootService())client.login(username="immudb",password="immudb")client.verifiedTxById(42)client.verifiedGet(b"example")In this example, the Root Service is saved to the disk after every verified transaction. As you can see, it is very
easy to use. Just create and use the PersistentRootService object in the client initialization.Process and threadsPlease keep in mind that the implementation is not thread/process safe. If you are using a multi-process application,
it is advisable to use a different state file for every instance: just pass the filename as argument to the
PersistentRootService constructor:client=ImmudbClient(rs=PersistentRootService("rootfilename"))Default rootfile is "~/.immudbRoot"If needed/wanted, it is also easy to extend the default implementation adding synchronization primitives to the get/set methods.
In this way, more than one immudb client can share the same PersistentRootService instance without interering each other.Cryptographic state signingTo increase safety, it is possible to generate a private key and use it to sign every verification response. Clients can
then use the corresponding public key to check for response correctness.Key generationYou can useopensslto create a private key, and then extract the public key:opensslecparam-nameprime256v1-genkey-noout-outprivate_signing_key.pem
opensslec-inprivate_signing_key.pem-pubout-outpublic_signing_key.pemKey usage (server side)On immudb server, use--signingKey private_signing_key.pemto activate cryptographic signature.Key usage (client/SDK side)On immudb python SDK, just pass the public key filename to the ImmudbClient constructor:client=ImmudbClient(publicKeyFile="/certs/public_signing_key.pem")Every transaction will be then automatically checked. An exception is thrown if the cryptographic check fails.ContributingWe welcome contributions. Feel free to join the team!To report bugs or get help, useGitHub's issues.