Module jumpscale.core.identity
Expand source code
import requests
from collections import namedtuple
from nacl.exceptions import CryptoError
from jumpscale.core import exceptions
from jumpscale.core.base import Base, StoredFactory, fields
from jumpscale.core.config import get_config, update_config
from jumpscale.core.exceptions import Input, Value
from jumpscale.data import serializers
from jumpscale.data.encryption import mnemonic, generate_mnemonic
from jumpscale.data.nacl import NACL
from jumpscale.data.idgenerator import random_int
from jumpscale.data.types import Email
from jumpscale.tools.console import ask_choice, ask_string
class Identity(Base):
    _tid = fields.Integer(default=-1)
    words = fields.Secret()
    email = fields.String()
    tname = fields.String()
    admins = fields.List(fields.String())
    def __init__(
        self,
        tname=None,
        email=None,
        words=None,
        _tid=-1,
        admins=None,
        *args,
        **kwargs,
    ):
        """
        Get Identity
        Requires: tname, email and words or tid and words
        Arguments:
            tname (str, optional): Name eg. example.3bot
            email (str, optional): Email of identity
            words (str): Words used to secure identity
            admins (list of str, optional): Admins
        Raises: NotFound incase tid is passed but does not exists
        Raises: Input: when params are missing
        """
        if not words:
            words = generate_mnemonic()
        super().__init__(
            tname=tname,
            email=email,
            words=words,
            _tid=_tid,
            admins=admins,
            *args,
            **kwargs,
        )
        self._nacl = None
        self.verify_configuration()
    @property
    def nacl(self):
        if not self._nacl:
            seed = mnemonic.mnemonic_to_key(self.words.strip())
            self._nacl = NACL(private_key=seed)
        return self._nacl
    def verify_configuration(self):
        """
        Verifies passed arguments to constructor
        Raises: NotFound incase tid is passed but does not exists
        Raises: Input: when params are missing
        """
        if not self.words:
            raise Input("Words are mandotory for an indentity")
        if self._tid != -1:
            self.register()
        else:
            for key in ["email", "tname"]:
                if not getattr(self, key):
                    raise Value(f"Threebot {key} not configured")
    @property
    def tid(self):
        if self._tid == -1:
            self.register()
        return self._tid
    def register(self, host=None):
        # self.verify_configuration()
        if self.tname not in self.admins:
            self.admins.append(self.tname)
        self._tid = random_int(1, 100000000)
        return self._tid
    def set_default(self):
        from jumpscale.loader import j
        return j.core.identity.set_default(self.instance_name)
def get_identity():
    return IdentityFactory(Identity).me
RESTART_CHOICE = "Restart from the begining"
REENTER_CHOICE = "Re-Enter your value"
CHOICES = [RESTART_CHOICE, REENTER_CHOICE]
IdentityInfo = namedtuple("IdentityInfo", ["identity", "email", "words"])
class Restart(Exception):
    pass
