Skip to content

Commit edcdbde

Browse files
author
IdezHD
authored
Graphql Schema Introduction (canada-ca#155)
* Created new domain management type. Started initial work on new domains type * Fix tests to reflect changes to domains * Continued work on testing json stuff * Created New README.md to give a examples on how to write schema objects * Update README.md Fixing formatting * Update README.md * Update README.md * Created new schema directory structure. Skipped all resolvers tests, and commented them out from the schema. Waiting on db decision * DMARC object type completed * SPF, and the inital EmailScan objects are in working order * SPF, and DMARC definitions completed * Removed Bool values from domains table * Update README.md Added in .all() in missing cases * Stated work on domain object type. Added fix to limit only related dmarc and spf scans results be returned * Initial work on dkim object type has been completed * Started work on www_scan and associated files, moved shared functions into seperate files in the functions folder * Combined elements straight into object other than tags, due to their logic * Started work on domain resolver * Fix db migration after rebase * Completed initial domain resolvers and corresponding tests, corrected dkim tag generation * Fixed org id issue in the domain resolver * Refactor test_domains_resolver.py to test_domains_resolver_access_control.py * Started work on resolver README.md * Fixed auth issue for user not having any roles in db * Started work on graphql logger filter * created ssl_tags file * Added descriptions to domain(s) resolver * Formatted excludes to be one field one row * Completed first iteration of the resolver README.md * Uncomment check
1 parent 01955fa commit edcdbde

49 files changed

Lines changed: 2187 additions & 1924 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

api/Pipfile.lock

Lines changed: 20 additions & 18 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/app/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from flask import Flask
22

3+
from app.logger import logger
4+
35
from db import (
46
db,
57
DB_NAME,

api/app/logger.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import logging
2+
import logging.config
3+
from graphql import GraphQLError
4+
5+
6+
class GraphQLErrorLogFilter(logging.Filter):
7+
def filter(self, record):
8+
exc_type, exc, _ = record.exc_info
9+
graphql_error = isinstance(exc, GraphQLError)
10+
if graphql_error:
11+
return False
12+
return True
13+
14+
15+
class GraphQLLocatedLogFilter(logging.Filter):
16+
def filter(self, record):
17+
if 'graphql.error.located_error.GraphQLLocatedError:' in record.msg:
18+
return False
19+
return True
20+
21+
22+
class GraphQLTracebackLogFilter(logging.Filter):
23+
def filter(self, record):
24+
if 'graphql.execution.utils:Traceback (most recent call last):' in record.msg:
25+
return False
26+
return True
27+
28+
29+
logger_dict = {
30+
'version': 1,
31+
'disable_existing_loggers': False,
32+
'handlers': {
33+
'console': {
34+
'level': 'DEBUG',
35+
'class': 'logging.StreamHandler',
36+
},
37+
},
38+
# Prevent graphql exception from displaying in console
39+
'filters': {
40+
'graphql_error_log_filter': {
41+
'()': GraphQLErrorLogFilter,
42+
},
43+
'graphql_located_error_filter': {
44+
'()': GraphQLLocatedLogFilter
45+
},
46+
'graphql_traceback_error_filter': {
47+
'()': GraphQLTracebackLogFilter
48+
}
49+
},
50+
'loggers': {
51+
'graphql.execution.executor': {
52+
'level': 'WARNING',
53+
'handlers': ['console'],
54+
'filters': [
55+
'graphql_error_log_filter',
56+
'graphql_located_error_filter',
57+
'graphql_traceback_error_filter',
58+
],
59+
},
60+
},
61+
}
62+
63+
logging.config.dictConfig(logger_dict)
64+
logger = logging.getLogger('custom')
65+
# logging.error('Error message')
66+

api/functions/auth_wrappers.py

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from graphql import GraphQLError
55

66
from functions.orm_to_dict import orm_to_dict
7-
from app import app
7+
from app import app, logger
88
from models import User_affiliations, Organizations
99

1010
user_admin_perm = ['super_admin', 'admin']
@@ -20,12 +20,16 @@ def decode_auth_token(request):
2020
"""
2121
auth_header = request.headers.get('Authorization')
2222
try:
23-
payload = jwt.decode(auth_header, os.getenv('SUPER_SECRET_SALT'), algorithms=['HS256'])
23+
payload = jwt.decode(
24+
auth_header,
25+
os.getenv('SUPER_SECRET_SALT'),
26+
algorithms=['HS256']
27+
)
2428
return payload['roles']
2529
except jwt.ExpiredSignatureError:
26-
raise GraphQLError('Signature expired. Please login again')
30+
raise GraphQLError('Signature expired, please login again')
2731
except jwt.InvalidTokenError:
28-
raise GraphQLError('Invalid token. Please login again')
32+
raise GraphQLError('Invalid token, please login again')
2933

3034

3135
def check_user_claims(user_claims):
@@ -36,14 +40,17 @@ def check_user_claims(user_claims):
3640
:param user_claims: A list of dicts that contain the users claims
3741
:return: Returns a valid list of user claims
3842
"""
39-
if user_claims:
43+
user_roles = []
44+
if user_claims[0] == 'none':
45+
raise GraphQLError('Error, please contact your administrator for '
46+
'organization access.')
47+
elif user_claims:
4048
user_id = user_claims[0]['user_id']
4149
with app.app_context():
4250
user_aff = User_affiliations.query.filter(
4351
User_affiliations.user_id == user_id).all()
4452
user_aff = orm_to_dict(user_aff)
4553
if user_aff:
46-
user_roles = []
4754
for select in user_aff:
4855
temp_dict = {
4956
'user_id': select['user_id'],
@@ -57,13 +64,12 @@ def check_user_claims(user_claims):
5764
+ list(
5865
itertools.filterfalse(lambda x: x in user_roles, user_claims))
5966
if user_claim_diff:
60-
print(user_claim_diff)
6167
# User has a difference in their claims
62-
raise GraphQLError("Error, Please sign in again.")
68+
raise GraphQLError("Error, please sign in again.")
6369
else:
6470
return user_claims
6571
else:
66-
raise GraphQLError("User has no claims")
72+
raise GraphQLError("User has no claims, please sign in again")
6773

6874

6975
def require_token(method):
@@ -74,4 +80,5 @@ def wrapper(self, *args, **kwargs):
7480
kwargs['user_roles'] = user_claims
7581
return method(self, *args, **kwargs)
7682
raise GraphQLError(auth_resp)
83+
7784
return wrapper

api/functions/db_seeding/organizations.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,14 @@ def seed_org(db, app):
2222
db.session.add(org)
2323
db.session.commit()
2424

25+
org = Organizations(
26+
id=3,
27+
organization='ORG3',
28+
description='Organization 3',
29+
)
30+
with app.app_context():
31+
db.session.add(org)
32+
db.session.commit()
2533

2634
def remove_org(db, app):
2735
with app.app_context():

api/functions/get_domain.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from sqlalchemy.orm import load_only
2+
3+
from db import db
4+
from models import Scans, Domains
5+
6+
7+
def get_domain(self, info):
8+
domain_id = db.session.query(Scans).filter(
9+
Scans.id == self.id
10+
).options(load_only('domain_id')).first()
11+
domain = db.session.query(Domains).filter(
12+
Domains.id == domain_id.domain_id
13+
).options(load_only('domain')).first()
14+
return domain.domain

api/functions/get_timestamp.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from sqlalchemy.orm import load_only
2+
3+
from db import db
4+
from models import Scans, Domains
5+
6+
def get_timestamp(self, info):
7+
timestamp = db.session.query(Scans).filter(
8+
Scans.id == self.id
9+
).options(load_only('scan_date')).first()
10+
return timestamp.scan_date

api/functions/sign_in_user.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def sign_in_user(user_name, password):
5555
}
5656
user_roles.append(temp_dict)
5757
else:
58-
user_roles = 'none'
58+
user_roles = ['none']
5959
try:
6060
payload = {
6161
'exp': datetime.datetime.utcnow() + datetime.timedelta(days=0, seconds=1800),
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
"""empty message
2+
3+
Revision ID: c98ceb3d9163
4+
Revises: 48853738b19d
5+
Create Date: 2020-03-09 08:13:31.523128
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
11+
12+
# revision identifiers, used by Alembic.
13+
revision = 'c98ceb3d9163'
14+
down_revision = '48853738b19d'
15+
branch_labels = None
16+
depends_on = None
17+
18+
19+
def upgrade():
20+
# ### commands auto generated by Alembic - please adjust! ###
21+
op.drop_column('domains', 'scan_ssl')
22+
op.drop_column('domains', 'scan_dmarc_psl')
23+
op.drop_column('domains', 'scan_dkim')
24+
op.drop_column('domains', 'scan_dmarc')
25+
op.drop_column('domains', 'scan_https')
26+
op.drop_column('domains', 'scan_mx')
27+
op.drop_column('domains', 'scan_spf')
28+
# ### end Alembic commands ###
29+
30+
31+
def downgrade():
32+
# ### commands auto generated by Alembic - please adjust! ###
33+
op.add_column('domains', sa.Column('scan_spf', sa.BOOLEAN(), autoincrement=False, nullable=True))
34+
op.add_column('domains', sa.Column('scan_mx', sa.BOOLEAN(), autoincrement=False, nullable=True))
35+
op.add_column('domains', sa.Column('scan_https', sa.BOOLEAN(), autoincrement=False, nullable=True))
36+
op.add_column('domains', sa.Column('scan_dmarc', sa.BOOLEAN(), autoincrement=False, nullable=True))
37+
op.add_column('domains', sa.Column('scan_dkim', sa.BOOLEAN(), autoincrement=False, nullable=True))
38+
op.add_column('domains', sa.Column('scan_dmarc_psl', sa.BOOLEAN(), autoincrement=False, nullable=True))
39+
op.add_column('domains', sa.Column('scan_ssl', sa.BOOLEAN(), autoincrement=False, nullable=True))
40+
# ### end Alembic commands ###

api/models.py

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,6 @@ class Domains(db.Model):
1313
id = Column(Integer, primary_key=True)
1414
domain = Column(String)
1515
last_run = Column(DateTime)
16-
scan_spf = Column(Boolean)
17-
scan_dmarc = Column(Boolean)
18-
scan_dmarc_psl = Column(Boolean)
19-
scan_mx = Column(Boolean)
20-
scan_dkim = Column(Boolean)
21-
scan_https = Column(Boolean)
22-
scan_ssl = Column(Boolean)
2316
dmarc_phase = Column(Integer)
2417
organization_id = Column(Integer, ForeignKey('organizations.id'))
2518
organization = relationship("Organizations", back_populates="domains", cascade="all, delete")
@@ -92,51 +85,41 @@ class Scans(db.Model):
9285
scan_date = Column(DateTime)
9386
initiated_by = Column(Integer, ForeignKey('users.id'))
9487
domain = relationship("Domains", back_populates="scans", cascade="all, delete")
95-
dmarc = relationship("Dmarc_scans", back_populates="dmarc_flagged_scan", cascade="all, delete")
96-
dkim = relationship("Dkim_scans", back_populates="dkim_flagged_scan", cascade="all, delete")
97-
spf = relationship("Spf_scans", back_populates="spf_flagged_scan", cascade="all, delete")
98-
https = relationship("Https_scans", back_populates="https_flagged_scan", cascade="all, delete")
99-
ssl = relationship("Ssl_scans", back_populates="ssl_flagged_scan", cascade="all, delete")
10088

10189

10290
class Dmarc_scans(db.Model):
10391
__tablename__ = 'dmarc_scans'
10492

10593
id = Column(Integer, ForeignKey('scans.id'), primary_key=True)
10694
dmarc_scan = Column(JSONB)
107-
dmarc_flagged_scan = relationship("Scans", back_populates="dmarc", cascade="all, delete")
10895

10996

11097
class Dkim_scans(db.Model):
11198
__tablename__ = 'dkim_scans'
11299

113100
id = Column(Integer, ForeignKey('scans.id'), primary_key=True)
114101
dkim_scan = Column(JSONB)
115-
dkim_flagged_scan = relationship("Scans", back_populates="dkim", cascade="all, delete")
116102

117103

118104
class Spf_scans(db.Model):
119105
__tablename__ = 'spf_scans'
120106

121107
id = Column(Integer, ForeignKey('scans.id'), primary_key=True)
122108
spf_scan = Column(JSONB)
123-
spf_flagged_scan = relationship("Scans", back_populates="spf", cascade="all, delete")
124109

125110

126111
class Https_scans(db.Model):
127112
__tablename__ = 'https_scans'
128113

129114
id = Column(Integer, ForeignKey('scans.id'), primary_key=True)
130115
https_scan = Column(JSONB)
131-
https_flagged_scan = relationship("Scans", back_populates="https", cascade="all, delete")
132116

133117

134118
class Ssl_scans(db.Model):
135119
__tablename__ = 'ssl_scans'
136120

137121
id = Column(Integer, ForeignKey('scans.id'), primary_key=True)
138122
ssl_scan = Column(JSONB)
139-
ssl_flagged_scan = relationship("Scans", back_populates="ssl", cascade="all, delete")
140123

141124

142125
class Ciphers(db.Model):

0 commit comments

Comments
 (0)