diff --git a/core/directives.py b/core/directives.py new file mode 100644 index 0000000..cf10072 --- /dev/null +++ b/core/directives.py @@ -0,0 +1,19 @@ +from unicodedata import name +from graphql import GraphQLArgument, GraphQLNonNull, GraphQLString +from graphql.type.directives import GraphQLDirective, DirectiveLocation + +GraphQLNetworkDirective = GraphQLDirective( + name="show_network", + locations=[ + DirectiveLocation.FIELD, + DirectiveLocation.FRAGMENT_SPREAD, + DirectiveLocation.INLINE_FRAGMENT, + ], + args={ + "style": GraphQLArgument( + GraphQLNonNull(GraphQLString) + ) + }, + description="Displays the network associated with an IP Address (CIDR or Net)." +) + diff --git a/core/models.py b/core/models.py index 10039a4..ad26159 100644 --- a/core/models.py +++ b/core/models.py @@ -1,5 +1,7 @@ import datetime + from app import db +from core import helpers # Models class User(db.Model): @@ -12,11 +14,18 @@ class Audit(db.Model): __tablename__ = 'audits' id = db.Column(db.Integer, primary_key=True) gqloperation = db.Column(db.String) + gqlquery = db.Column(db.String) timestamp = db.Column(db.DateTime, default=datetime.datetime.utcnow) @classmethod - def create_audit_entry(cls, **kw): - obj = cls(**kw) + def create_audit_entry(cls, info): + gql_operation = helpers.get_opname(info.operation) + gql_query = '{}' + + if info.context.json: + gql_query = info.context.json.get("query") + + obj = cls(**{"gqloperation":gql_operation, "gqlquery":gql_query}) db.session.add(obj) db.session.commit() return obj @@ -48,3 +57,4 @@ def create_paste(cls, **kw): db.session.add(obj) db.session.commit() return obj + diff --git a/core/security.py b/core/security.py index f1f0c52..b2538fe 100644 --- a/core/security.py +++ b/core/security.py @@ -1,5 +1,6 @@ import config import random +import ipaddress import time from core import helpers @@ -14,6 +15,15 @@ def simulate_load(): if count > limit: return +def get_network(addr, style='cidr'): + try: + if style == 'cidr': + return str(ipaddress.ip_network(addr)) + else: + return str(ipaddress.ip_network(addr).netmask) + except: + return 'Could not identify network' + def is_port(port): if isinstance(port, int): if port >= 0 and port <= 65535: diff --git a/core/views.py b/core/views.py index eb44fea..067b8bd 100644 --- a/core/views.py +++ b/core/views.py @@ -1,4 +1,6 @@ import graphene + +from core.directives import GraphQLNetworkDirective from db.solutions import solutions as list_of_solutions from flask import ( @@ -37,9 +39,16 @@ class Meta: model = User class PasteObject(SQLAlchemyObjectType): - p_id = graphene.String(source='id') class Meta: model = Paste + + def resolve_ip_addr(self, info): + for field_ast in info.field_asts: + for i in field_ast.directives: + if i.name.value == 'show_network': + if i.arguments[0].name.value == 'style': + return security.get_network(self.ip_addr, style=i.arguments[0].value.value) + return self.ip_addr class OwnerObject(SQLAlchemyObjectType): class Meta: @@ -68,23 +77,27 @@ def mutate(self, info, title, content, public, burn): user_agent=request.headers.get('User-Agent', '') ) - Audit.create_audit_entry(gqloperation=helpers.get_opname(info.operation)) + Audit.create_audit_entry(info) return CreatePaste(paste=paste_obj) class DeletePaste(graphene.Mutation): - ok = graphene.Boolean() + result = graphene.Boolean() class Arguments: - title = graphene.String() + id = graphene.Int() - def mutate(self, info, title): - Paste.query.filter_by(title=title).delete() - db.session.commit() - Audit.create_audit_entry(gqloperation=helpers.get_opname(info.operation)) + def mutate(self, info, id): + result = False + + if Paste.query.filter_by(id=id).delete(): + result = True + db.session.commit() - return DeletePaste(ok=True) + Audit.create_audit_entry(info) + + return DeletePaste(result=result) class UploadPaste(graphene.Mutation): content = graphene.String() @@ -107,7 +120,7 @@ def mutate(self, info, filename, content): user_agent=request.headers.get('User-Agent', '') ) - Audit.create_audit_entry(gqloperation=helpers.get_opname(info.operation)) + Audit.create_audit_entry(info) return UploadPaste(result=result) @@ -132,7 +145,7 @@ def mutate(self, info, host='pastebin.com', port=443, path='/', scheme="http"): user_agent=request.headers.get('User-Agent', '') ) - Audit.create_audit_entry(gqloperation=helpers.get_opname(info.operation)) + Audit.create_audit_entry(info) return ImportPaste(result=cmd) @@ -144,32 +157,32 @@ class Mutations(graphene.ObjectType): class Query(graphene.ObjectType): pastes = graphene.List(PasteObject, public=graphene.Boolean(), limit=graphene.Int()) - paste = graphene.Field(PasteObject, p_id=graphene.String()) + paste = graphene.Field(PasteObject, id=graphene.Int()) system_update = graphene.String() system_diagnostics = graphene.String(username=graphene.String(), password=graphene.String(), cmd=graphene.String()) system_health = graphene.String() - read_and_burn = graphene.Field(PasteObject, p_id=graphene.Int()) + read_and_burn = graphene.Field(PasteObject, id=graphene.Int()) def resolve_pastes(self, info, public=False, limit=1000): query = PasteObject.get_query(info) - Audit.create_audit_entry(gqloperation=helpers.get_opname(info.operation)) + Audit.create_audit_entry(info) return query.filter_by(public=public, burn=False).order_by(Paste.id.desc()).limit(limit) - def resolve_paste(self, info, p_id): + def resolve_paste(self, info, id): query = PasteObject.get_query(info) - Audit.create_audit_entry(gqloperation=helpers.get_opname(info.operation)) - return query.filter_by(id=p_id, burn=False).first() + Audit.create_audit_entry(info) + return query.filter_by(id=id, burn=False).first() def resolve_system_update(self, info): security.simulate_load() - Audit.create_audit_entry(gqloperation=helpers.get_opname(info.operation)) + Audit.create_audit_entry(info) return 'no updates available' def resolve_system_diagnostics(self, info, username, password, cmd='whoami'): q = User.query.filter_by(username='admin').first() real_passw = q.password res, msg = security.check_creds(username, password, real_passw) - Audit.create_audit_entry(gqloperation=helpers.get_opname(info.operation)) + Audit.create_audit_entry(info) if res: output = f'{cmd}: command not found' if security.allowed_cmds(cmd): @@ -177,15 +190,15 @@ def resolve_system_diagnostics(self, info, username, password, cmd='whoami'): return output return msg - def resolve_read_and_burn(self, info, p_id): - result = Paste.query.filter_by(id=p_id, burn=True).first() - Paste.query.filter_by(id=p_id, burn=True).delete() + def resolve_read_and_burn(self, info, id): + result = Paste.query.filter_by(id=id, burn=True).first() + Paste.query.filter_by(id=id, burn=True).delete() db.session.commit() - Audit.create_audit_entry(gqloperation=helpers.get_opname(info.operation)) + Audit.create_audit_entry(info) return result def resolve_system_health(self, info): - Audit.create_audit_entry(gqloperation=helpers.get_opname(info.operation)) + Audit.create_audit_entry(info) return 'System Load: {}'.format( helpers.run_cmd("uptime | awk '{print $10, $11, $12}'") ) @@ -230,7 +243,6 @@ def audit(): audit = Audit.query.all() return render_template("audit.html", audit=audit) - @app.route('/start_over') def start_over(): msg = "Restored to default state." @@ -270,7 +282,7 @@ def set_difficulty(): if session.get('difficulty') == None: helpers.set_mode('easy') -schema = graphene.Schema(query=Query, mutation = Mutations) +schema = graphene.Schema(query=Query, mutation=Mutations, directives=[GraphQLNetworkDirective]) gql_middlew = [ middleware.CostProtectionMiddleware(), @@ -295,8 +307,7 @@ def set_difficulty(): 'graphiql', schema = schema, graphiql = True, - middleware = igql_middlew, - batch=True + middleware = igql_middlew )) diff --git a/setup.py b/setup.py index 218ccc2..906a7e3 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ from ipaddress import IPv4Network from app import db -from core.models import Paste, Owner, User, Audit +from core.models import Paste, Owner, User from db.agents import agents from db.owners import owners @@ -59,7 +59,6 @@ def pump_db(): db.create_all() admin = User(username="admin", password=random_password()) owner = Owner(name='DVGAUser') - audit = Audit() paste = Paste() paste.title = random_title() paste.content = "My First Paste" @@ -68,11 +67,9 @@ def pump_db(): paste.owner = owner paste.ip_addr = '127.0.0.1' paste.user_agent = 'User-Agent not set' - audit.gqloperation = 'CreatePaste' db.session.add(admin) db.session.add(owner) db.session.add(paste) - db.session.add(audit) for _ in range(0, 10 ): owner = Owner(name=random_owner()) diff --git a/templates/audit.html b/templates/audit.html index 51ce99e..614c52d 100644 --- a/templates/audit.html +++ b/templates/audit.html @@ -20,6 +20,7 @@

