def normLogLevel(valu): ''' Norm a log level value to a integer. Args: valu: The value to norm ( a string or integer ). Returns: int: A valid Logging log level. ''' if isinstance(valu, int): if valu not in s_const.LOG_LEVEL_INVERSE_CHOICES: raise s_exc.BadArg(mesg=f'Invalid log level provided: {valu}', valu=valu) return valu if isinstance(valu, str): valu = valu.strip() try: valu = int(valu) except ValueError: valu = valu.upper() ret = s_const.LOG_LEVEL_CHOICES.get(valu) if ret is None: raise s_exc.BadArg(mesg=f'Invalid log level provided: {valu}', valu=valu) from None return ret else: return normLogLevel(valu) raise s_exc.BadArg(mesg=f'Unknown log level type: {type(valu)} {valu}', valu=valu)
async def delRuleIndx(self, indx): if indx < 0: raise s_exc.BadArg(mesg='Rule index must be greater than or equal to 0', valu=indx) rules = list(self.rules) try: rules.pop(indx) except IndexError: raise s_exc.BadArg(mesg='Rule does not exist at specified index.', valu=indx) from None await self.info.set('rules', rules)
async def setLocked(self, locked, logged=True): if not isinstance(locked, bool): raise s_exc.BadArg(mesg='setLocked requires a boolean') if logged: await self.auth.setUserInfo(self.iden, 'locked', locked) else: await self.auth._hndlsetUserInfo(self.iden, 'locked', locked)
async def setRoles(self, roleidens): ''' Replace all the roles for a given user with a new list of roles. Args: roleidens (list): A list of roleidens. Notes: The roleiden for the "all" role must be present in the new list of roles. This replaces all existing roles that the user has with the new roles. Returns: None ''' current_roles = list(self.info.get('roles')) roleidens = list(roleidens) if current_roles == roleidens: return if self.auth.allrole.iden not in roleidens: mesg = 'Role "all" must be in the list of roles set.' raise s_exc.BadArg(mesg=mesg) for iden in roleidens: await self.auth.reqRole(iden) await self.auth.setUserInfo(self.iden, 'roles', roleidens)
async def calculate(self, node, save=True, vers='3.1'): save = await s_stormtypes.tobool(save) if node.ndef[0] != 'risk:vuln': mesg = '$lib.infosec.cvss.calculate() requires a risk:vuln node.' raise s_exc.BadArg(mesg=mesg) rval = await self.calculateFromProps(node.props, vers=vers) if save and rval.get('ok'): score = rval.get('score') if score is not None: await node.set('cvss:score', score) scores = rval.get('scores', {}) basescore = scores.get('base') if basescore is not None: await node.set('cvss:score:base', basescore) temporalscore = scores.get('temporal') if temporalscore is not None: await node.set('cvss:score:temporal', temporalscore) environmentalscore = scores.get('environmental') if environmentalscore is not None: await node.set('cvss:score:environmental', environmentalscore) return rval
async def setArchived(self, archived): if not isinstance(archived, bool): raise s_exc.BadArg(mesg='setArchived requires a boolean') archived = bool(archived) await self.auth.setUserInfo(self.iden, 'archived', archived) if archived: await self.setLocked(True)
async def put(self, item): if self.closed: mesg = 'The Queue has been closed.' raise s_exc.BadArg(mesg=mesg) await self.q.put(item)
async def setPasswd(self, passwd): # Prevent empty string or non-string values if not passwd or not isinstance(passwd, str): raise s_exc.BadArg(mesg='Password must be a string') salt = s_common.guid() hashed = s_common.guid((salt, passwd)) await self.auth.setUserInfo(self.iden, 'passwd', (salt, hashed))
def chopurl(url, **opts): if isinstance(url, str): if url.find('://') == -1: newurl = alias(url) if newurl is None: raise s_exc.BadUrl(mesg=f':// not found in [{url}] and no alias found!', url=url) url = newurl info = s_urlhelp.chopurl(url) # flatten query params into info query = info.pop('query', None) if query is not None: info.update(query) elif isinstance(url, dict): info = dict(url) else: mesg = 'telepath.chopurl() requires a str or dict.' raise s_exc.BadArg(mesg) info.update(opts) return info
async def parse(self, valu): valu = await s_stormtypes.tostr(valu) try: todo = (xml_et.fromstring, (valu, ), {}) root = await s_coro.spawn(todo) return XmlElement(self.runt, root) except xml_et.ParseError as e: raise s_exc.BadArg(mesg=f'Invalid XML text: {str(e)}')
async def setViewInfo(self, name, valu): ''' Set a mutable view property. ''' if name not in ('name', 'desc', 'parent'): mesg = f'{name} is not a valid view info key' raise s_exc.BadOptValu(mesg=mesg) if name == 'parent': parent = self.core.getView(valu) if parent is None: mesg = 'The parent view must already exist.' raise s_exc.NoSuchView(mesg=mesg) if parent.iden == self.iden: mesg = 'A view may not have parent set to itself.' raise s_exc.BadArg(mesg=mesg) if parent.isForkOf(self.iden): mesg = 'Circular dependency of view parents is not supported.' raise s_exc.BadArg(mesg=mesg) if self.parent is not None: mesg = 'You may not set parent on a view which already has one.' raise s_exc.BadArg(mesg=mesg) if len(self.layers) != 1: mesg = 'You may not set parent on a view which has more than one layer.' raise s_exc.BadArg(mesg=mesg) self.parent = parent await self.info.set(name, valu) await self._calcForkLayers() for view in self.core.views.values(): if view.isForkOf(self.iden): await view._calcForkLayers() await self.core._calcViewsByLayer() else: await self.info.set(name, valu) return valu
async def delEdge(self, verb, n2iden): if not s_common.isbuidhex(n2iden): mesg = f'delEdge() got an invalid node iden: {n2iden}' raise s_exc.BadArg(mesg=mesg) nodeedits = ((self.buid, self.form.name, ((s_layer.EDIT_EDGE_DEL, (verb, n2iden), ()), )), ) await self.snap.applyNodeEdits(nodeedits)
def _reqBackDirn(self, name): self._reqBackConf() path = s_common.genpath(self.backdirn, name) if not path.startswith(self.backdirn): mesg = 'Directory traversal detected' raise s_exc.BadArg(mesg=mesg) return path
async def setPasswd(self, passwd, nexs=True): # Prevent empty string or non-string values if not passwd or not isinstance(passwd, str): raise s_exc.BadArg(mesg='Password must be a string') shadow = getShadow(passwd) if nexs: await self.auth.setUserInfo(self.iden, 'passwd', shadow) else: await self.auth._hndlsetUserInfo(self.iden, 'passwd', shadow)
async def delBackup(self, name): self._reqBackConf() path = self._reqBackDirn(name) cellguid = os.path.join(path, 'cell.guid') if not os.path.isfile(cellguid): mesg = 'Specified backup path has no cell.guid file.' raise s_exc.BadArg(mesg=mesg) await s_coro.executor(shutil.rmtree, path, ignore_errors=True)
async def addEdge(self, verb, n2iden): if self.form.isrunt: mesg = f'Edges cannot be used with runt nodes: {self.form.full}' raise s_exc.IsRuntForm(mesg=mesg, form=self.form.full) if not s_common.isbuidhex(n2iden): mesg = f'addEdge() got an invalid node iden: {n2iden}' raise s_exc.BadArg(mesg=mesg) nodeedits = ((self.buid, self.form.name, ((s_layer.EDIT_EDGE_ADD, (verb, n2iden), ()), )), ) await self.snap.applyNodeEdits(nodeedits)
async def vectToProps(self, text): text = await s_stormtypes.tostr(text) props = {} try: for item in text.split('/'): name, valu = item.split(':') prop = vect2prop.get(name) if prop is None: mesg = f'Invalid Vector Element: {name}' raise s_exc.BadArg(mesg=mesg) props[prop] = valu except ValueError: mesg = f'Invalid CVSS Vector: {text}' raise s_exc.BadArg(mesg=mesg) from None return props
async def setRoleName(self, iden, name): if not isinstance(name, str): raise s_exc.BadArg(mesg='setRoleName() name must be a string') role = self.rolesbyname.get(name) if role is not None: if role.iden == iden: return raise s_exc.DupRoleName(name=name) role = await self.reqRole(iden) if role.name == 'all': mesg = 'Role "all" may not be renamed.' raise s_exc.BadArg(mesg=mesg) self.rolesbyname.pop(role.name, None) self.rolesbyname[name] = role role.name = name await role.node.set(name)
def genFangRegex(fangs, flags=regex.IGNORECASE): # Fangs must be matches of equal or smaller length in order for the # contextScrape API to function. for src, dst in fangs.items(): if len(dst) > len(src): raise s_exc.BadArg( mesg=f'fang dst[{dst}] must be <= in length to src[{src}]', src=src, dst=dst) restr = "|".join(map(regex.escape, fangs.keys())) re = regex.compile(restr, flags) return re
async def setAdmin(self, admin, gateiden=None, logged=True): if not isinstance(admin, bool): raise s_exc.BadArg(mesg='setAdmin requires a boolean') if logged: await self.auth.setUserInfo(self.iden, 'admin', admin, gateiden=gateiden) else: await self.auth._hndlsetUserInfo(self.iden, 'admin', admin, gateiden=gateiden)
def get(self, key): if self.iscorocall: raise s_exc.BadArg( 'cache was initialized with coroutine. Must use aget') valu = self.cache.get(key, s_common.novalu) if valu is not s_common.novalu: return valu valu = self.callback(key) if valu is s_common.novalu: return valu self.put(key, valu) return valu
async def runBackup(self, name=None, wait=True): if name is None: name = time.strftime('%Y%m%d%H%M%S', datetime.datetime.now().timetuple()) path = self._reqBackDirn(name) if os.path.isdir(path): mesg = 'Backup with name already exists' raise s_exc.BadArg(mesg=mesg) task = self.schedCoro(self._execBackTask(path)) if wait: await task return name
async def _libBytesPut(self, byts): ''' Save the given bytes variable to the axon. Returns: ($size, $sha256) Example: ($size, $sha2) = $lib.bytes.put($bytes) ''' if not isinstance(byts, bytes): mesg = '$lib.bytes.put() requires a bytes argument' raise s_exc.BadArg(mesg=mesg) await self.runt.snap.core.axready.wait() size, sha2 = await self.runt.snap.core.axon.put(byts) return (size, s_common.ehex(sha2))
async def revoke(self, iden, nexs=True): role = await self.auth.reqRole(iden) if role.name == 'all': mesg = 'Role "all" may not be revoked.' raise s_exc.BadArg(mesg=mesg) roles = list(self.info.get('roles')) if role.iden not in roles: return roles.remove(role.iden) if nexs: await self.auth.setUserInfo(self.iden, 'roles', roles) else: await self.auth._hndlsetUserInfo(self.iden, 'roles', roles)
async def setUserName(self, iden, name): if not isinstance(name, str): raise s_exc.BadArg(mesg='setUserName() name must be a string') user = self.usersbyname.get(name) if user is not None: if user.iden == iden: return raise s_exc.DupUserName(name=name) user = await self.reqUser(iden) self.usersbyname.pop(user.name, None) self.usersbyname[name] = user user.name = name await user.node.set(name)
def _nameAndNetwork(self, name, network): if network is None: svcfull = name try: svcname, svcnetw = name.split('.', 1) except ValueError: raise s_exc.BadArg( name=name, arg='name', mesg='Name must contain at least one "."') from None else: svcname = name svcnetw = network svcfull = f'{name}.{network}' return svcname, svcnetw, svcfull
async def addUser(self, name, passwd=None, email=None, iden=None): ''' Add a User to the Hive. Args: name (str): The name of the User. passwd (str): A optional password for the user. email (str): A optional email for the user. iden (str): A optional iden to use as the user iden. Returns: HiveUser: A Hive User. ''' if self.usersbyname.get(name) is not None: raise s_exc.DupUserName(name=name) if iden is None: iden = s_common.guid() else: if not s_common.isguid(iden): raise s_exc.BadArg(name='iden', arg=iden, mesg='Argument it not a valid iden.') if self.usersbyiden.get(iden) is not None: raise s_exc.DupIden(name=name, iden=iden, mesg='User already exists for the iden.') await self._push('user:add', iden, name) user = self.user(iden) if passwd is not None: await user.setPasswd(passwd) if email is not None: await self.setUserInfo(user.iden, 'email', email) # Everyone's a member of 'all' await user.grant(self.allrole.iden) return user
async def _delUser(self, iden): if iden == self.rootuser.iden: mesg = 'User "root" may not be deleted.' raise s_exc.BadArg(mesg=mesg) user = self.user(iden) if user is None: return self.usersbyiden.pop(user.iden) self.usersbyname.pop(user.name) path = self.node.full + ('users', user.iden) for gate in self.authgates.values(): await gate._delGateUser(user.iden) await user.fini() await self.node.hive.pop(path)
def get(self, key): if self.iscorocall: raise s_exc.BadArg( 'cache was initialized with coroutine. Must use aget') valu = self.cache.get(key, s_common.novalu) if valu is not s_common.novalu: return valu valu = self.callback(key) if valu is s_common.novalu: return valu self.cache[key] = valu self.fifo.append(key) while len(self.fifo) > self.size: key = self.fifo.popleft() self.cache.pop(key, None) return valu
def reqConfValu(self, key): ''' Get a configuration value. If that value is not present in the schema or is not set, then raise an exception. Args: key (str): The key to require. Returns: The requested value. ''' # Ensure that the key is in self.json_schema if key not in self.json_schema.get('properties', {}): raise s_exc.BadArg(mesg='Required key is not present in the configuration schema.', key=key) # Ensure that the key is present in self.conf if key not in self.conf: raise s_exc.NeedConfValu(mesg='Required key is not present in configuration data.', key=key) return self.conf.get(key)