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
Base
instance and a parent factory.Once a stored factory is created, it tries to lazy-load all current configuration for given
type_
.Args
type_
:Base
Base
class typename_
:str
, optional- factory name. Defaults to None.
parent_instance_
:Base
, optional- a parent
Base
instance. 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: break
Ancestors
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): pass
Ancestors
- builtins.Exception
- builtins.BaseException