class IdentityFactory(StoredFactory):
    _me = None
    def new(
        self,
        name,
        tname=None,
        email=None,
        words=None,
        tid=-1,
        admins=None,
        **kwargs,
    ):
        instance = super().new(name, tname=tname, email=email, words=words, _tid=tid, admins=admins, **kwargs)
        instance.save()
        return instance
    @property
    def is_configured(self):
        return self._me is not None
    @property
    def me(self):
        if not self._me:
            config = get_config()
            default = config["threebot"]["default"]
            if default:
                self.__class__._me = self.get(name=default)
            else:
                for identity in self.list_all():
                    self.__class__._me = self.get(identity)
                    break
                else:
                    raise Value("No configured identity found")
        return self._me
    def set_default(self, name):
        config = get_config()
        config["threebot"]["default"] = name
        update_config(config)
        self.__class__._me = None
    def get_user(self, tname):
        response = requests.get(f"https://login.threefold.me/api/users/{tname}")
        if response.status_code == 404:
            raise exceptions.NotFound(
                "\nThis identity does not exist in 3bot mobile app connect, Please create an idenity first using 3Bot Connect mobile Application\n"
            )
        return response.json()
    def ask(self):
        """get identity information interactively"""
        def check_email(email):
            # TODO: a way to check/verify email (threefold connect or openkyc?)
            return Email().check(email)
        def with_error(e):
            """used in a loop to re-enter the value or break by raising `Restart` exception"""
            response = ask_choice(f"{e}, What would you like to do? ", CHOICES)
            if response == RESTART_CHOICE:
                raise Restart
        def get_identity_info():
            def fill_words():
                return ask_string("Copy the phrase from your 3bot Connect app here: ")
            def fill_identity():
                identity = ask_string("what is your threebot name (identity)? ")
                if "." not in identity:
                    identity += ".3bot"
                return identity
            user = None
            while not user:
                identity = fill_identity()
                try:
                    user = self.get_user(identity)
                except exceptions.NotFound as e:
                    with_error(e)
            while True:
                email = ask_string("What is the email address associated with your identity? ")
                if check_email(email):
                    break
                else:
                    with_error("This Email address is not valid")
            print("Configured email for this identity is {}".format(email))
            # time to do validation of words
            while True:
                words = fill_words()
                try:
                    seed = mnemonic.mnemonic_to_key(words.strip())
                    key = NACL(seed).get_verification_key()
                    if user and key != serializers.base64.decode(user["publicKey"]):
                        raise exceptions.Input
                    break
                except (exceptions.NotFound, exceptions.Input, CryptoError):
                    with_error("Seems one or more more words entered is invalid")
            return IdentityInfo(identity, email, words)
        while True:
            try:
                return get_identity_info()
            except Restart:
                continue
            except KeyboardInterrupt:
                break
def export_module_as():
    return IdentityFactory(Identity)
Functions
def export_module_as()- 
Expand source code
def export_module_as(): return IdentityFactory(Identity) def get_identity()- 
Expand source code
def get_identity(): return IdentityFactory(Identity).me 
Classes
class Identity (tname=None, email=None, words=None, admins=None, *args, **kwargs)- 
A simple attribute-based namespace.
SimpleNamespace(**kwargs)
Get Identity
Requires: tname, email and words or tid and words
Arguments
tname (str, optional): Name eg. example.3bot email (str, optional): Email of identity words (str): Words used to secure identity admins (list of str, optional): Admins
Raises: NotFound incase tid is passed but does not exists Raises: Input: when params are missing
Expand source code
class Identity(Base): _tid = fields.Integer(default=-1) words = fields.Secret() email = fields.String() tname = fields.String() admins = fields.List(fields.String()) def __init__( self, tname=None, email=None, words=None, _tid=-1, admins=None, *args, **kwargs, ): """ Get Identity Requires: tname, email and words or tid and words Arguments: tname (str, optional): Name eg. example.3bot email (str, optional): Email of identity words (str): Words used to secure identity admins (list of str, optional): Admins Raises: NotFound incase tid is passed but does not exists Raises: Input: when params are missing """ if not words: words = generate_mnemonic() super().__init__( tname=tname, email=email, words=words, _tid=_tid, admins=admins, *args, **kwargs, ) self._nacl = None self.verify_configuration() @property def nacl(self): if not self._nacl: seed = mnemonic.mnemonic_to_key(self.words.strip()) self._nacl = NACL(private_key=seed) return self._nacl def verify_configuration(self): """ Verifies passed arguments to constructor Raises: NotFound incase tid is passed but does not exists Raises: Input: when params are missing """ if not self.words: raise Input("Words are mandotory for an indentity") if self._tid != -1: self.register() else: for key in ["email", "tname"]: if not getattr(self, key): raise Value(f"Threebot {key} not configured") @property def tid(self): if self._tid == -1: self.register() return self._tid def register(self, host=None): # self.verify_configuration() if self.tname not in self.admins: self.admins.append(self.tname) self._tid = random_int(1, 100000000) return self._tid def set_default(self): from jumpscale.loader import j return j.core.identity.set_default(self.instance_name)Ancestors
- Base
 - types.SimpleNamespace
 