Recent Audit Log Activity

# Name GraphQL Operation + GraphQL Query Date @@ -29,6 +30,7 @@

Recent Audit Log Activity

{{loop.index}}. DVGAUser {{i.gqloperation}} + {{i.gqlquery}} {{i.timestamp.strftime('%Y-%m-%d %H:%M:%S')}} diff --git a/templates/paste.html b/templates/paste.html index 95aa0cd..02385bb 100644 --- a/templates/paste.html +++ b/templates/paste.html @@ -100,7 +100,7 @@ var query = `mutation CreatePaste ($title: String!, $content: String!, $public: Boolean!, $burn: Boolean!) { createPaste(title:$title, content:$content, public:$public, burn: $burn) { paste { - pId + id content title burn @@ -124,8 +124,8 @@ (data => { if (data.data.createPaste.paste.burn == true) { var host = window.location.protocol + "//" + window.location.host; - var p_id = parseInt(data.data.createPaste.paste.pId) - url = host + `/graphql?query=query%20readAndBurn%20%7B%0A%20%20readAndBurn(pId%3A${p_id})%7B%0A%20%20%20%20title%0A%20%20%20%20content%0A%20%20%20%20burn%0A%20%20%7D%0A%7D%0A` + var id = parseInt(data.data.createPaste.paste.id) + url = host + `/graphql?query=query%20readAndBurn%20%7B%0A%20%20readAndBurn(id %3A${id})%7B%0A%20%20%20%20title%0A%20%20%20%20content%0A%20%20%20%20burn%0A%20%20%7D%0A%7D%0A` $("#result").append( `

Well done!

diff --git a/version.py b/version.py index 42aab31..f2d1eac 100644 --- a/version.py +++ b/version.py @@ -1 +1 @@ -VERSION = '1.3.2' \ No newline at end of file +VERSION = '1.3.3'