From 69471e0d374ee2c044045120dd1a945a761b35d5 Mon Sep 17 00:00:00 2001 From: terrtia Date: Mon, 26 Aug 2024 15:56:46 +0200 Subject: [PATCH] chg: [core] add users organisation + tracker acl by organisation --- bin/lib/Tracker.py | 194 ++++++++++++------ bin/lib/ail_users.py | 176 ++++++++++++++++ update/v5.0/DB_KVROCKS_MIGRATION.py | 2 +- var/www/blueprints/hunters.py | 59 +++--- var/www/blueprints/settings_b.py | 50 +++++ var/www/templates/hunter/tracker_add.html | 20 +- var/www/templates/hunter/tracker_show.html | 6 +- .../templates/hunter/trackersManagement.html | 80 ++++++++ var/www/templates/settings/create_org.html | 79 +++++++ var/www/templates/settings/menu_sidebar.html | 17 ++ var/www/templates/settings/orgs_list.html | 99 +++++++++ 11 files changed, 686 insertions(+), 96 deletions(-) create mode 100644 var/www/templates/settings/create_org.html create mode 100644 var/www/templates/settings/orgs_list.html diff --git a/bin/lib/Tracker.py b/bin/lib/Tracker.py index 5bd1c47b..96f21998 100755 --- a/bin/lib/Tracker.py +++ b/bin/lib/Tracker.py @@ -186,10 +186,13 @@ class Tracker: def is_level_user(self): return self.get_level() == 0 + def is_level_org(self): + return self.get_level() == 2 + def is_level_global(self): return self.get_level() == 1 - def _set_level(self, level, tracker_type=None, user=None): + def _set_level(self, level, tracker_type=None, org=None, user=None): if not tracker_type: tracker_type = self.get_type() if level == 0: # user only @@ -200,6 +203,9 @@ class Tracker: elif level == 1: # global r_tracker.sadd('global:tracker', self.uuid) r_tracker.sadd(f'global:tracker:{tracker_type}', self.uuid) + elif level == 2: # org only + r_tracker.sadd(f'org:tracker:{org}', self.uuid) + r_tracker.sadd(f'org:tracker:{org}:{tracker_type}', self.uuid) self._set_field('level', level) def get_filters(self): @@ -252,6 +258,9 @@ class Tracker: def _del_mails(self): r_tracker.delete(f'tracker:mail:{self.uuid}') + def get_org(self): + return self._get_field('org') + def get_user(self): return self._get_field('user_id') @@ -285,6 +294,8 @@ class Tracker: 'date': self.get_date(), 'first_seen': self.get_first_seen(), 'last_seen': self.get_last_seen()} + if 'org' in options: + meta['org'] = self.get_org() if 'user' in options: meta['user'] = self.get_user() if 'level' in options: @@ -391,7 +402,7 @@ class Tracker: # TODO escape custom tags # TODO escape mails ???? - def create(self, tracker_type, to_track, user_id, level, description=None, filters={}, tags=[], mails=[], webhook=None): + def create(self, tracker_type, to_track, org, user_id, level, description=None, filters={}, tags=[], mails=[], webhook=None): if self.exists(): raise Exception('Error: Tracker already exists') @@ -413,6 +424,7 @@ class Tracker: self._set_field('tracked', to_track) self._set_field('type', tracker_type) self._set_field('date', datetime.date.today().strftime("%Y%m%d")) + self._set_field('org', org) self._set_field('user_id', user_id) if description: self._set_field('description', escape(description)) @@ -426,8 +438,10 @@ class Tracker: r_tracker.sadd('trackers:all', self.uuid) r_tracker.sadd(f'trackers:all:{tracker_type}', self.uuid) + + # TRACKER LEVEL - self._set_level(level, tracker_type=tracker_type, user=user_id) + self._set_level(level, tracker_type=tracker_type, org=org, user=user_id) # create tracker tags list if tags: @@ -454,7 +468,7 @@ class Tracker: trigger_trackers_refresh(tracker_type) return self.uuid - def edit(self, tracker_type, to_track, level, description=None, filters={}, tags=[], mails=[], webhook=None): + def edit(self, tracker_type, to_track, level, org, description=None, filters={}, tags=[], mails=[], webhook=None): # TODO ADMIN: EDIT ORG UUID # edit tracker old_type = self.get_type() @@ -481,9 +495,14 @@ class Tracker: # LEVEL if old_level == 0: r_tracker.srem(f'user:tracker:{user_id}:{old_type}', self.uuid) + r_tracker.srem(f'user:tracker:{user_id}', self.uuid) elif old_level == 1: r_tracker.srem(f'global:tracker:{old_type}', self.uuid) - self._set_level(level, tracker_type=tracker_type, user=user_id) + r_tracker.srem(f'global:tracker', self.uuid) + elif old_level == 2: + r_tracker.srem(f'org:tracker:{self.get_org()}:{old_type}', self.uuid) + r_tracker.srem(f'org:tracker:{self.get_org()}', self.uuid) + self._set_level(level, tracker_type=tracker_type, org=org, user=user_id) # Delete OLD YARA Rule File if old_type == 'yara': if not is_default_yara_rule(old_to_track): @@ -506,11 +525,16 @@ class Tracker: # Same Type elif level != old_level: - if level == 0: - r_tracker.srem('global:tracker', self.uuid) - elif level == 1: + if old_level == 0: r_tracker.srem(f'user:tracker:{user_id}', self.uuid) - self._set_level(level, tracker_type=tracker_type, user=user_id) + r_tracker.srem(f'user:tracker:{user_id}:{tracker_type}', self.uuid) + elif old_level == 1: + r_tracker.srem('global:tracker', self.uuid) + r_tracker.srem(f'global:tracker:{tracker_type}', self.uuid) + elif old_level == 2: + r_tracker.srem(f'org:tracker:{self.get_org()}', self.uuid) + r_tracker.srem(f'org:tracker:{self.get_org()}:{tracker_type}', self.uuid) + self._set_level(level, tracker_type=tracker_type, org=org, user=user_id) # To Track Edited if to_track != old_to_track: @@ -589,21 +613,25 @@ class Tracker: elif level == 1: # global r_tracker.srem('global:tracker', self.uuid) r_tracker.srem(f'global:tracker:{tracker_type}', self.uuid) + elif level == 2: # TODO ORG check delete permission + org = self.get_org() + r_tracker.srem(f'org:tracker:{org}', self.uuid) + r_tracker.srem(f'org:tracker:{org}:{tracker_type}', self.uuid) # meta r_tracker.delete(f'tracker:{self.uuid}') trigger_trackers_refresh(tracker_type) -def create_tracker(tracker_type, to_track, user_id, level, description=None, filters={}, tags=[], mails=[], webhook=None, tracker_uuid=None): +def create_tracker(tracker_type, to_track, org, user_id, level, description=None, filters={}, tags=[], mails=[], webhook=None, tracker_uuid=None): if not tracker_uuid: tracker_uuid = str(uuid.uuid4()) tracker = Tracker(tracker_uuid) - return tracker.create(tracker_type, to_track, user_id, level, description=description, filters=filters, tags=tags, + return tracker.create(tracker_type, to_track, org, user_id, level, description=description, filters=filters, tags=tags, mails=mails, webhook=webhook) -def _re_create_tracker(tracker_type, tracker_uuid, to_track, user_id, level, description=None, filters={}, tags=[], mails=[], webhook=None, first_seen=None, last_seen=None): - create_tracker(tracker_type, to_track, user_id, level, description=description, filters=filters, +def _re_create_tracker(tracker_type, tracker_uuid, to_track, org, user_id, level, description=None, filters={}, tags=[], mails=[], webhook=None, first_seen=None, last_seen=None): + create_tracker(tracker_type, to_track, org, user_id, level, description=description, filters=filters, tags=tags, mails=mails, webhook=webhook, tracker_uuid=tracker_uuid) def get_trackers_types(): @@ -649,6 +677,12 @@ def get_user_trackers(user_id, tracker_type=None): else: return r_tracker.smembers(f'user:tracker:{user_id}') +def get_org_trackers(org, tracker_type=None): + if tracker_type: + return r_tracker.smembers(f'org:tracker:{org}:{tracker_type}') + else: + return r_tracker.smembers(f'org:tracker:{org}') + def get_nb_global_trackers(tracker_type=None): if tracker_type: return r_tracker.scard(f'global:tracker:{tracker_type}') @@ -661,6 +695,13 @@ def get_nb_user_trackers(user_id, tracker_type=None): else: return r_tracker.scard(f'user:tracker:{user_id}') +def get_nb_org_trackers(org, tracker_type=None): + if tracker_type: + return r_tracker.scard(f'org:tracker:{org}:{tracker_type}') + else: + return r_tracker.scard(f'org:tracker:{org}') + + def get_user_trackers_meta(user_id, tracker_type=None): metas = [] for tracker_uuid in get_user_trackers(user_id, tracker_type=tracker_type): @@ -675,6 +716,13 @@ def get_global_trackers_meta(tracker_type=None): metas.append(tracker.get_meta(options={'description', 'mails', 'sparkline', 'tags'})) return metas +def get_org_trackers_meta(user_org, tracker_type=None): + metas = [] + for tracker_uuid in get_org_trackers(user_org, tracker_type=tracker_type): + tracker = Tracker(tracker_uuid) + metas.append(tracker.get_meta(options={'description', 'mails', 'sparkline', 'tags'})) + return metas + def get_users_trackers_meta(): trackers = [] for tracker_uuid in get_trackers(): @@ -683,6 +731,14 @@ def get_users_trackers_meta(): trackers.append(tracker.get_meta(options={'mails', 'sparkline', 'tags'})) return trackers +def get_orgs_trackers_meta(): + trackers = [] + for tracker_uuid in get_trackers(): + tracker = Tracker(tracker_uuid) + if tracker.is_level_org(): + trackers.append(tracker.get_meta(options={'mails', 'sparkline', 'tags'})) + return trackers + def get_trackers_graph_by_day(l_trackers, num_day=31, date_from=None, date_to=None): if date_from and date_to: date_range = Date.substract_date(date_from, date_to) @@ -725,13 +781,14 @@ def get_user_dashboard(user_id): # TODO SORT + REMOVE OLDER ROWS (trim) return trackers -def get_trackers_stats(user_id): +def get_trackers_stats(user_org, user_id): stats = {'all': 0} for tracker_type in get_trackers_types(): nb_global = get_nb_global_trackers(tracker_type=tracker_type) nb_user = get_nb_user_trackers(user_id, tracker_type=tracker_type) - stats[tracker_type] = nb_global + nb_user - stats['all'] += nb_global + nb_user + nb_org = get_nb_org_trackers(user_org, tracker_type=tracker_type) + stats[tracker_type] = nb_global + nb_user + nb_org + stats['all'] += nb_global + nb_user + nb_org return stats @@ -789,7 +846,7 @@ def api_check_tracker_uuid(tracker_uuid): return {"status": "error", "reason": "Unknown uuid"}, 404 return None -def api_check_tracker_acl(tracker_uuid, user_id): +def api_check_tracker_acl(tracker_uuid, user_org, user_id): res = api_check_tracker_uuid(tracker_uuid) if res: return res @@ -797,31 +854,45 @@ def api_check_tracker_acl(tracker_uuid, user_id): if tracker.is_level_user(): if tracker.get_user() != user_id or not AILUser(user_id).is_in_role('admin'): return {"status": "error", "reason": "Access Denied"}, 403 + elif tracker.is_level_org(): + if tracker.get_org() != user_org or not AILUser(user_id).is_in_role('admin'): + return {"status": "error", "reason": "Access Denied"}, 403 return None -def api_is_allowed_to_edit_tracker(tracker_uuid, user_id): - if not is_valid_uuid_v4(tracker_uuid): - return {"status": "error", "reason": "Invalid uuid"}, 400 - tracker_creator = r_tracker.hget('tracker:{}'.format(tracker_uuid), 'user_id') - if not tracker_creator: - return {"status": "error", "reason": "Unknown uuid"}, 404 - user = AILUser(user_id) - if not user.is_in_role('admin') and user_id != tracker_creator: - return {"status": "error", "reason": "Access Denied"}, 403 - return {"uuid": tracker_uuid}, 200 - - -def api_is_allowed_to_access_tracker(tracker_uuid, user_id): - if not is_valid_uuid_v4(tracker_uuid): - return {"status": "error", "reason": "Invalid uuid"}, 400 - tracker_creator = r_tracker.hget('tracker:{}'.format(tracker_uuid), 'user_id') - if not tracker_creator: - return {"status": "error", "reason": "Unknown uuid"}, 404 - user = AILUser(user_id) - if not is_tracker_global_level(tracker_uuid): - if not user.is_in_role('admin') and user_id != tracker_creator: +def api_is_allowed_to_edit_tracker(tracker_uuid, user_org, user_id): + res = api_check_tracker_uuid(tracker_uuid) + if res: + return res + tracker = Tracker(tracker_uuid) + if tracker.is_level_user(): + if tracker.get_user() != user_id or not AILUser(user_id).is_in_role('admin'): return {"status": "error", "reason": "Access Denied"}, 403 - return {"uuid": tracker_uuid}, 200 + elif tracker.is_level_org(): + if tracker.get_org() != user_org or not AILUser(user_id).is_in_role('admin'): + return {"status": "error", "reason": "Access Denied"}, 403 + else: # global + if tracker.get_user() != user_id or not AILUser(user_id).is_in_role('admin'): + return {"status": "error", "reason": "Access Denied"}, 403 + return None + +def api_is_allowed_to_edit_tracker_level(tracker_uuid, user_org, user_id, new_level): + tracker = Tracker(tracker_uuid) + level = tracker.get_level() + if level == new_level: + return None + # Global Edit + if level == 1: + if new_level == 0: + if tracker.get_user() != user_id or not AILUser(user_id).is_in_role('admin'): + return {"status": "error", "reason": "Access Denied"}, 403 + elif new_level == 2: + if tracker.get_org() != user_org or not AILUser(user_id).is_in_role('admin'): + return {"status": "error", "reason": "Access Denied"}, 403 + # Community Edit + elif level == 2: + if new_level == 0: + if tracker.get_user() != user_id or not AILUser(user_id).is_in_role('admin'): + return {"status": "error", "reason": "Access Denied"}, 403 ##-- ACL --## @@ -922,7 +993,7 @@ def api_validate_tracker_to_add(to_track, tracker_type, nb_words=1): return {"status": "error", "reason": "Incorrect type"}, 400 return {"status": "success", "tracked": to_track, "type": tracker_type}, 200 -def api_add_tracker(dict_input, user_id): +def api_add_tracker(dict_input, org, user_id): to_track = dict_input.get('tracked', None) if not to_track: return {"status": "error", "reason": "Tracker not provided"}, 400 @@ -982,17 +1053,17 @@ def api_add_tracker(dict_input, user_id): level = int(level) except TypeError: level = 1 - if level not in range(0, 1): + if level not in range(0, 3): level = 1 - tracker_uuid = create_tracker(tracker_type, to_track, user_id, level, description=description, filters=filters, + tracker_uuid = create_tracker(tracker_type, to_track, org, user_id, level, description=description, filters=filters, tags=tags, mails=mails, webhook=webhook) return {'tracked': to_track, 'type': tracker_type, 'uuid': tracker_uuid}, 200 -def api_edit_tracker(dict_input, user_id): +def api_edit_tracker(dict_input, user_org, user_id): tracker_uuid = dict_input.get('uuid') - res = api_check_tracker_acl(tracker_uuid, user_id) + res = api_check_tracker_acl(tracker_uuid, user_org, user_id) if res: return res @@ -1004,6 +1075,18 @@ def api_edit_tracker(dict_input, user_id): tracker_type = dict_input.get('type', None) if not tracker_type: return {"status": "error", "reason": "Tracker type not provided"}, 400 + + level = dict_input.get('level', 1) + try: + level = int(level) + except TypeError: + level = 1 + if level not in range(0, 3): + level = 1 + res = api_is_allowed_to_edit_tracker_level(tracker_uuid, user_org, user_id, level) + if res: + return res + nb_words = dict_input.get('nb_words', 1) description = dict_input.get('description', '') description = escape(description) @@ -1053,31 +1136,23 @@ def api_edit_tracker(dict_input, user_id): if subtype not in obj_subtypes: return {"status": "error", "reason": "Invalid Tracker Object subtype"}, 400 - level = dict_input.get('level', 1) - try: - level = int(level) - except TypeError: - level = 1 - if level not in range(0, 1): - level = 1 - - tracker.edit(tracker_type, to_track, level, description=description, filters=filters, + tracker.edit(tracker_type, to_track, level, user_org, description=description, filters=filters, tags=tags, mails=mails, webhook=webhook) return {'tracked': to_track, 'type': tracker_type, 'uuid': tracker_uuid}, 200 -def api_delete_tracker(data, user_id): +def api_delete_tracker(data, user_org, user_id): tracker_uuid = data.get('uuid') - res = api_check_tracker_acl(tracker_uuid, user_id) + res = api_check_tracker_acl(tracker_uuid, user_org, user_id) if res: return res tracker = Tracker(tracker_uuid) return tracker.delete(), 200 -def api_tracker_add_object(data, user_id): +def api_tracker_add_object(data, user_org, user_id): tracker_uuid = data.get('uuid') - res = api_check_tracker_acl(tracker_uuid, user_id) + res = api_check_tracker_acl(tracker_uuid, user_org, user_id) if res: return res tracker = Tracker(tracker_uuid) @@ -1092,9 +1167,9 @@ def api_tracker_add_object(data, user_id): return {"status": "error", "reason": "Invalid Object"}, 400 return tracker.add(obj_type, subtype, obj_id, date=date), 200 -def api_tracker_remove_object(data, user_id): +def api_tracker_remove_object(data, user_org, user_id): tracker_uuid = data.get('uuid') - res = api_check_tracker_acl(tracker_uuid, user_id) + res = api_check_tracker_acl(tracker_uuid, user_org, user_id) if res: return res @@ -1216,7 +1291,6 @@ def get_tracked_yara_rules(): else: rules[tracked] = rule to_track[obj_type] = yara.compile(filepaths=rules) - print(to_track) return to_track def reload_yara_rules(): diff --git a/bin/lib/ail_users.py b/bin/lib/ail_users.py index 60953c27..b39d2adf 100755 --- a/bin/lib/ail_users.py +++ b/bin/lib/ail_users.py @@ -20,8 +20,10 @@ sys.path.append(os.environ['AIL_BIN']) # Import Project packages ################################## from lib import ail_logger +from lib.ail_core import is_valid_uuid_v4 from lib.ConfigLoader import ConfigLoader + # LOGS access_logger = ail_logger.get_access_config() @@ -40,6 +42,145 @@ config_loader = None regex_password = r'^(?=(.*\d){2})(?=.*[a-z])(?=.*[A-Z]).{10,100}$' regex_password = re.compile(regex_password) +#### ORGANISATIONS #### + +# TODO EDIT +# TODO DELETE CHECK + +# TODO ORG View + +# TODO TAGS +# TODO TAGS USERS ???? + +# TODO Check if ORG name is UNIQUE + +def get_orgs(): + return r_serv_db.smembers(f'ail:orgs') + +def is_user_in_org(org_uuid, user_id): + return r_serv_db.sadd(f'ail:org:{org_uuid}:users', user_id) + +class Organisation: + + def __init__(self, org_uuid): + self.uuid = org_uuid + + def exists(self): + return r_serv_db.exists(f'ail:org:{self.uuid}') + + def _get_field(self, field): + return r_serv_db.hget(f'ail:org:{self.uuid}', field) + + def _set_fields(self, field, value): + return r_serv_db.hset(f'ail:org:{self.uuid}', field, value) + + def get_uuid(self): + return self.uuid + + def get_date_created(self): + date = self._get_field('date_created') + + def get_date_modified(self): + date = self._get_field('date_modified') + + def get_description(self): + return self._get_field('description') + + def get_name(self): + return self._get_field('name') + + def get_nationality(self): + return self._get_field('nationality') + + def get_creator(self): + return self._get_field('creator') + + def get_org_type(self): + return self._get_field('type') + + def get_sector(self): + return self._get_field('sector') + + def get_tags(self): # TODO + pass + + def get_logo(self): + pass + + def get_users(self): + return r_serv_db.smembers(f'ail:org:{self.uuid}:users') + + def get_nb_users(self): + return r_serv_db.scard(f'ail:org:{self.uuid}:users') + + def get_meta(self, options=set()): + meta = {'uuid': self.uuid} + if 'name' in options: + meta['name'] = self._get_field('name') + if 'description' in options: + meta['description'] = self._get_field('description') + if 'creator' in options: + meta['creator'] = self._get_field('creator') + if 'date_created' in options: + meta['date_created'] = self._get_field('date_created') + return meta + + def add_user(self, user_id): + if exists_user(user_id) and not get_user_org(user_id): + r_serv_db.sadd(f'ail:org:{self.uuid}:users', user_id) + r_serv_db.hset(f'ail:user:metadata:{user_id}', 'org', self.uuid) + + def remove_user(self, user_id): + r_serv_db.srem(f'ail:org:{self.uuid}:users', user_id) + r_serv_db.hdel(f'ail:user:metadata:{user_id}', 'org') + + def remove_users(self): + for user_id in self.get_users(): + self.remove_user(user_id) + + def create(self, creator, name, description=None, nationality=None, sector=None, org_type=None, logo=None): + r_serv_db.sadd(f'ail:orgs', self.uuid) + + self._set_fields('creator', creator) + self._set_fields('name', name) + self._set_fields('description', description) + if nationality: + self._set_fields('nationality', nationality) + if sector: + self._set_fields('sector', sector) + if org_type: + self._set_fields('type', org_type) + #if logo: + + current = datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S') + self._set_fields('date_created', current) + self._set_fields('date_modified', current) + + def edit(self): + pass + + def delete(self): # TODO CHANGE ACL ASSOCIATED WITH ORGS -> Tracker, Investigation, objects, ... + self.remove_users() + r_serv_db.delete(f'ail:org:{self.uuid}') + r_serv_db.srem(f'ail:orgs', self.uuid) + + + +def exists_org(org_uuid): + return r_serv_db.exists(f'ail:org:{org_uuid}') + +def create_org(name, description, uuid=None, nationality=None, sector=None, org_type=None, logo=None): # contacts ????? + if uuid is None: + uuid = str(uuid4()) # TODO check if is uuidv4 + else: + if exists_org(uuid): + raise Exception('Organisation already exists') # TODO CUSTOM ERROR + + org = Organisation(uuid) + org.create( name, description, nationality=nationality, sector=sector, org_type=org_type, logo=logo) + +## --ORGANISATIONS-- ## + #### SESSIONS #### def get_sessions(): @@ -266,6 +407,9 @@ def get_user_role(user_id): def exists_user(user_id): return r_serv_db.exists(f'ail:user:metadata:{user_id}') +def get_user_org(user_id): + return r_serv_db.hget(f'ail:user:metadata:{user_id}', 'org') + def get_user_creator(user_id): return r_serv_db.hget(f'ail:user:metadata:{user_id}', 'creator') @@ -409,6 +553,9 @@ class AILUser(UserMixin): def update_last_login(self): r_serv_db.hset(f'ail:user:metadata:{self.user_id}', 'last_login', datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')) + def get_org(self): + return get_user_org(self.user_id) + def get_meta(self, options=set()): meta = {'id': self.user_id} if 'creator' in options: @@ -435,6 +582,8 @@ class AILUser(UserMixin): meta['is_disabled'] = self.is_disabled() if 'is_logged' in options: meta['is_logged'] = is_user_logged(self.user_id) + if 'org' in options: + meta['org'] = self.get_org() return meta ## SESSION ## @@ -549,6 +698,33 @@ class AILUser(UserMixin): #### API #### +def api_get_orgs_meta(): + meta = {'orgs': []} + options = {'date_created', 'description', 'name'} + for org_uuid in get_orgs(): + org = Organisation(org_uuid) + meta['orgs'].append(org.get_meta(options=options)) + return meta + +def api_create_org(creator, org_uuid, name, ip_address, description=None): + if not is_valid_uuid_v4(org_uuid): + return {'status': 'error', 'reason': 'Invalid UUID'}, 400 + if exists_org(org_uuid): + return {'status': 'error', 'reason': 'Org already exists'}, 400 + + org = Organisation(org_uuid) + org.create(creator, name, description=description) + access_logger.info(f'Created org {org_uuid}', extra={'user_id': creator, 'ip_address': ip_address}) + return org.get_uuid(), 200 + +def api_delete_org(org_uuid, admin_id, ip_address): # TODO check if nothing is linked to this org + if not exists_org(org_uuid): + return {'status': 'error', 'reason': 'Org not found'}, 404 + access_logger.warning(f'Deleted org {org_uuid}', extra={'user_id': admin_id, 'ip_address': ip_address}) + org = Organisation(org_uuid) + org.delete() + return org_uuid, 200 + def api_get_users_meta(): meta = {'users': []} options = {'api_key', 'creator', 'created_at', 'is_logged', 'last_edit', 'last_login', 'last_seen', 'last_seen_api', 'role', '2fa', 'otp_setup'} diff --git a/update/v5.0/DB_KVROCKS_MIGRATION.py b/update/v5.0/DB_KVROCKS_MIGRATION.py index 81cf8484..3d87bb5d 100755 --- a/update/v5.0/DB_KVROCKS_MIGRATION.py +++ b/update/v5.0/DB_KVROCKS_MIGRATION.py @@ -220,7 +220,7 @@ def trackers_migration(): print('TRACKERS MIGRATION...') for tracker_uuid in old_Tracker.get_all_tracker_uuid(): meta = get_tracker_metadata(tracker_uuid) - Tracker._re_create_tracker(meta['type'], meta['uuid'], meta['tracked'], meta['user_id'], meta['level'], + Tracker._re_create_tracker(meta['type'], meta['uuid'], meta['tracked'], 'TEST_ORG', meta['user_id'], meta['level'], tags=meta['tags'], mails=meta['mails'], description=meta['description'], webhook=meta['webhook'], sources=meta['sources'], first_seen=meta['first_seen'], last_seen=meta['last_seen']) diff --git a/var/www/blueprints/hunters.py b/var/www/blueprints/hunters.py index 1d051ac0..316b1107 100644 --- a/var/www/blueprints/hunters.py +++ b/var/www/blueprints/hunters.py @@ -9,7 +9,7 @@ import os import sys import json -from flask import render_template, jsonify, request, Blueprint, redirect, url_for, Response, abort +from flask import render_template, jsonify, request, Blueprint, redirect, url_for, Response from flask_login import login_required, current_user sys.path.append('modules') @@ -67,7 +67,7 @@ def get_default_yara_rule_content(): def trackers_dashboard(): user_id = current_user.get_user_id() trackers = Tracker.get_trackers_dashboard() - stats = Tracker.get_trackers_stats(user_id) + stats = Tracker.get_trackers_stats(current_user.get_org(), user_id) return render_template("trackers_dashboard.html", trackers=trackers, stats=stats, bootstrap_label=bootstrap_label) @hunters.route("/trackers/all") @@ -75,9 +75,10 @@ def trackers_dashboard(): @login_read_only def tracked_menu(): user_id = current_user.get_user_id() + org_trackers = Tracker.get_org_trackers_meta(current_user.get_org()) user_trackers = Tracker.get_user_trackers_meta(user_id) global_trackers = Tracker.get_global_trackers_meta() - return render_template("trackersManagement.html", user_trackers=user_trackers, global_trackers=global_trackers, bootstrap_label=bootstrap_label) + return render_template("trackersManagement.html", user_trackers=user_trackers, org_trackers=org_trackers, global_trackers=global_trackers, bootstrap_label=bootstrap_label) @hunters.route("/trackers/word") @login_required @@ -85,9 +86,10 @@ def tracked_menu(): def tracked_menu_word(): tracker_type = 'word' user_id = current_user.get_user_id() + org_trackers = Tracker.get_org_trackers_meta(current_user.get_org(), tracker_type='word') user_trackers = Tracker.get_user_trackers_meta(user_id, tracker_type='word') global_trackers = Tracker.get_global_trackers_meta(tracker_type='word') - return render_template("trackersManagement.html", user_trackers=user_trackers, global_trackers=global_trackers, bootstrap_label=bootstrap_label, tracker_type=tracker_type) + return render_template("trackersManagement.html", user_trackers=user_trackers, org_trackers=org_trackers, global_trackers=global_trackers, bootstrap_label=bootstrap_label, tracker_type=tracker_type) @hunters.route("/trackers/set") @login_required @@ -95,9 +97,10 @@ def tracked_menu_word(): def tracked_menu_set(): tracker_type = 'set' user_id = current_user.get_user_id() + org_trackers = Tracker.get_org_trackers_meta(current_user.get_org(), tracker_type=tracker_type) user_trackers = Tracker.get_user_trackers_meta(user_id, tracker_type=tracker_type) global_trackers = Tracker.get_global_trackers_meta(tracker_type=tracker_type) - return render_template("trackersManagement.html", user_trackers=user_trackers, global_trackers=global_trackers, bootstrap_label=bootstrap_label, tracker_type=tracker_type) + return render_template("trackersManagement.html", user_trackers=user_trackers, org_trackers=org_trackers, global_trackers=global_trackers, bootstrap_label=bootstrap_label, tracker_type=tracker_type) @hunters.route("/trackers/regex") @login_required @@ -105,9 +108,10 @@ def tracked_menu_set(): def tracked_menu_regex(): tracker_type = 'regex' user_id = current_user.get_user_id() + org_trackers = Tracker.get_org_trackers_meta(current_user.get_org(), tracker_type=tracker_type) user_trackers = Tracker.get_user_trackers_meta(user_id, tracker_type=tracker_type) global_trackers = Tracker.get_global_trackers_meta(tracker_type=tracker_type) - return render_template("trackersManagement.html", user_trackers=user_trackers, global_trackers=global_trackers, bootstrap_label=bootstrap_label, tracker_type=tracker_type) + return render_template("trackersManagement.html", user_trackers=user_trackers, org_trackers=org_trackers, global_trackers=global_trackers, bootstrap_label=bootstrap_label, tracker_type=tracker_type) @hunters.route("/trackers/yara") @login_required @@ -115,9 +119,10 @@ def tracked_menu_regex(): def tracked_menu_yara(): tracker_type = 'yara' user_id = current_user.get_user_id() + org_trackers = Tracker.get_org_trackers_meta(current_user.get_org(), tracker_type=tracker_type) user_trackers = Tracker.get_user_trackers_meta(user_id, tracker_type=tracker_type) global_trackers = Tracker.get_global_trackers_meta(tracker_type=tracker_type) - return render_template("trackersManagement.html", user_trackers=user_trackers, global_trackers=global_trackers, bootstrap_label=bootstrap_label, tracker_type=tracker_type) + return render_template("trackersManagement.html", user_trackers=user_trackers, org_trackers=org_trackers, global_trackers=global_trackers, bootstrap_label=bootstrap_label, tracker_type=tracker_type) @hunters.route("/trackers/typosquatting") @login_required @@ -125,17 +130,19 @@ def tracked_menu_yara(): def tracked_menu_typosquatting(): tracker_type = 'typosquatting' user_id = current_user.get_user_id() + org_trackers = Tracker.get_org_trackers_meta(current_user.get_org(), tracker_type=tracker_type) user_trackers = Tracker.get_user_trackers_meta(user_id, tracker_type=tracker_type) global_trackers = Tracker.get_global_trackers_meta(tracker_type=tracker_type) - return render_template("trackersManagement.html", user_trackers=user_trackers, global_trackers=global_trackers, + return render_template("trackersManagement.html", user_trackers=user_trackers, org_trackers=org_trackers, global_trackers=global_trackers, bootstrap_label=bootstrap_label, tracker_type=tracker_type) @hunters.route("/trackers/admin") @login_required @login_admin def tracked_menu_admin(): + org_trackers = Tracker.get_orgs_trackers_meta() user_trackers = Tracker.get_users_trackers_meta() - return render_template("trackersManagement.html", user_trackers=user_trackers, global_trackers=[], + return render_template("trackersManagement.html", user_trackers=user_trackers, org_trackers=org_trackers, global_trackers=[], bootstrap_label=bootstrap_label) @@ -145,8 +152,8 @@ def tracked_menu_admin(): def show_tracker(): user_id = current_user.get_user_id() tracker_uuid = request.args.get('uuid', None) - res = Tracker.api_is_allowed_to_access_tracker(tracker_uuid, user_id) - if res[1] != 200: # invalid access + res = Tracker.api_check_tracker_acl(tracker_uuid, current_user.get_org(), user_id) + if res: # invalid access return Response(json.dumps(res[0], indent=2, sort_keys=True), mimetype='application/json'), res[1] date_from = request.args.get('date_from') @@ -241,10 +248,7 @@ def parse_add_edit_request(request_form): to_track = yara_default_rule tracker_type = 'yara_default' - if level == 'on': - level = 1 - else: - level = 0 + level = int(level) if mails: mails = mails.split() else: @@ -293,7 +297,8 @@ def add_tracked_menu(): if request.method == 'POST': input_dict = parse_add_edit_request(request.form) user_id = current_user.get_user_id() - res = Tracker.api_add_tracker(input_dict, user_id) + org = current_user.get_org() + res = Tracker.api_add_tracker(input_dict, org, user_id) if res[1] == 200: return redirect(url_for('hunters.trackers_dashboard')) else: @@ -309,19 +314,19 @@ def add_tracked_menu(): @login_required @login_analyst def tracker_edit(): + user_id = current_user.get_user_id() + user_org = current_user.get_org() if request.method == 'POST': input_dict = parse_add_edit_request(request.form) - user_id = current_user.get_user_id() - res = Tracker.api_edit_tracker(input_dict, user_id) + res = Tracker.api_edit_tracker(input_dict, user_org, user_id) if res[1] == 200: return redirect(url_for('hunters.show_tracker', uuid=res[0].get('uuid'))) else: return create_json_response(res[0], res[1]) else: - user_id = current_user.get_user_id() tracker_uuid = request.args.get('uuid', None) - res = Tracker.api_is_allowed_to_edit_tracker(tracker_uuid, user_id) - if res[1] != 200: # invalid access + res = Tracker.api_is_allowed_to_edit_tracker(tracker_uuid, user_org, user_id) + if res: # invalid access return Response(json.dumps(res[0], indent=2, sort_keys=True), mimetype='application/json'), res[1] tracker = Tracker.Tracker(tracker_uuid) @@ -352,7 +357,7 @@ def tracker_edit(): def tracker_delete(): user_id = current_user.get_user_id() tracker_uuid = request.args.get('uuid') - res = Tracker.api_delete_tracker({'uuid': tracker_uuid}, user_id) + res = Tracker.api_delete_tracker({'uuid': tracker_uuid}, current_user.get_org(), user_id) if res[1] != 200: return create_json_response(res[0], res[1]) else: @@ -365,7 +370,7 @@ def tracker_delete(): def get_json_tracker_graph(): user_id = current_user.get_user_id() tracker_uuid = request.args.get('uuid') - res = Tracker.api_check_tracker_acl(tracker_uuid, user_id) + res = Tracker.api_check_tracker_acl(tracker_uuid, current_user.get_org(), user_id) if res: return create_json_response(res[0], res[1]) @@ -394,7 +399,7 @@ def tracker_object_add(): date = obj.get_date() else: date = request.args.get('date') # TODO check daterange - res = Tracker.api_tracker_add_object({'uuid': tracker_uuid, 'gid': object_global_id, 'date': date}, user_id) + res = Tracker.api_tracker_add_object({'uuid': tracker_uuid, 'gid': object_global_id, 'date': date}, current_user.get_org(), user_id) if res[1] != 200: return create_json_response(res[0], res[1]) else: @@ -410,7 +415,7 @@ def tracker_object_remove(): user_id = current_user.get_user_id() tracker_uuid = request.args.get('uuid') object_global_id = request.args.get('gid') - res = Tracker.api_tracker_remove_object({'uuid': tracker_uuid, 'gid': object_global_id}, user_id) + res = Tracker.api_tracker_remove_object({'uuid': tracker_uuid, 'gid': object_global_id}, current_user.get_org(), user_id) if res[1] != 200: return create_json_response(res[0], res[1]) else: @@ -426,8 +431,8 @@ def tracker_object_remove(): def tracker_objects(): user_id = current_user.get_user_id() tracker_uuid = request.args.get('uuid', None) - res = Tracker.api_is_allowed_to_edit_tracker(tracker_uuid, user_id) - if res[1] != 200: # invalid access + res = Tracker.api_is_allowed_to_edit_tracker(tracker_uuid, current_user.get_org(), user_id) + if res: # invalid access return Response(json.dumps(res[0], indent=2, sort_keys=True), mimetype='application/json'), res[1] tracker = Tracker.Tracker(tracker_uuid) diff --git a/var/www/blueprints/settings_b.py b/var/www/blueprints/settings_b.py index 1d238738..5e56d77f 100644 --- a/var/www/blueprints/settings_b.py +++ b/var/www/blueprints/settings_b.py @@ -303,6 +303,56 @@ def users_list(): ############################################# +@settings_b.route("/settings/organisations", methods=['GET']) +@login_required +@login_admin +def organisations_list(): + meta = ail_users.api_get_orgs_meta() + return render_template("orgs_list.html", meta=meta, acl_admin=True) + +@settings_b.route("/settings/create_organisation", methods=['GET']) +@login_required +@login_admin +def create_organisation(): + meta = {} + return render_template("create_org.html", meta=meta, error_mail=False, acl_admin=True) + +@settings_b.route("/settings/create_org_post", methods=['POST']) +@login_required +@login_admin +def create_org_post(): + # Admin ID + admin_id = current_user.get_user_id() + + org_uuid = request.form.get('uuid') + name = request.form.get('name') + description = request.form.get('description') + + r = ail_users.api_create_org(admin_id, org_uuid, name, request.remote_addr, description=description) + if r[1] != 200: + return create_json_response(r[0], r[1]) + else: + return redirect(url_for('settings_b.organisations_list')) + + + # TODO check if uuid4 + # TODO check name format + length + +@settings_b.route("/settings/delete_org", methods=['GET']) +@login_required +@login_admin +def delete_org(): + admin_id = current_user.get_user_id() + org_uuid = request.args.get('uuid') + r = ail_users.api_delete_org(org_uuid, admin_id, request.remote_addr) + if r[1] != 200: + return create_json_response(r[0], r[1]) + else: + return redirect(url_for('settings_b.organisations_list')) + + +############################################# + @settings_b.route("/settings/passivedns", methods=['GET']) @login_required @login_read_only diff --git a/var/www/templates/hunter/tracker_add.html b/var/www/templates/hunter/tracker_add.html index fe9ea43d..6e0d8d58 100644 --- a/var/www/templates/hunter/tracker_add.html +++ b/var/www/templates/hunter/tracker_add.html @@ -211,12 +211,20 @@
-
- - -
+ + + +
diff --git a/var/www/templates/hunter/tracker_show.html b/var/www/templates/hunter/tracker_show.html index df51a809..b6b9ae7b 100644 --- a/var/www/templates/hunter/tracker_show.html +++ b/var/www/templates/hunter/tracker_show.html @@ -119,9 +119,11 @@ Level {% if meta['level'] == 0 %} - Private - {% else %} + My User + {% elif meta['level'] == 1 %} Global + {% elif meta['level'] == 2 %} + My Organisation {% endif %} diff --git a/var/www/templates/hunter/trackersManagement.html b/var/www/templates/hunter/trackersManagement.html index 89407245..8182d11d 100644 --- a/var/www/templates/hunter/trackersManagement.html +++ b/var/www/templates/hunter/trackersManagement.html @@ -115,6 +115,78 @@ + {% endif %} + + + {% if org_trackers %} + +
+
+
Organisation {{ tracker_type }} Trackers
+
+
+ + + + + + + + + + + + + {% for dict_uuid in org_trackers %} + + + + + + + + + {% endfor %} + +
TypeTrackerFirst seenLast seenEmailssparkline
{{ dict_uuid['type'] }} + + + {% if dict_uuid['tracked'] %} + {% if dict_uuid['tracked']|length > 256 %} + {{ dict_uuid['tracked'][0:256] }}... + {% else %} + {{ dict_uuid['tracked'] }} + {% endif %} + {% endif %} + + + {% if dict_uuid['description'] %} +
{{ dict_uuid['description'] }}
+ {% endif %} + +
+ {% for tag in dict_uuid['tags'] %} + + {{ tag }} + + {% endfor %} +
+
+ {% if dict_uuid['first_seen'] %} + {{ dict_uuid['first_seen'][0:4] }}/{{ dict_uuid['first_seen'][4:6] }}/{{ dict_uuid['first_seen'][6:8] }} + {% endif %} + + {% if dict_uuid['last_seen'] %} + {{ dict_uuid['last_seen'][0:4] }}/{{ dict_uuid['last_seen'][4:6] }}/{{ dict_uuid['last_seen'][6:8] }} + {% endif %} + + {% for mail in dict_uuid['mails'] %} + {{ mail }}
+ {% endfor %} +
+
+
+ {% endif %}
@@ -203,6 +275,9 @@ {% for dict_uuid in user_trackers %} sparkline("sparklines_{{ dict_uuid['uuid'] }}", {{ dict_uuid['sparkline'] }}, {height: 40}); {% endfor %} + {% for dict_uuid in org_trackers %} + sparkline("sparklines_{{ dict_uuid['uuid'] }}", {{ dict_uuid['sparkline'] }}, {height: 40}); + {% endfor %} {% for dict_uuid in global_trackers %} sparkline("sparklines_{{ dict_uuid['uuid'] }}", {{ dict_uuid['sparkline'] }}, {height: 40}); {% endfor %} @@ -212,6 +287,11 @@ "iDisplayLength": 10, "order": [[0, "desc"]] }); + $('#table_org_trackers').DataTable({ + "aLengthMenu": [[5, 10, 15, -1], [5, 10, 15, "All"]], + "iDisplayLength": 10, + "order": [[0, "desc"]] + }); $('#table_global_trackers').DataTable({ "aLengthMenu": [[5, 10, 15, -1], [5, 10, 15, "All"]], "iDisplayLength": 10, diff --git a/var/www/templates/settings/create_org.html b/var/www/templates/settings/create_org.html new file mode 100644 index 00000000..245fe42c --- /dev/null +++ b/var/www/templates/settings/create_org.html @@ -0,0 +1,79 @@ + + + + + Create Org - AIL + + + + + + + + + + + + + + + + + +{% include 'nav_bar.html' %} +
+
+ {% include 'settings/menu_sidebar.html' %} +
+ + + +
+
+
+ + + + + diff --git a/var/www/templates/settings/menu_sidebar.html b/var/www/templates/settings/menu_sidebar.html index c342ba14..004a1436 100644 --- a/var/www/templates/settings/menu_sidebar.html +++ b/var/www/templates/settings/menu_sidebar.html @@ -101,6 +101,23 @@ + + {% endif %}