Instance variables
var admins- 
getter method this property
will call
_get_value, which would if the value is already defined and will get the default value if notReturns
any- the field value
 
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field) var email- 
getter method this property
will call
_get_value, which would if the value is already defined and will get the default value if notReturns
any- the field value
 
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field) var nacl- 
Expand source code
@property def nacl(self): if not self._nacl: seed = mnemonic.mnemonic_to_key(self.words.strip()) self._nacl = NACL(private_key=seed) return self._nacl var tid- 
Expand source code
@property def tid(self): if self._tid == -1: self.register() return self._tid var tname- 
getter method this property
will call
_get_value, which would if the value is already defined and will get the default value if notReturns
any- the field value
 
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field) var words- 
getter method this property
will call
_get_value, which would if the value is already defined and will get the default value if notReturns
any- the field value
 
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field) 
Methods
def register(self, host=None)- 
Expand source code
def register(self, host=None): # self.verify_configuration() if self.tname not in self.admins: self.admins.append(self.tname) self._tid = random_int(1, 100000000) return self._tid def set_default(self)- 
Expand source code
def set_default(self): from jumpscale.loader import j return j.core.identity.set_default(self.instance_name) def verify_configuration(self)- 
Verifies passed arguments to constructor
Raises: NotFound incase tid is passed but does not exists Raises: Input: when params are missing
Expand source code
def verify_configuration(self): """ Verifies passed arguments to constructor Raises: NotFound incase tid is passed but does not exists Raises: Input: when params are missing """ if not self.words: raise Input("Words are mandotory for an indentity") if self._tid != -1: self.register() else: for key in ["email", "tname"]: if not getattr(self, key): raise Value(f"Threebot {key} not configured") 
Inherited members
 class IdentityFactory (type_, name_=None, parent_instance_=None, parent_factory_=None)- 
Stored factories are a custom type of
Factory, which uses current configured store backend to store all instance configurations.get a new stored factory given the type to create and store instances for.
Any factory can have a name, parent
Baseinstance and a parent factory.Once a stored factory is created, it tries to lazy-load all current configuration for given
type_.Args
type_:BaseBaseclass typename_:str, optional- factory name. Defaults to None.
 parent_instance_:Base, optional- a parent 
