class Groups(PaginatedAPIMixin, db.Model): """Group Database Table Module.""" __tablename__ = 'groups' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(128), index=True, unique=True) timestamp = db.Column(db.DateTime, index=True, default=udatetime.utcnow) def __repr__(self): """Return string representation of the Groups Database Object Table.""" return '<Groups {}>'.format(self.name) def to_dict(self): """Return dictionary object type for Group table database API calls.""" data = { 'id': self.id, 'name': self.name, 'last_seen': self.timestamp.isoformat() + 'Z' } return data def from_dict(self, data): """Process from dictionary object type for API Posts.""" for field in ['name']: if field in data: setattr(self, field, data[field])
class FileUpload(db.Model): """File upload model default database format for analysis_plugin.""" __searchable__ = ['id', 'md5_hash', 'uploaded_by', 'file_type', 'time_stamp'] __tablename__ = 'uploaded_file_table' id = db.Column(db.Integer, primary_key=True) md5_hash = db.Column(db.String(32), unique=True) uploaded_by = db.Column(db.Integer, db.ForeignKey('user.id')) file_type = db.Column(db.String(512), index=True) time_stamp = db.Column(db.DateTime, index=True, default=udatetime.utcnow) def __repr__(self): """Official Analysis Plugins Table database name object representation.""" return '<FileUpload {}>'.format(self.md5_hash) def to_dict(self): """Return dictionary object type for API File Upload call.""" data = { 'id': self.id, 'md5_hash': self.md5_hash, 'file_type': self.file_type, 'last_seen': self.time_stamp.isoformat() + 'Z', } return data def from_dict(self, data): """Process from dictionary object type for API Posts.""" for field in ['file']: if field in data: setattr(self, field, data[field])
class Task(db.Model): """AUCR's database table for redis mq service.""" __tablename__ = 'task_mq' id = db.Column(db.String(36), primary_key=True) name = db.Column(db.String(128), index=True) description = db.Column(db.String(128)) user_id = db.Column(db.Integer, db.ForeignKey('user.id')) complete = db.Column(db.Boolean, default=False)
class Log(db.Model): """Log tracking for report_plugin.""" id = db.Column(db.Integer, primary_key=True) log_name = db.Column(db.String(128), index=True) time_stamp = db.Column(db.DateTime, index=True, default=udatetime.utcnow) def __repr__(self): """Log table change tracking.""" return '<Log {}>'.format(self.report_name)
class Severity(db.Model): """Severity default database table format for tasks_plugin.""" __searchable__ = ['severity'] __tablename__ = 'task_severity' id = db.Column(db.Integer, primary_key=True) severity = db.Column(db.Integer, index=True) def __repr__(self): """Official TLP Table database name object representation.""" return '<Severity {}>'.format(self.severity)
class Detection(db.Model): """Detection method data default table for aucr.""" __tablename__ = 'detection' id = db.Column(db.Integer, primary_key=True) detection_method = db.Column(db.String(32), index=True) description = db.Column(db.String(256), index=True) time_stamp = db.Column(db.DateTime, index=True, default=datetime.utcnow) def __repr__(self): return '<Detection {}>'.format(self.detection_method)
class Comments(db.Model): """Comment default database table format for tasks_plugin.""" __tablename__ = 'task_comments' id = db.Column(db.Integer, primary_key=True) comment = db.Column(db.String(512), index=True) time_stamp = db.Column(db.DateTime, index=True, default=udatetime.utcnow) def __repr__(self): """Official Comments Table database name object representation.""" return '<Comments {}>'.format(self.comment)
class Rooms(db.Model): """Chat Database Table.""" __tablename__ = "chat_rooms" id = db.Column(db.Integer, primary_key=True) room_name = db.Column(db.String(64), unique=True) author_id = db.Column(db.Integer, db.ForeignKey('user.id')) timestamp = db.Column(db.DateTime, index=True, default=udatetime.utcnow) def __repr__(self): """AUCR chat plugin return messages.""" return '<ChatRooms {}>'.format(self.room_name)
class TasksPlugins(db.Model): """The TasksPlugins models Class defines the default database format for tasks_plugin.""" __tablename__ = 'task_plugins' id = db.Column(db.Integer, primary_key=True) task_name = db.Column(db.String(128), index=True) description = db.Column(db.String(256), index=True) time_stamp = db.Column(db.DateTime, index=True, default=udatetime.utcnow) def __repr__(self): """Official Tasks Plugins Table database name object representation.""" return '<TasksPlugins {}>'.format(self.task_name)
class Errors(db.Model): """HTTP Error Code Database Table.""" __tablename__ = "errors" id = db.Column(db.Integer, primary_key=True) error_name = db.Column(db.Integer, index=True) error_message = db.Column(db.String(140)) timestamp = db.Column(db.DateTime, index=True, default=udatetime.utcnow) def __repr__(self): """AUCR HTTP Error return self.""" return '<Errors {}>'.format(self.error_name)
class Label(db.Model): """Label models class defines the default database format for tasks_plugin.""" __tablename__ = 'label' id = db.Column(db.Integer, primary_key=True) label_name = db.Column(db.String(128), index=True) description = db.Column(db.String(256), index=True) time_stamp = db.Column(db.DateTime, index=True, default=udatetime.utcnow) def __repr__(self): """Official Label Table database name object representation.""" return '<Label {}>'.format(self.label_name)
class BusinessCoverage(db.Model): """BusinessCoverage models class defines business coverage database table format for tasks_plugin.""" __tablename__ = 'business_coverage' id = db.Column(db.Integer, primary_key=True) business_coverage = db.Column(db.String(128), index=True) description = db.Column(db.String(256), index=True) time_stamp = db.Column(db.DateTime, index=True, default=udatetime.utcnow) def __repr__(self): """Official Business Coverage Table database name object representation.""" return '<BusinessCoverage {}>'.format(self.business_coverage)
class Notification(db.Model): """AUCR auth plugin Database table for User Notification.""" __tablename__ = 'notification' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(128), index=True) user_id = db.Column(db.Integer, db.ForeignKey('user.id')) timestamp = db.Column(db.Float, index=True, default=time) payload_json = db.Column(db.Text) def get_data(self): """Return string representation of the Notification Database Object Table.""" return json.loads(str(self.payload_json))
class TaskStates(db.Model): """Tasks States models class defines default database format for tasks_plugin.""" __searchable__ = ['task_category', 'description', 'task_state_name'] __tablename__ = 'task_states' id = db.Column(db.Integer, primary_key=True) task_state_name = db.Column(db.String(128), index=True) description = db.Column(db.String(256), index=True) time_stamp = db.Column(db.DateTime, index=True, default=udatetime.utcnow) def __repr__(self): """Official Task States database name object representation.""" return '<TaskStates {}>'.format(self.task_state_name)
class Message(SearchableMixin, db.Model): """Database table for User messages.""" __searchable__ = ['id', 'body', 'sender_id', 'recipient_id', 'timestamp'] __tablename__ = 'message' id = db.Column(db.Integer, primary_key=True) body = db.Column(db.String(4912000)) sender_id = db.Column(db.Integer, db.ForeignKey('user.id')) recipient_id = db.Column(db.Integer, db.ForeignKey('user.id')) timestamp = db.Column(db.DateTime, index=True, default=udatetime.utcnow) def __repr__(self): """Return string representation of the Message Database Object Table.""" return '<Message {}>'.format(self.id)
class Chat(db.Model): """Chat Database Table.""" __searchable__ = ['id', 'author', 'message', 'room', 'timestamp'] __tablename__ = "chat" id = db.Column(db.Integer, primary_key=True) author = db.Column(db.String(64), db.ForeignKey('user.username')) message = db.Column(db.String(512), index=True) room_name = db.Column(db.String(64), db.ForeignKey('chat_rooms.room_name')) timestamp = db.Column(db.DateTime, index=True, default=udatetime.utcnow) def __repr__(self): """AUCR chat plugin return messages.""" return '<Chat {}>'.format(self.message)
class TrafficLightProtocol(db.Model): """TLP default database table format for tasks_plugin.""" __searchable__ = [ 'color_name', 'when_description', 'how_description', 'quick_description' ] __tablename__ = 'task_tlp' id = db.Column(db.Integer, primary_key=True) color_name = db.Column(db.String(5), index=True) when_description = db.Column(db.String(256), index=True) how_description = db.Column(db.String(512), index=True) quick_description = db.Column(db.String(128), index=True) def __repr__(self): """Official TLP Table database name object representation.""" return '<TrafficLightProtocol {}>'.format(self.color_name)
class YaraRuleResults(db.Model): """Yara Result database table.""" __tablename__ = 'yara_rule_results' id = db.Column(db.Integer, primary_key=True) yara_list_id = db.Column(db.Integer, db.ForeignKey('yara_rules.id')) matches = db.Column(db.String(3072)) file_string_matches = db.Column(db.String(4912000)) file_matches = db.Column(db.Integer, db.ForeignKey('uploaded_file_table.id')) file_classification = db.Column(db.String(3072)) run_time = db.Column(db.DateTime) def __repr__(self): return '<Yara Results {}>'.format(self.yara_name) def to_dict(self): """Return dictionary object type for API calls.""" data = { 'id': self.id, 'yara_list_id': self.yara_list_id, 'matches': self.matches, 'run_time': self.run_time.isoformat() + 'Z', 'file_matches': self.file_matches, 'file_string_matches': self.file_string_matches, 'file_classification': self.file_classification } return data
class IDSRuleResults(db.Model): """IDS Result database table.""" __tablename__ = 'ids_rule_results' id = db.Column(db.Integer, primary_key=True) ids_plugin_list_id = db.Column(db.Integer, db.ForeignKey('ids_rules.id')) matches = db.Column(db.String(3072)) pcap_matches = db.Column(db.Integer, db.ForeignKey('uploaded_file_table.id')) pcap_classification = db.Column(db.String(3072)) run_time = db.Column(db.DateTime) def __repr__(self): return '<IDS Rule Results {}>'.format(self.ids_plugin_list_id) def to_dict(self): """Return dictionary object type for API calls.""" data = { 'id': self.id, 'ids_plugin_list_id': self.ids_plugin_list_id, 'matches': self.matches, 'run_time': self.run_time.isoformat() + 'Z', 'file_matches': self.pcap_matches, 'file_classification': self.pcap_classification, } return data
class Task(db.Model): """AUCR's database table for redis mq service.""" __tablename__ = 'task_mq' id = db.Column(db.String(36), primary_key=True) name = db.Column(db.String(128), index=True) description = db.Column(db.String(128)) user_id = db.Column(db.Integer, db.ForeignKey('user.id')) complete = db.Column(db.Boolean, default=False) def get_rq_job(self): """Return redis mq job.""" try: rq_job = rq.job.Job.fetch(self.id, connection=current_app.redis) except (redis.exceptions.RedisError, rq.exceptions.NoSuchJobError): return None return rq_job def get_progress(self): """Return message progress from redis mq.""" job = self.get_rq_job() return job.meta.get('progress', 0) if job is not None else 100
class Group(PaginatedAPIMixin, db.Model): """AUCR Group Table Database Module.""" __tablename__ = 'group' id = db.Column(db.Integer, primary_key=True) groups_id = db.Column(db.Integer, db.ForeignKey('groups.id'), index=True) username_id = db.Column(db.Integer, db.ForeignKey('user.id')) timestamp = db.Column(db.DateTime, index=True, default=udatetime.utcnow) def __repr__(self): """Return string representation of Group Database Object Table.""" return '<Group {}>'.format(self.group_id) def to_dict(self): """Return dictionary object type for Group database Table API calls.""" group_object = Groups.query.filter_by(id=self.id).first() data = { 'id': self.id, 'groups_id': group_object.id, 'username_id': self.username_id, 'time_stamp': self.timestamp.isoformat() + 'Z', } return data
class UNUM(SearchableMixin, PaginatedAPIMixin, db.Model): """Upload File data default table for aucr.""" __searchable__ = [ 'id', 'description', 'classification', 'created_by', 'md5_hash', 'file_name', 'created_time_stamp' ] __tablename__ = 'unum' id = db.Column(db.Integer, primary_key=True) description = db.Column(db.String(256), index=True) created_time_stamp = db.Column(db.DateTime, index=True, default=datetime.utcnow) modify_time_stamp = db.Column(db.DateTime, index=True, default=datetime.utcnow) classification = db.Column(db.Integer, db.ForeignKey('classification.id')) file_name = db.Column(db.String(512)) created_by = db.Column(db.Integer, db.ForeignKey('user.id')) group_access = db.Column(db.Integer, db.ForeignKey('groups.id')) md5_hash = db.Column(db.String(128), db.ForeignKey('uploaded_file_table.md5_hash')) def __repr__(self): return '<unum {}>'.format(self.md5_hash) def to_dict(self): """Return dictionary object type for API calls.""" data = { 'id': self.id, 'md5_hash': self.md5_hash, 'file_name': self.file_name, 'description': self.description, 'classification': self.classification, 'last_seen': self.created_time_stamp.isoformat() + 'Z', 'modify_time_stamp': self.modify_time_stamp.isoformat() + 'Z', 'created_by': self.created_by, 'group_access': self.group_access } return data
class YaraRules(SearchableMixin, PaginatedAPIMixin, db.Model): """Yara data default table for aucr.""" __searchable__ = [ 'id', 'yara_list_name', 'modify_time_stamp', 'created_by', 'yara_rules' ] __tablename__ = 'yara_rules' id = db.Column(db.Integer, primary_key=True) yara_list_name = db.Column(db.String(32), index=True, unique=True) created_time_stamp = db.Column(db.DateTime, index=True, default=datetime.utcnow) modify_time_stamp = db.Column(db.DateTime, index=True, default=datetime.utcnow) created_by = db.Column(db.Integer, db.ForeignKey('user.id')) group_access = db.Column(db.Integer, db.ForeignKey('groups.id')) last_updated_by = db.Column(db.Integer, db.ForeignKey('user.id')) yara_rules = db.Column(db.String(4912000)) def __repr__(self): return '<Yara {}>'.format(self.yara_list_name) def to_dict(self): """Return dictionary object type for API calls.""" data = { 'id': self.id, 'yara_list_name': self.yara_list_name, 'last_seen': self.created_time_stamp.isoformat() + 'Z', 'modify_time_stamp': self.modify_time_stamp.isoformat() + 'Z', 'created_by': self.created_by, 'group_access': self.group_access, 'yara_rules': self.yara_rules, 'last_updated_by': self.last_updated_by } return data def from_dict(self, data): """Process from dictionary object type for API Yara Rule Post.""" for field in ['yara_list_name', 'group_access', 'created_by']: if field in data: setattr(self, field, data[field])
class User(UserMixin, PaginatedAPIMixin, db.Model): """AUCR User models class defines information in the user table.""" __tablename__ = 'user' id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(64), index=True, unique=True) email = db.Column(db.String(120), index=True, unique=True) alt_email = db.Column(db.String(240), unique=True) password_hash = db.Column(db.String(128)) about_me = db.Column(db.String(140)) last_seen = db.Column(db.DateTime, default=udatetime.utcnow) token = db.Column(db.String(120), index=True, unique=True) token_expiration = db.Column(db.DateTime) website = db.Column(db.String(140)) affiliation = db.Column(db.String(32)) country = db.Column(db.String(32)) last_used_ip = db.Column(db.String(16)) api_enabled = db.Column(db.String(5)) account_enabled = db.Column(db.String(5)) groups = db.relationship('Group', foreign_keys='Group.username_id', backref='author', lazy='dynamic') messages_sent = db.relationship('Message', foreign_keys='Message.sender_id', backref='author', lazy='dynamic') messages_received = db.relationship('Message', foreign_keys='Message.recipient_id', backref='recipient', lazy='dynamic') last_message_read_time = db.Column(db.DateTime) notifications = db.relationship('Notification', backref='user', lazy='dynamic') tasks = db.relationship('Task', backref='user', lazy='dynamic') otp_secret = db.Column(db.String(120)) def __repr__(self): """Return string representation of the User Database Object Table.""" return '<User {}>'.format(self.username) def __init__(self, **kwargs): """Create the User init of the User Database table object.""" super(User, self).__init__(**kwargs) def set_otp_secret(self): """Set two factor token for user.""" if self.otp_secret is None: # generate a random secret self.otp_secret = pyotp.random_base32() def set_password(self, password): """Set the user password.""" self.password_hash = generate_password_hash(password).decode("utf-8") def enable_api(self): """Enable API""" if self.api_enabled is None: self.api_enabled = True def check_password(self, password): """Verify bcrypt stored hash against password parameter.""" result = check_password_hash(self.password_hash, password) return result def avatar(self, size): """Return user avatar from gravatar.com.""" digest = md5(self.email.lower().encode('utf-8')).hexdigest() return 'https://www.gravatar.com/avatar/{}?d=identicon&s={}'.format( digest, size) def get_reset_password_token(self, expires_in=600): """Return user reset password token.""" return jwt.encode( { 'reset_password': self.id, 'exp': time() + expires_in }, current_app.config['SECRET_KEY'], algorithm='HS256').decode('utf-8') @staticmethod def verify_reset_password_token(token): """Check reset password token and return outcome.""" try: user_id = jwt.decode(token, current_app.config['SECRET_KEY'], algorithms=['HS256'])['reset_password'] except AttributeError: return return User.query.get(user_id) def new_messages(self): """Check and return new messages for current user.""" last_read_time = self.last_message_read_time or udatetime.from_string( "1900-01-01T00:00:00.000000") return Message.query.filter_by(recipient=self).filter( Message.timestamp > last_read_time).count() def add_notification(self, name, data): """Create notification message for a user.""" self.notifications.filter_by(name=name).delete() n = Notification(name=name, payload_json=json.dumps(data), user=self) db.session.add(n) return n def get_tasks_in_progress(self): """Return tasks progress from AUCR redis mq service.""" return Task.query.filter_by(user=self, complete=False).all() def to_dict(self, include_email=False): """Return dictionary object type for API calls.""" last_seen = None if self.last_seen: last_seen = self.last_seen.isoformat() + 'Z' data = { 'id': self.id, 'username': self.username, 'last_seen': last_seen, 'about_me': self.about_me, '_links': { 'avatar': self.avatar(128) } } if include_email: data['email'] = self.email return data def from_dict(self, data, new_user=False): """Process from dictionary object type for API Posts.""" for field in ['username', 'email', 'about_me']: if field in data: setattr(self, field, data[field]) if new_user and 'password' in data: self.set_password(data['password']) def get_token(self, expires_in=360000): """Generate and return a token for user auth.""" now = udatetime.utcnow().replace(tzinfo=None) if self.token and self.token_expiration > now - timedelta(seconds=60): return self.token self.token = base64.b64encode(os.urandom(64)).decode('utf-8') self.token_expiration = now + timedelta(seconds=expires_in) db.session.add(self) return self.token def revoke_token(self): """Check and expire user token if expiration time is True.""" self.token_expiration = udatetime.utcnow().replace( tzinfo=None) - timedelta(seconds=1) @staticmethod def check_token(token): """Check a token against user token.""" now = udatetime.utcnow().replace(tzinfo=None) user = User.query.filter_by(token=token).first() if user is None or user.token_expiration < now: return None return user def get_totp_uri(self): """Return two factor token uri path.""" return 'otpauth://totp/AUCR:{0}?secret={1}&issuer=AUCR' \ .format(self.username, self.otp_secret) def verify_totp(self, token): """Check and return if user two factor token for AUCR auth plugin matches.""" totp = pyotp.TOTP(self.otp_secret) result_totp = totp.verify(token) return result_totp def set_last_used_ip(self, ip_address): """Set the user password.""" self.last_used_ip = str(ip_address)
class Cases(SearchableMixin, db.Model): """Case data default table for aucr.""" __searchable__ = [ 'id', 'description', 'modify_time_stamp', 'detection_method', 'subject', 'case_notes', 'case_rules', 'created_by', 'assigned_to', 'group_access', 'attached_files', 'case_status' ] __tablename__ = 'cases' id = db.Column(db.Integer, primary_key=True) description = db.Column(db.String(256), index=True) created_time_stamp = db.Column(db.DateTime, index=True, default=datetime.utcnow) modify_time_stamp = db.Column(db.DateTime, index=True, default=datetime.utcnow) detection_method = db.Column(db.String(32), index=True) subject = db.Column(db.String(256)) case_notes = db.Column(db.String(3072)) case_rules = db.Column(db.String(3072)) created_by = db.Column(db.Integer, db.ForeignKey('user.id')) assigned_to = db.Column(db.Integer, db.ForeignKey('user.id')) group_access = db.Column(db.Integer, db.ForeignKey('groups.id')) md5_hash = db.Column(db.String(32), db.ForeignKey('uploaded_file_table.md5_hash')) case_status = db.Column(db.Integer, db.ForeignKey('task_states.id')) def __repr__(self): return '<Cases {}>'.format(self.id) def to_dict(self): """Return dictionary object type for API calls.""" data = { 'id': self.id, 'description': self.description, 'created_time_stamp': self.created_time_stamp.isoformat() + 'Z', 'modify_time_stamp': self.modify_time_stamp.isoformat() + 'Z', 'detection_method': self.detection_method, 'subject': self.subject, 'case_notes': self.case_notes, 'case_rules': self.case_rules, 'created_by': self.created_by, 'assigned_to': self.assigned_to, 'group_access': self.group_access, 'md5_hash': self.md5_hash, 'case_status': self.case_status } return data