Baseinstance. Defaults to None. parent_factory_:Factory, optional- a parent 
Factory. Defaults to None. 
Expand source code
class IdentityFactory(StoredFactory): _me = None def new( self, name, tname=None, email=None, words=None, tid=-1, admins=None, **kwargs, ): instance = super().new(name, tname=tname, email=email, words=words, _tid=tid, admins=admins, **kwargs) instance.save() return instance @property def is_configured(self): return self._me is not None @property def me(self): if not self._me: config = get_config() default = config["threebot"]["default"] if default: self.__class__._me = self.get(name=default) else: for identity in self.list_all(): self.__class__._me = self.get(identity) break else: raise Value("No configured identity found") return self._me def set_default(self, name): config = get_config() config["threebot"]["default"] = name update_config(config) self.__class__._me = None def get_user(self, tname): response = requests.get(f"https://login.threefold.me/api/users/{tname}") if response.status_code == 404: raise exceptions.NotFound( "\nThis identity does not exist in 3bot mobile app connect, Please create an idenity first using 3Bot Connect mobile Application\n" ) return response.json() def ask(self): """get identity information interactively""" def check_email(email): # TODO: a way to check/verify email (threefold connect or openkyc?) return Email().check(email) def with_error(e): """used in a loop to re-enter the value or break by raising `Restart` exception""" response = ask_choice(f"{e}, What would you like to do? ", CHOICES) if response == RESTART_CHOICE: raise Restart def get_identity_info(): def fill_words(): return ask_string("Copy the phrase from your 3bot Connect app here: ") def fill_identity(): identity = ask_string("what is your threebot name (identity)? ") if "." not in identity: identity += ".3bot" return identity user = None while not user: identity = fill_identity() try: user = self.get_user(identity) except exceptions.NotFound as e: with_error(e) while True: email = ask_string("What is the email address associated with your identity? ") if check_email(email): break else: with_error("This Email address is not valid") print("Configured email for this identity is {}".format(email)) # time to do validation of words while True: words = fill_words() try: seed = mnemonic.mnemonic_to_key(words.strip()) key = NACL(seed).get_verification_key() if user and key != serializers.base64.decode(user["publicKey"]): raise exceptions.Input break except (exceptions.NotFound, exceptions.Input, CryptoError): with_error("Seems one or more more words entered is invalid") return IdentityInfo(identity, email, words) while True: try: return get_identity_info() except Restart: continue except KeyboardInterrupt: breakAncestors
Instance variables
var is_configured- 
Expand source code
@property def is_configured(self): return self._me is not None var me- 
Expand source code
@property def me(self): if not self._me: config = get_config() default = config["threebot"]["default"] if default: self.__class__._me = self.get(name=default) else: for identity in self.list_all(): self.__class__._me = self.get(identity) break else: raise Value("No configured identity found") return self._me 
Methods
def ask(self)- 
get identity information interactively
Expand source code
def ask(self): """get identity information interactively""" def check_email(email): # TODO: a way to check/verify email (threefold connect or openkyc?) return Email().check(email) def with_error(e): """used in a loop to re-enter the value or break by raising `Restart` exception""" response = ask_choice(f"{e}, What would you like to do? ", CHOICES) if response == RESTART_CHOICE: raise Restart def get_identity_info(): def fill_words(): return ask_string("Copy the phrase from your 3bot Connect app here: ") def fill_identity(): identity = ask_string("what is your threebot name (identity)? ") if "." not in identity: identity += ".3bot" return identity user = None while not user: identity = fill_identity() try: user = self.get_user(identity) except exceptions.NotFound as e: with_error(e) while True: email = ask_string("What is the email address associated with your identity? ") if check_email(email): break else: with_error("This Email address is not valid") print("Configured email for this identity is {}".format(email)) # time to do validation of words while True: words = fill_words() try: seed = mnemonic.mnemonic_to_key(words.strip()) key = NACL(seed).get_verification_key() if user and key != serializers.base64.decode(user["publicKey"]): raise exceptions.Input break except (exceptions.NotFound, exceptions.Input, CryptoError): with_error("Seems one or more more words entered is invalid") return IdentityInfo(identity, email, words) while True: try: return get_identity_info() except Restart: continue except KeyboardInterrupt: break def get_user(self, tname)- 
Expand source code
def get_user(self, tname): response = requests.get(f"https://login.threefold.me/api/users/{tname}") if response.status_code == 404: raise exceptions.NotFound( "\nThis identity does not exist in 3bot mobile app connect, Please create an idenity first using 3Bot Connect mobile Application\n" ) return response.json() def set_default(self, name)- 
Expand source code
def set_default(self, name): config = get_config() config["threebot"]["default"] = name update_config(config) self.__class__._me = None 
Inherited members
 class IdentityInfo (identity, email, words)- 
IdentityInfo(identity, email, words)
Ancestors
- builtins.tuple
 
Instance variables
var email- 
Alias for field number 1
 var identity- 
Alias for field number 0
 var words- 
Alias for field number 2
 
 class Restart (*args, **kwargs)- 
Common base class for all non-exit exceptions.
Expand source code
class Restart(Exception): passAncestors
- builtins.Exception
 - builtins.BaseException